mirror of
https://github.com/google/nomulus.git
synced 2025-06-03 19:17:50 +02:00
Import code from internal repository to git
This commit is contained in:
commit
0ef0c933d2
2490 changed files with 281594 additions and 0 deletions
39
javatests/com/google/domain/registry/backup/BUILD
Normal file
39
javatests/com/google/domain/registry/backup/BUILD
Normal file
|
@ -0,0 +1,39 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "backup",
|
||||
srcs = glob(["*.java"]),
|
||||
resources = glob(["testdata/*"]),
|
||||
deps = [
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/net",
|
||||
"//java/com/google/common/primitives",
|
||||
"//java/com/google/common/util/concurrent",
|
||||
"//java/com/google/domain/registry/backup",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/appengine_gcs_client",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":backup"],
|
||||
)
|
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.backup;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogCheckpointRoot.loadRoot;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.model.ofy.CommitLogCheckpoint;
|
||||
import com.google.domain.registry.model.ofy.CommitLogCheckpointRoot;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import com.google.domain.registry.util.Retrier;
|
||||
import com.google.domain.registry.util.TaskEnqueuer;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Unit tests for {@link CommitLogCheckpointAction}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CommitLogCheckpointActionTest {
|
||||
|
||||
private static final String QUEUE_NAME = "export-commits";
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
CommitLogCheckpointStrategy strategy;
|
||||
|
||||
DateTime now = DateTime.now(UTC);
|
||||
CommitLogCheckpointAction task = new CommitLogCheckpointAction();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
task.clock = new FakeClock(now);
|
||||
task.strategy = strategy;
|
||||
task.taskEnqueuer = new TaskEnqueuer(new Retrier(null, 1));
|
||||
when(strategy.computeCheckpoint()).thenReturn(
|
||||
CommitLogCheckpoint.create(now, ImmutableMap.of(1, START_OF_TIME)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_noCheckpointEverWritten_writesCheckpointAndEnqueuesTask() throws Exception {
|
||||
task.run();
|
||||
assertTasksEnqueued(
|
||||
QUEUE_NAME,
|
||||
new TaskMatcher()
|
||||
.url(ExportCommitLogDiffAction.PATH)
|
||||
.param(ExportCommitLogDiffAction.LOWER_CHECKPOINT_TIME_PARAM, START_OF_TIME.toString())
|
||||
.param(ExportCommitLogDiffAction.UPPER_CHECKPOINT_TIME_PARAM, now.toString()));
|
||||
assertThat(loadRoot().getLastWrittenTime()).isEqualTo(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_checkpointWrittenBeforeNow_writesCheckpointAndEnqueuesTask()
|
||||
throws Exception {
|
||||
DateTime oneMinuteAgo = now.minusMinutes(1);
|
||||
persistResource(CommitLogCheckpointRoot.create(oneMinuteAgo));
|
||||
task.run();
|
||||
assertTasksEnqueued(
|
||||
QUEUE_NAME,
|
||||
new TaskMatcher()
|
||||
.url(ExportCommitLogDiffAction.PATH)
|
||||
.param(ExportCommitLogDiffAction.LOWER_CHECKPOINT_TIME_PARAM, oneMinuteAgo.toString())
|
||||
.param(ExportCommitLogDiffAction.UPPER_CHECKPOINT_TIME_PARAM, now.toString()));
|
||||
assertThat(loadRoot().getLastWrittenTime()).isEqualTo(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_checkpointWrittenAfterNow_doesntOverwrite_orEnqueueTask() throws Exception {
|
||||
DateTime oneMinuteFromNow = now.plusMinutes(1);
|
||||
persistResource(CommitLogCheckpointRoot.create(oneMinuteFromNow));
|
||||
task.run();
|
||||
assertNoTasksEnqueued(QUEUE_NAME);
|
||||
assertThat(loadRoot().getLastWrittenTime()).isEqualTo(oneMinuteFromNow);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,327 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.backup;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.getBucketKey;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.model.ofy.CommitLogBucket;
|
||||
import com.google.domain.registry.model.ofy.CommitLogCheckpoint;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.registry.RegistryCursor;
|
||||
import com.google.domain.registry.model.registry.RegistryCursor.CursorType;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Unit tests for {@link CommitLogCheckpointStrategy}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CommitLogCheckpointStrategyTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule();
|
||||
|
||||
final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||
final Ofy ofy = new Ofy(clock);
|
||||
final CommitLogCheckpointStrategy strategy = new CommitLogCheckpointStrategy();
|
||||
|
||||
/**
|
||||
* Supplier to inject into CommitLogBucket for doling out predictable bucket IDs.
|
||||
*
|
||||
* <p>If not overridden, the supplier returns 1 so that other saves won't hit an NPE (since even
|
||||
* if they use saveWithoutBackup() the transaction still selects a bucket key early).
|
||||
*/
|
||||
final FakeSupplier<Integer> fakeBucketIdSupplier = new FakeSupplier<>(1);
|
||||
|
||||
/** Gross but necessary supplier that can be modified to return the desired value. */
|
||||
private static class FakeSupplier<T> implements Supplier<T> {
|
||||
/** Default value to return if 'value' is not set. */
|
||||
final T defaultValue;
|
||||
|
||||
/** Set this value field to make the supplier return this value. */
|
||||
T value = null;
|
||||
|
||||
public FakeSupplier(T defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
strategy.clock = clock;
|
||||
strategy.ofy = ofy;
|
||||
|
||||
// Use three commit log buckets for easier but sufficiently complex testing.
|
||||
configRule.override(new TestRegistryConfig() {
|
||||
@Override
|
||||
public int getCommitLogBucketCount() {
|
||||
return 3;
|
||||
}});
|
||||
|
||||
// Need to inject clock into Ofy so that createTld() below will get the right time.
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
// Inject a fake bucket ID supplier so we can dole out specific bucket IDs to commit logs.
|
||||
inject.setStaticField(CommitLogBucket.class, "bucketIdSupplier", fakeBucketIdSupplier);
|
||||
|
||||
// Create some fake TLDs to parent RegistryCursor test objects under.
|
||||
createTld("tld1");
|
||||
createTld("tld2");
|
||||
createTld("tld3");
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readBucketTimestamps_noCommitLogs() throws Exception {
|
||||
assertThat(strategy.readBucketTimestamps())
|
||||
.containsExactly(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readBucketTimestamps_withSomeCommitLogs() throws Exception {
|
||||
DateTime startTime = clock.nowUtc();
|
||||
writeCommitLogToBucket(1);
|
||||
clock.advanceOneMilli();
|
||||
writeCommitLogToBucket(2);
|
||||
assertThat(strategy.readBucketTimestamps())
|
||||
.containsExactly(1, startTime, 2, startTime.plusMillis(1), 3, START_OF_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readBucketTimestamps_againAfterUpdate_reflectsUpdate() throws Exception {
|
||||
DateTime firstTime = clock.nowUtc();
|
||||
writeCommitLogToBucket(1);
|
||||
writeCommitLogToBucket(2);
|
||||
writeCommitLogToBucket(3);
|
||||
assertThat(strategy.readBucketTimestamps().values())
|
||||
.containsExactly(firstTime, firstTime, firstTime);
|
||||
clock.advanceOneMilli();
|
||||
writeCommitLogToBucket(1);
|
||||
DateTime secondTime = clock.nowUtc();
|
||||
assertThat(strategy.readBucketTimestamps())
|
||||
.containsExactly(1, secondTime, 2, firstTime, 3, firstTime);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readNewCommitLogsAndFindThreshold_noCommitsAtAll_returnsEndOfTime() {
|
||||
ImmutableMap<Integer, DateTime> bucketTimes =
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME);
|
||||
assertThat(strategy.readNewCommitLogsAndFindThreshold(bucketTimes)).isEqualTo(END_OF_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readNewCommitLogsAndFindThreshold_noNewCommits_returnsEndOfTime() {
|
||||
DateTime now = clock.nowUtc();
|
||||
writeCommitLogToBucket(1);
|
||||
clock.advanceOneMilli();
|
||||
writeCommitLogToBucket(2);
|
||||
clock.advanceOneMilli();
|
||||
writeCommitLogToBucket(3);
|
||||
ImmutableMap<Integer, DateTime> bucketTimes =
|
||||
ImmutableMap.of(1, now, 2, now.plusMillis(1), 3, now.plusMillis(2));
|
||||
assertThat(strategy.readNewCommitLogsAndFindThreshold(bucketTimes)).isEqualTo(END_OF_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readNewCommitLogsAndFindThreshold_tiedNewCommits_returnsCommitTimeMinusOne() {
|
||||
DateTime now = clock.nowUtc();
|
||||
writeCommitLogToBucket(1);
|
||||
writeCommitLogToBucket(2);
|
||||
writeCommitLogToBucket(3);
|
||||
assertThat(strategy.readNewCommitLogsAndFindThreshold(
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME)))
|
||||
.isEqualTo(now.minusMillis(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readNewCommitLogsAndFindThreshold_someNewCommits_returnsEarliestTimeMinusOne() {
|
||||
DateTime now = clock.nowUtc();
|
||||
writeCommitLogToBucket(1); // 1A
|
||||
writeCommitLogToBucket(2); // 2A
|
||||
writeCommitLogToBucket(3); // 3A
|
||||
clock.advanceBy(Duration.millis(5));
|
||||
writeCommitLogToBucket(1); // 1B
|
||||
writeCommitLogToBucket(2); // 2B
|
||||
writeCommitLogToBucket(3); // 3B
|
||||
clock.advanceBy(Duration.millis(5));
|
||||
writeCommitLogToBucket(1); // 1C
|
||||
writeCommitLogToBucket(2); // 2C
|
||||
writeCommitLogToBucket(3); // 3C
|
||||
// First pass times: 1 at T0, 2 at T+5, 3 at T+10.
|
||||
// Commits 1A, 2B, 3C are the commits seen in the first pass.
|
||||
// Commits 2A, 3A, 3B are all old prior commits that should be ignored.
|
||||
// Commit 1B is the first new commit for bucket 1, at T+5.
|
||||
// Commit 1C is the second new commit for bucket 1, at T+10, and should be ignored.
|
||||
// Commit 2C is the first new commit for bucket 2, at T+10.
|
||||
// Since 1B as a new commit is older than 1C, T+5 is the oldest new commit time.
|
||||
// Therefore, expect T+4 as the threshold time.
|
||||
assertThat(strategy.readNewCommitLogsAndFindThreshold(
|
||||
ImmutableMap.of(1, now, 2, now.plusMillis(5), 3, now.plusMillis(10))))
|
||||
.isEqualTo(now.plusMillis(4));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_readNewCommitLogsAndFindThreshold_commitsAtBucketTimes() {
|
||||
DateTime now = clock.nowUtc();
|
||||
ImmutableMap<Integer, DateTime> bucketTimes =
|
||||
ImmutableMap.of(1, now.minusMillis(1), 2, now, 3, now.plusMillis(1));
|
||||
assertThat(strategy.readNewCommitLogsAndFindThreshold(bucketTimes)).isEqualTo(END_OF_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_computeBucketCheckpointTimes_earlyThreshold_setsEverythingToThreshold() {
|
||||
DateTime now = clock.nowUtc();
|
||||
ImmutableMap<Integer, DateTime> bucketTimes =
|
||||
ImmutableMap.of(1, now.minusMillis(1), 2, now, 3, now.plusMillis(1));
|
||||
assertThat(strategy.computeBucketCheckpointTimes(bucketTimes, now.minusMillis(2)).values())
|
||||
.containsExactly(now.minusMillis(2), now.minusMillis(2), now.minusMillis(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_computeBucketCheckpointTimes_middleThreshold_clampsToThreshold() {
|
||||
DateTime now = clock.nowUtc();
|
||||
ImmutableMap<Integer, DateTime> bucketTimes =
|
||||
ImmutableMap.of(1, now.minusMillis(1), 2, now, 3, now.plusMillis(1));
|
||||
assertThat(strategy.computeBucketCheckpointTimes(bucketTimes, now))
|
||||
.containsExactly(1, now.minusMillis(1), 2, now, 3, now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_computeBucketCheckpointTimes_lateThreshold_leavesBucketTimesAsIs() {
|
||||
DateTime now = clock.nowUtc();
|
||||
ImmutableMap<Integer, DateTime> bucketTimes =
|
||||
ImmutableMap.of(1, now.minusMillis(1), 2, now, 3, now.plusMillis(1));
|
||||
assertThat(strategy.computeBucketCheckpointTimes(bucketTimes, now.plusMillis(2)))
|
||||
.isEqualTo(bucketTimes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_computeCheckpoint_noCommitsAtAll_bucketCheckpointTimesAreStartOfTime() {
|
||||
assertThat(strategy.computeCheckpoint())
|
||||
.isEqualTo(CommitLogCheckpoint.create(
|
||||
clock.nowUtc(),
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_computeCheckpoint_noNewCommitLogs_bucketCheckpointTimesAreBucketTimes() {
|
||||
DateTime now = clock.nowUtc();
|
||||
writeCommitLogToBucket(1);
|
||||
clock.advanceOneMilli();
|
||||
writeCommitLogToBucket(2);
|
||||
clock.advanceOneMilli();
|
||||
writeCommitLogToBucket(3);
|
||||
clock.advanceOneMilli();
|
||||
DateTime checkpointTime = clock.nowUtc();
|
||||
assertThat(strategy.computeCheckpoint())
|
||||
.isEqualTo(CommitLogCheckpoint.create(
|
||||
checkpointTime,
|
||||
ImmutableMap.of(1, now, 2, now.plusMillis(1), 3, now.plusMillis(2))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_computeCheckpoint_someNewCommits_bucketCheckpointTimesAreClampedToThreshold() {
|
||||
DateTime now = clock.nowUtc();
|
||||
writeCommitLogToBucket(1); // 1A
|
||||
writeCommitLogToBucket(2); // 2A
|
||||
writeCommitLogToBucket(3); // 3A
|
||||
clock.advanceBy(Duration.millis(5));
|
||||
writeCommitLogToBucket(1); // 1B
|
||||
writeCommitLogToBucket(2); // 2B
|
||||
writeCommitLogToBucket(3); // 3B
|
||||
clock.advanceBy(Duration.millis(5));
|
||||
writeCommitLogToBucket(1); // 1C
|
||||
writeCommitLogToBucket(2); // 2C
|
||||
writeCommitLogToBucket(3); // 3C
|
||||
|
||||
// Set first pass times: 1 at T0, 2 at T+5, 3 at T+10.
|
||||
saveBucketWithLastWrittenTime(1, now);
|
||||
saveBucketWithLastWrittenTime(2, now.plusMillis(5));
|
||||
saveBucketWithLastWrittenTime(3, now.plusMillis(10));
|
||||
|
||||
// Commits 1A, 2B, 3C are the commits seen in the first pass.
|
||||
// Commits 2A, 3A, 3B are all old prior commits that should be ignored.
|
||||
// Commit 1B is the first new commit for bucket 1, at T+5.
|
||||
// Commit 1C is the second new commit for bucket 1, at T+10, and should be ignored.
|
||||
// Commit 2C is the first new commit for bucket 2, at T+10.
|
||||
// Since 1B as a new commit is older than 1C, T+5 is the oldest new commit time.
|
||||
// Therefore, expect T+4 as the threshold time.
|
||||
DateTime threshold = now.plusMillis(4);
|
||||
|
||||
// Advance clock before taking checkpoint.
|
||||
clock.advanceBy(Duration.millis(10));
|
||||
DateTime checkpointTime = clock.nowUtc();
|
||||
|
||||
// Bucket checkpoint times should be clamped as expected.
|
||||
assertThat(strategy.computeCheckpoint())
|
||||
.isEqualTo(CommitLogCheckpoint.create(
|
||||
checkpointTime,
|
||||
ImmutableMap.of(1, now, 2, threshold, 3, threshold)));
|
||||
}
|
||||
|
||||
private void writeCommitLogToBucket(final int bucketId) {
|
||||
fakeBucketIdSupplier.value = bucketId;
|
||||
ofy.transact(
|
||||
new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
String tld = "tld" + bucketId;
|
||||
RegistryCursor.save(Registry.get(tld), CursorType.RDE_REPORT, ofy.getTransactionTime());
|
||||
}
|
||||
});
|
||||
fakeBucketIdSupplier.value = null;
|
||||
}
|
||||
|
||||
private void saveBucketWithLastWrittenTime(final int bucketId, final DateTime lastWrittenTime) {
|
||||
ofy.transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy.saveWithoutBackup().entity(
|
||||
CommitLogBucket.loadBucket(getBucketKey(bucketId)).asBuilder()
|
||||
.setLastWrittenTime(lastWrittenTime)
|
||||
.build());
|
||||
}});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.backup;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.joda.time.Duration.millis;
|
||||
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.model.ofy.CommitLogManifest;
|
||||
import com.google.domain.registry.model.ofy.CommitLogMutation;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link DeleteOldCommitLogsAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DeleteOldCommitLogsActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||
private final Ofy ofy = new Ofy(clock);
|
||||
private final DeleteOldCommitLogsAction task = new DeleteOldCommitLogsAction();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
task.bucketNum = 1;
|
||||
task.clock = clock;
|
||||
task.maxAge = Duration.millis(2);
|
||||
task.maxDeletes = 4;
|
||||
task.ofy = ofy;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_noCommitLogs_doesNothing() throws Exception {
|
||||
assertManifestAndMutationCounts(0, 0);
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_commitLogNewerThanThreshold_doesntGetDeleted() throws Exception {
|
||||
createCommitLog();
|
||||
clock.advanceOneMilli();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_commitLogEqualToThreshold_doesntGetDeleted() throws Exception {
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(2));
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_commitLogOlderThanThreshold_getsDeleted() throws Exception {
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(3));
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_oneOlderThanThresholdAndOneNewer_onlyOldOneIsDeleted() throws Exception {
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(3));
|
||||
createCommitLog();
|
||||
assertManifestAndMutationCounts(2, 4);
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_twoOlderThanThreshold_bothGetDeletedInSameTransaction() throws Exception {
|
||||
task.maxDeletes = 2;
|
||||
createCommitLog();
|
||||
clock.advanceOneMilli();
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(3));
|
||||
assertManifestAndMutationCounts(2, 4);
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(0, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_twoOlderThanThreshold_bothGetDeletedInTwoTransactions() throws Exception {
|
||||
task.maxDeletes = 1;
|
||||
createCommitLog();
|
||||
clock.advanceOneMilli();
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(3));
|
||||
createCommitLog();
|
||||
assertManifestAndMutationCounts(3, 6);
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(2, 4);
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_commitLogOlderButInADifferentBucket_doesntGetDeleted() throws Exception {
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(31337));
|
||||
configRule.override(new TestRegistryConfig() {
|
||||
@Override public int getCommitLogBucketCount() { return 2; }
|
||||
});
|
||||
task.bucketNum = 2;
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_lessThanATenthOfOldData_doesntGetDeleted() throws Exception {
|
||||
task.maxDeletes = 20;
|
||||
createCommitLog();
|
||||
clock.advanceBy(millis(2));
|
||||
task.run();
|
||||
assertManifestAndMutationCounts(1, 2);
|
||||
}
|
||||
|
||||
private void assertManifestAndMutationCounts(int manifestCount, int mutationCount) {
|
||||
assertThat(ofy.load().type(CommitLogManifest.class).count()).isEqualTo(manifestCount);
|
||||
assertThat(ofy.load().type(CommitLogMutation.class).count()).isEqualTo(mutationCount);
|
||||
}
|
||||
|
||||
private void createCommitLog() {
|
||||
ofy.transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy.save().entity(
|
||||
Registrar.loadByClientId("NewRegistrar").asBuilder()
|
||||
.setEmailAddress("pumpkin@cat.test")
|
||||
.build());
|
||||
ofy.save().entity(
|
||||
Registrar.loadByClientId("TheRegistrar").asBuilder()
|
||||
.setReferralUrl("http://justine.test")
|
||||
.build());
|
||||
}});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,397 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.backup;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static com.google.domain.registry.backup.BackupUtils.GcsMetadataKeys.LOWER_BOUND_CHECKPOINT;
|
||||
import static com.google.domain.registry.backup.BackupUtils.GcsMetadataKeys.NUM_TRANSACTIONS;
|
||||
import static com.google.domain.registry.backup.BackupUtils.GcsMetadataKeys.UPPER_BOUND_CHECKPOINT;
|
||||
import static com.google.domain.registry.backup.BackupUtils.deserializeEntities;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.appengine.tools.cloudstorage.GcsFilename;
|
||||
import com.google.appengine.tools.cloudstorage.GcsService;
|
||||
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.model.ofy.CommitLogBucket;
|
||||
import com.google.domain.registry.model.ofy.CommitLogCheckpoint;
|
||||
import com.google.domain.registry.model.ofy.CommitLogManifest;
|
||||
import com.google.domain.registry.model.ofy.CommitLogMutation;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.GcsTestingUtils;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
import com.google.domain.registry.testing.TestObject;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/** Unit tests for {@link ExportCommitLogDiffAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ExportCommitLogDiffActionTest {
|
||||
|
||||
private static final int NUM_BUCKETS = 3;
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule(
|
||||
new TestRegistryConfig() {
|
||||
@Override public int getCommitLogBucketCount() {
|
||||
return NUM_BUCKETS;
|
||||
}});
|
||||
|
||||
/** Local GCS service available for testing. */
|
||||
private final GcsService gcsService = GcsServiceFactory.createGcsService();
|
||||
|
||||
private final DateTime now = DateTime.now(UTC);
|
||||
private final DateTime oneMinuteAgo = now.minusMinutes(1);
|
||||
|
||||
private final ExportCommitLogDiffAction task = new ExportCommitLogDiffAction();
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ObjectifyService.register(TestObject.class);
|
||||
task.gcsService = gcsService;
|
||||
task.gcsBucket = "gcs bucket";
|
||||
task.batchSize = 5;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_noCommitHistory_onlyUpperCheckpointExported() throws Exception {
|
||||
task.lowerCheckpointTime = oneMinuteAgo;
|
||||
task.upperCheckpointTime = now;
|
||||
|
||||
persistResource(CommitLogCheckpoint.create(
|
||||
oneMinuteAgo,
|
||||
ImmutableMap.of(1, oneMinuteAgo, 2, oneMinuteAgo, 3, oneMinuteAgo)));
|
||||
CommitLogCheckpoint upperCheckpoint = persistResource(CommitLogCheckpoint.create(
|
||||
now,
|
||||
ImmutableMap.of(1, now, 2, now, 3, now)));
|
||||
|
||||
// Don't persist any manifests or mutations.
|
||||
|
||||
task.run();
|
||||
|
||||
GcsFilename expectedFilename = new GcsFilename("gcs bucket", "commit_diff_until_" + now);
|
||||
assertWithMessage("GCS file not found: " + expectedFilename)
|
||||
.that(gcsService.getMetadata(expectedFilename)).isNotNull();
|
||||
assertThat(gcsService.getMetadata(expectedFilename).getOptions().getUserMetadata())
|
||||
.containsExactly(
|
||||
LOWER_BOUND_CHECKPOINT,
|
||||
oneMinuteAgo.toString(),
|
||||
UPPER_BOUND_CHECKPOINT,
|
||||
now.toString(),
|
||||
NUM_TRANSACTIONS,
|
||||
"0");
|
||||
List<ImmutableObject> exported =
|
||||
deserializeEntities(GcsTestingUtils.readGcsFile(gcsService, expectedFilename));
|
||||
assertThat(exported).containsExactly(upperCheckpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_regularCommitHistory_exportsCorrectCheckpointDiff() throws Exception {
|
||||
task.lowerCheckpointTime = oneMinuteAgo;
|
||||
task.upperCheckpointTime = now;
|
||||
|
||||
// Persist the lower and upper checkpoints, with 3 buckets each and staggered times. We respect
|
||||
// the real invariant that the time for bucket n in the lower checkpoint is <= the time for
|
||||
// that bucket in the upper.
|
||||
persistResource(CommitLogCheckpoint.create(
|
||||
oneMinuteAgo,
|
||||
ImmutableMap.of(
|
||||
1, oneMinuteAgo,
|
||||
2, oneMinuteAgo.minusDays(1),
|
||||
3, oneMinuteAgo.minusDays(2))));
|
||||
CommitLogCheckpoint upperCheckpoint = persistResource(CommitLogCheckpoint.create(
|
||||
now,
|
||||
ImmutableMap.of(
|
||||
1, now,
|
||||
2, now.minusDays(1),
|
||||
3, oneMinuteAgo.minusDays(2)))); // Note that this matches the lower bound.
|
||||
|
||||
// Persist some fake commit log manifests.
|
||||
// These shouldn't be in the diff because the lower bound is exclusive.
|
||||
persistManifestAndMutation(1, oneMinuteAgo);
|
||||
persistManifestAndMutation(2, oneMinuteAgo.minusDays(1));
|
||||
persistManifestAndMutation(3, oneMinuteAgo.minusDays(2)); // Even though it's == upper bound.
|
||||
// These shouldn't be in the diff because they are above the upper bound.
|
||||
persistManifestAndMutation(1, now.plusMillis(1));
|
||||
persistManifestAndMutation(2, now.minusDays(1).plusMillis(1));
|
||||
persistManifestAndMutation(3, oneMinuteAgo.minusDays(2).plusMillis(1));
|
||||
// These should be in the diff because they are between the bounds. (Not possible for bucket 3.)
|
||||
persistManifestAndMutation(1, now.minusMillis(1));
|
||||
persistManifestAndMutation(2, now.minusDays(1).minusMillis(1));
|
||||
// These should be in the diff because they are at the upper bound. (Not possible for bucket 3.)
|
||||
persistManifestAndMutation(1, now);
|
||||
persistManifestAndMutation(2, now.minusDays(1));
|
||||
|
||||
task.run();
|
||||
|
||||
GcsFilename expectedFilename = new GcsFilename("gcs bucket", "commit_diff_until_" + now);
|
||||
assertWithMessage("GCS file not found: " + expectedFilename)
|
||||
.that(gcsService.getMetadata(expectedFilename)).isNotNull();
|
||||
assertThat(gcsService.getMetadata(expectedFilename).getOptions().getUserMetadata())
|
||||
.containsExactly(
|
||||
LOWER_BOUND_CHECKPOINT,
|
||||
oneMinuteAgo.toString(),
|
||||
UPPER_BOUND_CHECKPOINT,
|
||||
now.toString(),
|
||||
NUM_TRANSACTIONS,
|
||||
"4");
|
||||
List<ImmutableObject> exported =
|
||||
deserializeEntities(GcsTestingUtils.readGcsFile(gcsService, expectedFilename));
|
||||
assertThat(exported.get(0)).isEqualTo(upperCheckpoint);
|
||||
// We expect these manifests, in time order, with matching mutations.
|
||||
CommitLogManifest manifest1 = createManifest(2, now.minusDays(1).minusMillis(1));
|
||||
CommitLogManifest manifest2 = createManifest(2, now.minusDays(1));
|
||||
CommitLogManifest manifest3 = createManifest(1, now.minusMillis(1));
|
||||
CommitLogManifest manifest4 = createManifest(1, now);
|
||||
assertThat(exported).containsExactly(
|
||||
upperCheckpoint,
|
||||
manifest1,
|
||||
createMutation(manifest1),
|
||||
manifest2,
|
||||
createMutation(manifest2),
|
||||
manifest3,
|
||||
createMutation(manifest3),
|
||||
manifest4,
|
||||
createMutation(manifest4))
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_simultaneousTransactions_bothExported() throws Exception {
|
||||
task.lowerCheckpointTime = oneMinuteAgo;
|
||||
task.upperCheckpointTime = now;
|
||||
|
||||
persistResource(CommitLogCheckpoint.create(
|
||||
oneMinuteAgo,
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME)));
|
||||
CommitLogCheckpoint upperCheckpoint = persistResource(CommitLogCheckpoint.create(
|
||||
now,
|
||||
ImmutableMap.of(1, now, 2, now, 3, now)));
|
||||
|
||||
// Persist some fake commit log manifests that are at the same time but in different buckets.
|
||||
persistManifestAndMutation(1, oneMinuteAgo);
|
||||
persistManifestAndMutation(2, oneMinuteAgo);
|
||||
persistManifestAndMutation(1, now);
|
||||
persistManifestAndMutation(2, now);
|
||||
|
||||
task.run();
|
||||
|
||||
GcsFilename expectedFilename = new GcsFilename("gcs bucket", "commit_diff_until_" + now);
|
||||
assertWithMessage("GCS file not found: " + expectedFilename)
|
||||
.that(gcsService.getMetadata(expectedFilename)).isNotNull();
|
||||
assertThat(gcsService.getMetadata(expectedFilename).getOptions().getUserMetadata())
|
||||
.containsExactly(
|
||||
LOWER_BOUND_CHECKPOINT,
|
||||
oneMinuteAgo.toString(),
|
||||
UPPER_BOUND_CHECKPOINT,
|
||||
now.toString(),
|
||||
NUM_TRANSACTIONS,
|
||||
"4");
|
||||
List<ImmutableObject> exported =
|
||||
deserializeEntities(GcsTestingUtils.readGcsFile(gcsService, expectedFilename));
|
||||
assertThat(exported.get(0)).isEqualTo(upperCheckpoint);
|
||||
// We expect these manifests, in the order below, with matching mutations.
|
||||
CommitLogManifest manifest1 = createManifest(1, oneMinuteAgo);
|
||||
CommitLogManifest manifest2 = createManifest(2, oneMinuteAgo);
|
||||
CommitLogManifest manifest3 = createManifest(1, now);
|
||||
CommitLogManifest manifest4 = createManifest(2, now);
|
||||
assertThat(exported).containsExactly(
|
||||
upperCheckpoint,
|
||||
manifest1,
|
||||
createMutation(manifest1),
|
||||
manifest2,
|
||||
createMutation(manifest2),
|
||||
manifest3,
|
||||
createMutation(manifest3),
|
||||
manifest4,
|
||||
createMutation(manifest4))
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_exportsAcrossMultipleBatches() throws Exception {
|
||||
task.batchSize = 2;
|
||||
task.lowerCheckpointTime = oneMinuteAgo;
|
||||
task.upperCheckpointTime = now;
|
||||
|
||||
persistResource(CommitLogCheckpoint.create(
|
||||
oneMinuteAgo,
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME)));
|
||||
CommitLogCheckpoint upperCheckpoint = persistResource(CommitLogCheckpoint.create(
|
||||
now,
|
||||
ImmutableMap.of(1, now, 2, now, 3, now)));
|
||||
|
||||
// Persist some fake commit log manifests.
|
||||
persistManifestAndMutation(1, oneMinuteAgo);
|
||||
persistManifestAndMutation(2, oneMinuteAgo);
|
||||
persistManifestAndMutation(3, oneMinuteAgo);
|
||||
persistManifestAndMutation(1, now);
|
||||
persistManifestAndMutation(2, now);
|
||||
persistManifestAndMutation(3, now);
|
||||
|
||||
task.run();
|
||||
|
||||
GcsFilename expectedFilename = new GcsFilename("gcs bucket", "commit_diff_until_" + now);
|
||||
assertWithMessage("GCS file not found: " + expectedFilename)
|
||||
.that(gcsService.getMetadata(expectedFilename)).isNotNull();
|
||||
assertThat(gcsService.getMetadata(expectedFilename).getOptions().getUserMetadata())
|
||||
.containsExactly(
|
||||
LOWER_BOUND_CHECKPOINT,
|
||||
oneMinuteAgo.toString(),
|
||||
UPPER_BOUND_CHECKPOINT,
|
||||
now.toString(),
|
||||
NUM_TRANSACTIONS,
|
||||
"6");
|
||||
List<ImmutableObject> exported =
|
||||
deserializeEntities(GcsTestingUtils.readGcsFile(gcsService, expectedFilename));
|
||||
assertThat(exported.get(0)).isEqualTo(upperCheckpoint);
|
||||
// We expect these manifests, in the order below, with matching mutations.
|
||||
CommitLogManifest manifest1 = createManifest(1, oneMinuteAgo);
|
||||
CommitLogManifest manifest2 = createManifest(2, oneMinuteAgo);
|
||||
CommitLogManifest manifest3 = createManifest(3, oneMinuteAgo);
|
||||
CommitLogManifest manifest4 = createManifest(1, now);
|
||||
CommitLogManifest manifest5 = createManifest(2, now);
|
||||
CommitLogManifest manifest6 = createManifest(3, now);
|
||||
assertThat(exported).containsExactly(
|
||||
upperCheckpoint,
|
||||
manifest1,
|
||||
createMutation(manifest1),
|
||||
manifest2,
|
||||
createMutation(manifest2),
|
||||
manifest3,
|
||||
createMutation(manifest3),
|
||||
manifest4,
|
||||
createMutation(manifest4),
|
||||
manifest5,
|
||||
createMutation(manifest5),
|
||||
manifest6,
|
||||
createMutation(manifest6))
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_checkpointDiffWithNeverTouchedBuckets_exportsCorrectly() throws Exception {
|
||||
task.lowerCheckpointTime = oneMinuteAgo;
|
||||
task.upperCheckpointTime = now;
|
||||
|
||||
persistResource(CommitLogCheckpoint.create(
|
||||
oneMinuteAgo,
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME)));
|
||||
CommitLogCheckpoint upperCheckpoint = persistResource(CommitLogCheckpoint.create(
|
||||
now,
|
||||
ImmutableMap.of(1, START_OF_TIME, 2, START_OF_TIME, 3, START_OF_TIME)));
|
||||
|
||||
// Don't persist any commit log manifests; we're just checking that the task runs correctly
|
||||
// even if the upper timestamp contains START_OF_TIME values.
|
||||
|
||||
task.run();
|
||||
|
||||
GcsFilename expectedFilename = new GcsFilename("gcs bucket", "commit_diff_until_" + now);
|
||||
assertWithMessage("GCS file not found: " + expectedFilename)
|
||||
.that(gcsService.getMetadata(expectedFilename)).isNotNull();
|
||||
assertThat(gcsService.getMetadata(expectedFilename).getOptions().getUserMetadata())
|
||||
.containsExactly(
|
||||
LOWER_BOUND_CHECKPOINT,
|
||||
oneMinuteAgo.toString(),
|
||||
UPPER_BOUND_CHECKPOINT,
|
||||
now.toString(),
|
||||
NUM_TRANSACTIONS,
|
||||
"0");
|
||||
List<ImmutableObject> exported =
|
||||
deserializeEntities(GcsTestingUtils.readGcsFile(gcsService, expectedFilename));
|
||||
// We expect no manifests or mutations, only the upper checkpoint.
|
||||
assertThat(exported).containsExactly(upperCheckpoint);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_exportingFromStartOfTime_exportsAllCommits() throws Exception {
|
||||
task.lowerCheckpointTime = START_OF_TIME;
|
||||
task.upperCheckpointTime = now;
|
||||
|
||||
CommitLogCheckpoint upperCheckpoint = persistResource(CommitLogCheckpoint.create(
|
||||
now,
|
||||
ImmutableMap.of(1, now, 2, now, 3, now)));
|
||||
|
||||
// Persist some fake commit log manifests.
|
||||
persistManifestAndMutation(1, START_OF_TIME.plusMillis(1)); // Oldest possible manifest time.
|
||||
persistManifestAndMutation(2, oneMinuteAgo);
|
||||
persistManifestAndMutation(3, now);
|
||||
|
||||
task.run();
|
||||
|
||||
GcsFilename expectedFilename = new GcsFilename("gcs bucket", "commit_diff_until_" + now);
|
||||
assertWithMessage("GCS file not found: " + expectedFilename)
|
||||
.that(gcsService.getMetadata(expectedFilename)).isNotNull();
|
||||
assertThat(gcsService.getMetadata(expectedFilename).getOptions().getUserMetadata())
|
||||
.containsExactly(
|
||||
LOWER_BOUND_CHECKPOINT,
|
||||
START_OF_TIME.toString(),
|
||||
UPPER_BOUND_CHECKPOINT,
|
||||
now.toString(),
|
||||
NUM_TRANSACTIONS,
|
||||
"3");
|
||||
List<ImmutableObject> exported =
|
||||
deserializeEntities(GcsTestingUtils.readGcsFile(gcsService, expectedFilename));
|
||||
assertThat(exported.get(0)).isEqualTo(upperCheckpoint);
|
||||
// We expect these manifests, in the order below, with matching mutations.
|
||||
CommitLogManifest manifest1 = createManifest(1, START_OF_TIME.plusMillis(1));
|
||||
CommitLogManifest manifest2 = createManifest(2, oneMinuteAgo);
|
||||
CommitLogManifest manifest3 = createManifest(3, now);
|
||||
assertThat(exported).containsExactly(
|
||||
upperCheckpoint,
|
||||
manifest1,
|
||||
createMutation(manifest1),
|
||||
manifest2,
|
||||
createMutation(manifest2),
|
||||
manifest3,
|
||||
createMutation(manifest3))
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
private CommitLogManifest createManifest(int bucketNum, DateTime commitTime) {
|
||||
return CommitLogManifest.create(CommitLogBucket.getBucketKey(bucketNum), commitTime, null);
|
||||
}
|
||||
|
||||
private CommitLogMutation createMutation(CommitLogManifest manifest) {
|
||||
return CommitLogMutation.create(
|
||||
Key.create(manifest),
|
||||
TestObject.create(manifest.getCommitTime().toString()));
|
||||
}
|
||||
|
||||
private void persistManifestAndMutation(int bucketNum, DateTime commitTime) {
|
||||
persistResource(
|
||||
createMutation(persistResource(createManifest(bucketNum, commitTime))));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.backup;
|
||||
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
|
||||
import static com.google.domain.registry.backup.BackupUtils.GcsMetadataKeys.LOWER_BOUND_CHECKPOINT;
|
||||
import static com.google.domain.registry.backup.ExportCommitLogDiffAction.DIFF_FILE_PREFIX;
|
||||
import static java.lang.reflect.Proxy.newProxyInstance;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.appengine.tools.cloudstorage.GcsFileMetadata;
|
||||
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
|
||||
import com.google.appengine.tools.cloudstorage.GcsFilename;
|
||||
import com.google.appengine.tools.cloudstorage.GcsService;
|
||||
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
|
||||
import com.google.appengine.tools.cloudstorage.ListItem;
|
||||
import com.google.appengine.tools.cloudstorage.ListResult;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Iterators;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.TestObject;
|
||||
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
|
||||
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;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/** Unit tests for {@link GcsDiffFileLister}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class GcsDiffFileListerTest {
|
||||
|
||||
static final String GCS_BUCKET = "gcs bucket";
|
||||
|
||||
final DateTime now = DateTime.now(UTC);
|
||||
final GcsDiffFileLister diffLister = new GcsDiffFileLister();
|
||||
final GcsService gcsService = GcsServiceFactory.createGcsService();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
ObjectifyService.register(TestObject.class);
|
||||
diffLister.gcsService = gcsService;
|
||||
diffLister.gcsBucket = GCS_BUCKET;
|
||||
diffLister.executor = newDirectExecutorService();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
gcsService.createOrReplace(
|
||||
new GcsFilename(GCS_BUCKET, DIFF_FILE_PREFIX + now.minusMinutes(i)),
|
||||
new GcsFileOptions.Builder()
|
||||
.addUserMetadata(LOWER_BOUND_CHECKPOINT, now.minusMinutes(i + 1).toString())
|
||||
.build(),
|
||||
ByteBuffer.wrap(new byte[]{1, 2, 3}));
|
||||
}
|
||||
}
|
||||
|
||||
private Iterable<DateTime> extractTimesFromDiffFiles(List<GcsFileMetadata> diffFiles) {
|
||||
return transform(
|
||||
diffFiles,
|
||||
new Function<GcsFileMetadata, DateTime>() {
|
||||
@Override
|
||||
public DateTime apply(GcsFileMetadata metadata) {
|
||||
return DateTime.parse(
|
||||
metadata.getFilename().getObjectName().substring(DIFF_FILE_PREFIX.length()));
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testList_noFilesFound() {
|
||||
DateTime fromTime = now.plusMillis(1);
|
||||
assertThat(extractTimesFromDiffFiles(diffLister.listDiffFiles(fromTime))).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testList_findsFiles_backToFromTimeExclusive() {
|
||||
DateTime fromTime = now.minusMinutes(2);
|
||||
assertThat(extractTimesFromDiffFiles(diffLister.listDiffFiles(fromTime)))
|
||||
.containsExactly(now.minusMinutes(1), now)
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testList_patchesHoles() throws Exception {
|
||||
// Fake out the GCS list() method to return only the first and last file.
|
||||
// We can't use Mockito.spy() because GcsService's impl is final.
|
||||
diffLister.gcsService = (GcsService) newProxyInstance(
|
||||
GcsService.class.getClassLoader(),
|
||||
new Class<?>[] {GcsService.class},
|
||||
new InvocationHandler() {
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
if (method.getName().equals("list")) {
|
||||
// ListResult is an incredibly annoying thing to construct. It needs to be fed from a
|
||||
// Callable that returns Iterators, each representing a batch of results.
|
||||
return new ListResult(new Callable<Iterator<ListItem>>() {
|
||||
boolean called = false;
|
||||
|
||||
@Override
|
||||
public Iterator<ListItem> call() throws Exception {
|
||||
try {
|
||||
return called ? null : Iterators.forArray(
|
||||
new ListItem.Builder()
|
||||
.setName(DIFF_FILE_PREFIX + now)
|
||||
.build(),
|
||||
new ListItem.Builder()
|
||||
.setName(DIFF_FILE_PREFIX + now.minusMinutes(4))
|
||||
.build());
|
||||
} finally {
|
||||
called = true;
|
||||
}
|
||||
}});
|
||||
}
|
||||
return method.invoke(gcsService, args);
|
||||
}});
|
||||
DateTime fromTime = now.minusMinutes(4).minusSeconds(1);
|
||||
// Request all files with checkpoint > fromTime.
|
||||
assertThat(extractTimesFromDiffFiles(diffLister.listDiffFiles(fromTime)))
|
||||
.containsExactly(
|
||||
now.minusMinutes(4),
|
||||
now.minusMinutes(3),
|
||||
now.minusMinutes(2),
|
||||
now.minusMinutes(1),
|
||||
now)
|
||||
.inOrder();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,319 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.backup;
|
||||
|
||||
import static com.google.appengine.tools.cloudstorage.GcsServiceFactory.createGcsService;
|
||||
import static com.google.common.base.Functions.constant;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.collect.Maps.toMap;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.util.concurrent.MoreExecutors.newDirectExecutorService;
|
||||
import static com.google.domain.registry.backup.BackupUtils.GcsMetadataKeys.LOWER_BOUND_CHECKPOINT;
|
||||
import static com.google.domain.registry.backup.BackupUtils.serializeEntity;
|
||||
import static com.google.domain.registry.backup.ExportCommitLogDiffAction.DIFF_FILE_PREFIX;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.getBucketIds;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.getBucketKey;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.appengine.api.datastore.DatastoreServiceFactory;
|
||||
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
|
||||
import com.google.appengine.tools.cloudstorage.GcsFilename;
|
||||
import com.google.appengine.tools.cloudstorage.GcsService;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.primitives.Longs;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.model.ofy.CommitLogBucket;
|
||||
import com.google.domain.registry.model.ofy.CommitLogCheckpoint;
|
||||
import com.google.domain.registry.model.ofy.CommitLogCheckpointRoot;
|
||||
import com.google.domain.registry.model.ofy.CommitLogManifest;
|
||||
import com.google.domain.registry.model.ofy.CommitLogMutation;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.FakeSleeper;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
import com.google.domain.registry.testing.TestObject;
|
||||
import com.google.domain.registry.util.Retrier;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/** Unit tests for {@link RestoreCommitLogsAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RestoreCommitLogsActionTest {
|
||||
|
||||
static final String GCS_BUCKET = "gcs bucket";
|
||||
|
||||
final DateTime now = DateTime.now(UTC);
|
||||
final RestoreCommitLogsAction action = new RestoreCommitLogsAction();
|
||||
final GcsService gcsService = createGcsService();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule();
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
ObjectifyService.register(TestObject.class);
|
||||
action.gcsService = gcsService;
|
||||
action.dryRun = false;
|
||||
action.datastoreService = DatastoreServiceFactory.getDatastoreService();
|
||||
action.fromTime = now.minusMillis(1);
|
||||
action.retrier = new Retrier(new FakeSleeper(new FakeClock()), 1);
|
||||
action.diffLister = new GcsDiffFileLister();
|
||||
action.diffLister.gcsService = gcsService;
|
||||
action.diffLister.gcsBucket = GCS_BUCKET;
|
||||
action.diffLister.executor = newDirectExecutorService();
|
||||
configRule.override(new TestRegistryConfig() {
|
||||
@Override
|
||||
public int getCommitLogBucketCount() {
|
||||
return 3;
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestore_multipleDiffFiles() throws Exception {
|
||||
ofy().saveWithoutBackup().entities(
|
||||
TestObject.create("previous to keep"),
|
||||
TestObject.create("previous to delete")).now();
|
||||
// Create 3 transactions, across two diff files.
|
||||
// Before: {"previous to keep", "previous to delete"}
|
||||
// 1a: Add {"a", "b"}, Delete {"previous to delete"}
|
||||
// 1b: Add {"c", "d"}, Delete {"a"}
|
||||
// 2: Add {"e", "f"}, Delete {"c"}
|
||||
// After: {"previous to keep", "b", "d", "e", "f"}
|
||||
Key<CommitLogManifest> manifest1aKey =
|
||||
CommitLogManifest.createKey(getBucketKey(1), now.minusMinutes(3));
|
||||
Key<CommitLogManifest> manifest1bKey =
|
||||
CommitLogManifest.createKey(getBucketKey(2), now.minusMinutes(2));
|
||||
Key<CommitLogManifest> manifest2Key =
|
||||
CommitLogManifest.createKey(getBucketKey(1), now.minusMinutes(1));
|
||||
saveDiffFileNotToRestore(now.minusMinutes(2));
|
||||
Iterable<ImmutableObject> file1CommitLogs = saveDiffFile(
|
||||
createCheckpoint(now.minusMinutes(1)),
|
||||
CommitLogManifest.create(
|
||||
getBucketKey(1),
|
||||
now.minusMinutes(3),
|
||||
ImmutableSet.<Key<?>>of(Key.create(TestObject.create("previous to delete")))),
|
||||
CommitLogMutation.create(manifest1aKey, TestObject.create("a")),
|
||||
CommitLogMutation.create(manifest1aKey, TestObject.create("b")),
|
||||
CommitLogManifest.create(
|
||||
getBucketKey(2),
|
||||
now.minusMinutes(2),
|
||||
ImmutableSet.<Key<?>>of(Key.create(TestObject.create("a")))),
|
||||
CommitLogMutation.create(manifest1bKey, TestObject.create("c")),
|
||||
CommitLogMutation.create(manifest1bKey, TestObject.create("d")));
|
||||
Iterable<ImmutableObject> file2CommitLogs = saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(
|
||||
getBucketKey(1),
|
||||
now.minusMinutes(1),
|
||||
ImmutableSet.<Key<?>>of(Key.create(TestObject.create("c")))),
|
||||
CommitLogMutation.create(manifest2Key, TestObject.create("e")),
|
||||
CommitLogMutation.create(manifest2Key, TestObject.create("f")));
|
||||
action.fromTime = now.minusMinutes(1).minusMillis(1);
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertExpectedIds("previous to keep", "b", "d", "e", "f");
|
||||
assertInDatastore(file1CommitLogs);
|
||||
assertInDatastore(file2CommitLogs);
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
assertCommitLogBuckets(ImmutableMap.of(1, now.minusMinutes(1), 2, now.minusMinutes(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestore_noManifests() throws Exception {
|
||||
ofy().saveWithoutBackup().entity(
|
||||
TestObject.create("previous to keep")).now();
|
||||
saveDiffFileNotToRestore(now.minusMinutes(1));
|
||||
Iterable<ImmutableObject> commitLogs = saveDiffFile(createCheckpoint(now));
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertExpectedIds("previous to keep");
|
||||
assertInDatastore(commitLogs);
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
assertCommitLogBuckets(ImmutableMap.<Integer, DateTime>of());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestore_manifestWithNoDeletions() throws Exception {
|
||||
ofy().saveWithoutBackup().entity(TestObject.create("previous to keep")).now();
|
||||
Key<CommitLogBucket> bucketKey = getBucketKey(1);
|
||||
Key<CommitLogManifest> manifestKey = CommitLogManifest.createKey(bucketKey, now);
|
||||
saveDiffFileNotToRestore(now.minusMinutes(1));
|
||||
Iterable<ImmutableObject> commitLogs = saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(bucketKey, now, null),
|
||||
CommitLogMutation.create(manifestKey, TestObject.create("a")),
|
||||
CommitLogMutation.create(manifestKey, TestObject.create("b")));
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertExpectedIds("previous to keep", "a", "b");
|
||||
assertInDatastore(commitLogs);
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
assertCommitLogBuckets(ImmutableMap.of(1, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestore_manifestWithNoMutations() throws Exception {
|
||||
ofy().saveWithoutBackup().entities(
|
||||
TestObject.create("previous to keep"),
|
||||
TestObject.create("previous to delete")).now();
|
||||
saveDiffFileNotToRestore(now.minusMinutes(1));
|
||||
Iterable<ImmutableObject> commitLogs = saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(
|
||||
getBucketKey(1),
|
||||
now,
|
||||
ImmutableSet.<Key<?>>of(Key.create(TestObject.create("previous to delete")))));
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertExpectedIds("previous to keep");
|
||||
assertInDatastore(commitLogs);
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
assertCommitLogBuckets(ImmutableMap.of(1, now));
|
||||
}
|
||||
|
||||
// This is a pathological case that shouldn't be possible, but we should be robust to it.
|
||||
@Test
|
||||
public void testRestore_manifestWithNoMutationsOrDeletions() throws Exception {
|
||||
ofy().saveWithoutBackup().entities(
|
||||
TestObject.create("previous to keep")).now();
|
||||
saveDiffFileNotToRestore(now.minusMinutes(1));
|
||||
Iterable<ImmutableObject> commitLogs = saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(getBucketKey(1), now, null));
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertExpectedIds("previous to keep");
|
||||
assertInDatastore(commitLogs);
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
assertCommitLogBuckets(ImmutableMap.of(1, now));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestore_mutateExistingEntity() throws Exception {
|
||||
ofy().saveWithoutBackup().entity(TestObject.create("existing", "a")).now();
|
||||
Key<CommitLogManifest> manifestKey = CommitLogManifest.createKey(getBucketKey(1), now);
|
||||
saveDiffFileNotToRestore(now.minusMinutes(1));
|
||||
Iterable<ImmutableObject> commitLogs = saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(getBucketKey(1), now, null),
|
||||
CommitLogMutation.create(manifestKey, TestObject.create("existing", "b")));
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().entity(TestObject.create("existing")).now().getField()).isEqualTo("b");
|
||||
assertInDatastore(commitLogs);
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
assertCommitLogBuckets(ImmutableMap.of(1, now));
|
||||
}
|
||||
|
||||
// This should be harmless; deletes are idempotent.
|
||||
@Test
|
||||
public void testRestore_deleteMissingEntity() throws Exception {
|
||||
ofy().saveWithoutBackup().entity(TestObject.create("previous to keep", "a")).now();
|
||||
saveDiffFileNotToRestore(now.minusMinutes(1));
|
||||
Iterable<ImmutableObject> commitLogs = saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(
|
||||
getBucketKey(1),
|
||||
now,
|
||||
ImmutableSet.<Key<?>>of(Key.create(TestObject.create("previous to delete")))));
|
||||
action.run();
|
||||
ofy().clearSessionCache();
|
||||
assertExpectedIds("previous to keep");
|
||||
assertInDatastore(commitLogs);
|
||||
assertCommitLogBuckets(ImmutableMap.of(1, now));
|
||||
assertInDatastore(asList(CommitLogCheckpointRoot.create(now)));
|
||||
}
|
||||
|
||||
private CommitLogCheckpoint createCheckpoint(DateTime now) {
|
||||
return CommitLogCheckpoint.create(now, toMap(getBucketIds(), constant(now)));
|
||||
}
|
||||
|
||||
private Iterable<ImmutableObject> saveDiffFile(
|
||||
CommitLogCheckpoint checkpoint, ImmutableObject... entities) throws IOException {
|
||||
DateTime now = checkpoint.getCheckpointTime();
|
||||
List<ImmutableObject> allEntities = Lists.<ImmutableObject>asList(checkpoint, entities);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
for (ImmutableObject entity : allEntities) {
|
||||
serializeEntity(entity, output);
|
||||
}
|
||||
gcsService.createOrReplace(
|
||||
new GcsFilename(GCS_BUCKET, DIFF_FILE_PREFIX + now),
|
||||
new GcsFileOptions.Builder()
|
||||
.addUserMetadata(LOWER_BOUND_CHECKPOINT, now.minusMinutes(1).toString())
|
||||
.build(),
|
||||
ByteBuffer.wrap(output.toByteArray()));
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
private void saveDiffFileNotToRestore(DateTime now) throws Exception {
|
||||
saveDiffFile(
|
||||
createCheckpoint(now),
|
||||
CommitLogManifest.create(getBucketKey(1), now, null),
|
||||
CommitLogMutation.create(
|
||||
CommitLogManifest.createKey(getBucketKey(1), now),
|
||||
TestObject.create("should not be restored")));
|
||||
}
|
||||
|
||||
private void assertExpectedIds(String... ids) {
|
||||
assertThat(transform(
|
||||
ofy().load().type(TestObject.class),
|
||||
new Function<TestObject, String>() {
|
||||
@Override
|
||||
public String apply(TestObject test) {
|
||||
return test.getId();
|
||||
}})).containsExactly((Object[]) ids);
|
||||
}
|
||||
|
||||
private void assertInDatastore(Iterable<? extends ImmutableObject> entities) {
|
||||
assertThat(ofy().load().entities(entities).values()).containsExactlyElementsIn(entities);
|
||||
}
|
||||
|
||||
private void assertCommitLogBuckets(Map<Integer, DateTime> bucketIdsAndTimestamps) {
|
||||
Map<Long, CommitLogBucket> buckets = ofy().load()
|
||||
.type(CommitLogBucket.class)
|
||||
.ids(Longs.asList(Longs.toArray(CommitLogBucket.getBucketIds())));
|
||||
assertThat(buckets).hasSize(bucketIdsAndTimestamps.size());
|
||||
for (Entry<Integer, DateTime> bucketIdAndTimestamp : bucketIdsAndTimestamps.entrySet()) {
|
||||
assertThat(buckets.get((long) bucketIdAndTimestamp.getKey()).getLastWrittenTime())
|
||||
.isEqualTo(bucketIdAndTimestamp.getValue());
|
||||
}
|
||||
}
|
||||
}
|
28
javatests/com/google/domain/registry/bigquery/BUILD
Normal file
28
javatests/com/google/domain/registry/bigquery/BUILD
Normal file
|
@ -0,0 +1,28 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "bigquery",
|
||||
srcs = glob(["*.java"]),
|
||||
resources = glob(["testdata/*"]),
|
||||
deps = [
|
||||
"//apiserving/discoverydata/bigquery:bigqueryv2",
|
||||
"//java/com/google/domain/registry/bigquery",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":bigquery"],
|
||||
)
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.bigquery;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link BigqueryConnection}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class BigqueryConnectionTest {
|
||||
|
||||
@Test
|
||||
public void testNothing() throws Exception {
|
||||
// Placeholder test class for now.
|
||||
// TODO(b/16569089): figure out a good way for testing our Bigquery usage overall - maybe unit
|
||||
// tests here, maybe end-to-end testing.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.bigquery;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.bigquery.BigqueryUtils.fromBigqueryTimestampString;
|
||||
import static com.google.domain.registry.bigquery.BigqueryUtils.toBigqueryTimestamp;
|
||||
import static com.google.domain.registry.bigquery.BigqueryUtils.toBigqueryTimestampString;
|
||||
import static com.google.domain.registry.bigquery.BigqueryUtils.toJobReferenceString;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.api.services.bigquery.model.JobReference;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/** Unit tests for {@link BigqueryUtils}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class BigqueryUtilsTest {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
private static final DateTime DATE_0 = DateTime.parse("2014-07-17T20:35:42Z");
|
||||
private static final DateTime DATE_1 = DateTime.parse("2014-07-17T20:35:42.1Z");
|
||||
private static final DateTime DATE_2 = DateTime.parse("2014-07-17T20:35:42.12Z");
|
||||
private static final DateTime DATE_3 = DateTime.parse("2014-07-17T20:35:42.123Z");
|
||||
|
||||
@Test
|
||||
public void test_toBigqueryTimestampString() throws Exception {
|
||||
assertThat(toBigqueryTimestampString(START_OF_TIME)).isEqualTo("1970-01-01 00:00:00.000");
|
||||
assertThat(toBigqueryTimestampString(DATE_0)).isEqualTo("2014-07-17 20:35:42.000");
|
||||
assertThat(toBigqueryTimestampString(DATE_1)).isEqualTo("2014-07-17 20:35:42.100");
|
||||
assertThat(toBigqueryTimestampString(DATE_2)).isEqualTo("2014-07-17 20:35:42.120");
|
||||
assertThat(toBigqueryTimestampString(DATE_3)).isEqualTo("2014-07-17 20:35:42.123");
|
||||
assertThat(toBigqueryTimestampString(END_OF_TIME)).isEqualTo("294247-01-10 04:00:54.775");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toBigqueryTimestampString_convertsToUtc() throws Exception {
|
||||
assertThat(toBigqueryTimestampString(START_OF_TIME.withZone(DateTimeZone.forOffsetHours(5))))
|
||||
.isEqualTo("1970-01-01 00:00:00.000");
|
||||
assertThat(toBigqueryTimestampString(DateTime.parse("1970-01-01T00:00:00-0500")))
|
||||
.isEqualTo("1970-01-01 05:00:00.000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_fromBigqueryTimestampString_startAndEndOfTime() throws Exception {
|
||||
assertThat(fromBigqueryTimestampString("1970-01-01 00:00:00 UTC")).isEqualTo(START_OF_TIME);
|
||||
assertThat(fromBigqueryTimestampString("294247-01-10 04:00:54.775 UTC")).isEqualTo(END_OF_TIME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_fromBigqueryTimestampString_trailingZerosOkay() throws Exception {
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42 UTC")).isEqualTo(DATE_0);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.0 UTC")).isEqualTo(DATE_0);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.00 UTC")).isEqualTo(DATE_0);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.000 UTC")).isEqualTo(DATE_0);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.1 UTC")).isEqualTo(DATE_1);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.10 UTC")).isEqualTo(DATE_1);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.100 UTC")).isEqualTo(DATE_1);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.12 UTC")).isEqualTo(DATE_2);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.120 UTC")).isEqualTo(DATE_2);
|
||||
assertThat(fromBigqueryTimestampString("2014-07-17 20:35:42.123 UTC")).isEqualTo(DATE_3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_fromBigqueryTimestampString_nonUtcTimeZone() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
fromBigqueryTimestampString("2014-01-01 01:01:01 +05:00");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_fromBigqueryTimestampString_noTimeZone() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
fromBigqueryTimestampString("2014-01-01 01:01:01");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_fromBigqueryTimestampString_tooManyMillisecondDigits() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
fromBigqueryTimestampString("2014-01-01 01:01:01.1234 UTC");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toBigqueryTimestamp_timeunitConversion() throws Exception {
|
||||
assertThat(toBigqueryTimestamp(1234567890L, TimeUnit.SECONDS))
|
||||
.isEqualTo("1234567890.000000");
|
||||
assertThat(toBigqueryTimestamp(1234567890123L, TimeUnit.MILLISECONDS))
|
||||
.isEqualTo("1234567890.123000");
|
||||
assertThat(toBigqueryTimestamp(1234567890123000L, TimeUnit.MICROSECONDS))
|
||||
.isEqualTo("1234567890.123000");
|
||||
assertThat(toBigqueryTimestamp(1234567890123000000L, TimeUnit.NANOSECONDS))
|
||||
.isEqualTo("1234567890.123000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toBigqueryTimestamp_timeunitConversionForZero() throws Exception {
|
||||
assertThat(toBigqueryTimestamp(0L, TimeUnit.SECONDS)).isEqualTo("0.000000");
|
||||
assertThat(toBigqueryTimestamp(0L, TimeUnit.MILLISECONDS)).isEqualTo("0.000000");
|
||||
assertThat(toBigqueryTimestamp(0L, TimeUnit.MICROSECONDS)).isEqualTo("0.000000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toBigqueryTimestamp_datetimeConversion() throws Exception {
|
||||
assertThat(toBigqueryTimestamp(START_OF_TIME)).isEqualTo("0.000000");
|
||||
assertThat(toBigqueryTimestamp(DATE_0)).isEqualTo("1405629342.000000");
|
||||
assertThat(toBigqueryTimestamp(DATE_1)).isEqualTo("1405629342.100000");
|
||||
assertThat(toBigqueryTimestamp(DATE_2)).isEqualTo("1405629342.120000");
|
||||
assertThat(toBigqueryTimestamp(DATE_3)).isEqualTo("1405629342.123000");
|
||||
assertThat(toBigqueryTimestamp(END_OF_TIME)).isEqualTo("9223372036854.775000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toJobReferenceString_normalSucceeds() throws Exception {
|
||||
assertThat(toJobReferenceString(new JobReference().setProjectId("foo").setJobId("bar")))
|
||||
.isEqualTo("foo:bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toJobReferenceString_emptyReferenceSucceeds() throws Exception {
|
||||
assertThat(toJobReferenceString(new JobReference())).isEqualTo("null:null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_toJobReferenceString_nullThrowsNpe() throws Exception {
|
||||
thrown.expect(NullPointerException.class);
|
||||
toJobReferenceString(null);
|
||||
}
|
||||
}
|
21
javatests/com/google/domain/registry/config/BUILD
Normal file
21
javatests/com/google/domain/registry/config/BUILD
Normal file
|
@ -0,0 +1,21 @@
|
|||
package(default_visibility = ["//java/com/google/domain/registry:registry_project"])
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "config",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/common/annotations",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":config"],
|
||||
)
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.config;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RegistryEnvironment}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RegistryEnvironmentTest {
|
||||
|
||||
@Test
|
||||
public void testGet() throws Exception {
|
||||
RegistryEnvironment.get();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverride() throws Exception {
|
||||
RegistryEnvironment.overrideConfigurationForTesting(new TestRegistryConfig() {
|
||||
@Override
|
||||
public String getSnapshotsBucket() {
|
||||
return "black velvet";
|
||||
}});
|
||||
assertThat(RegistryEnvironment.get().config().getSnapshotsBucket()).isEqualTo("black velvet");
|
||||
}
|
||||
}
|
32
javatests/com/google/domain/registry/cron/BUILD
Normal file
32
javatests/com/google/domain/registry/cron/BUILD
Normal file
|
@ -0,0 +1,32 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "cron",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/domain/registry/cron",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":cron"],
|
||||
)
|
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.cron;
|
||||
|
||||
import static com.google.domain.registry.cron.CommitLogFanoutAction.BUCKET_PARAM;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.domain.registry.model.ofy.CommitLogBucket;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import com.google.domain.registry.util.Retrier;
|
||||
import com.google.domain.registry.util.TaskEnqueuer;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Unit tests for {@link CommitLogFanoutAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CommitLogFanoutActionTest {
|
||||
|
||||
private static final String ENDPOINT = "/the/servlet";
|
||||
private static final String QUEUE = "the-queue";
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue(Joiner.on('\n').join(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
|
||||
"<queue-entries>",
|
||||
" <queue>",
|
||||
" <name>the-queue</name>",
|
||||
" <rate>1/s</rate>",
|
||||
" </queue>",
|
||||
"</queue-entries>"))
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
CommitLogFanoutAction action = new CommitLogFanoutAction();
|
||||
action.taskEnqueuer = new TaskEnqueuer(new Retrier(null, 1));
|
||||
action.endpoint = ENDPOINT;
|
||||
action.queue = QUEUE;
|
||||
action.jitterSeconds = Optional.absent();
|
||||
action.run();
|
||||
List<TaskMatcher> matchers = new ArrayList<>();
|
||||
for (int bucketId : CommitLogBucket.getBucketIds()) {
|
||||
matchers.add(new TaskMatcher().url(ENDPOINT).param(BUCKET_PARAM, Integer.toString(bucketId)));
|
||||
}
|
||||
assertTasksEnqueued(QUEUE, matchers);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.cron;
|
||||
|
||||
import static com.google.common.collect.Iterables.getLast;
|
||||
import static com.google.common.collect.Lists.transform;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTlds;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableListMultimap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.registry.Registry.TldType;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import com.google.domain.registry.util.Retrier;
|
||||
import com.google.domain.registry.util.TaskEnqueuer;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link TldFanoutAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class TldFanoutActionTest {
|
||||
|
||||
private static final String ENDPOINT = "/the/servlet";
|
||||
private static final String QUEUE = "the-queue";
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue(Joiner.on('\n').join(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
|
||||
"<queue-entries>",
|
||||
" <queue>",
|
||||
" <name>the-queue</name>",
|
||||
" <rate>1/s</rate>",
|
||||
" </queue>",
|
||||
"</queue-entries>"))
|
||||
.build();
|
||||
|
||||
private static ImmutableListMultimap<String, String> getParamsMap(String... keysAndValues) {
|
||||
ImmutableListMultimap.Builder<String, String> params = new ImmutableListMultimap.Builder<>();
|
||||
params.put("queue", QUEUE);
|
||||
params.put("endpoint", ENDPOINT);
|
||||
for (int i = 0; i < keysAndValues.length; i += 2) {
|
||||
params.put(keysAndValues[i], keysAndValues[i + 1]);
|
||||
}
|
||||
return params.build();
|
||||
}
|
||||
|
||||
private static void run(ImmutableListMultimap<String, String> params) throws Exception {
|
||||
TldFanoutAction action = new TldFanoutAction();
|
||||
action.params = params;
|
||||
action.endpoint = getLast(params.get("endpoint"));
|
||||
action.queue = getLast(params.get("queue"));
|
||||
action.excludes = params.containsKey("exclude")
|
||||
? ImmutableSet.copyOf(Splitter.on(',').split(params.get("exclude").get(0)))
|
||||
: ImmutableSet.<String>of();
|
||||
action.taskEnqueuer = new TaskEnqueuer(new Retrier(null, 1));
|
||||
action.runInEmpty = params.containsKey("runInEmpty");
|
||||
action.forEachRealTld = params.containsKey("forEachRealTld");
|
||||
action.forEachTestTld = params.containsKey("forEachTestTld");
|
||||
action.jitterSeconds = Optional.absent();
|
||||
action.run();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
createTlds("com", "net", "org", "example");
|
||||
persistResource(Registry.get("example").asBuilder().setTldType(TldType.TEST).build());
|
||||
}
|
||||
|
||||
private static void assertTasks(String... tasks) throws Exception {
|
||||
assertTasksEnqueued(
|
||||
QUEUE,
|
||||
transform(asList(tasks), new Function<String, TaskMatcher>() {
|
||||
@Override
|
||||
public TaskMatcher apply(String namespace) {
|
||||
return new TaskMatcher()
|
||||
.url(ENDPOINT)
|
||||
.header("content-type", "application/x-www-form-urlencoded")
|
||||
.param("tld", namespace);
|
||||
}}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pathargTld() throws Exception {
|
||||
run(getParamsMap(
|
||||
"forEachRealTld", "",
|
||||
"endpoint", "/the/servlet/:tld"));
|
||||
assertTasksEnqueued(QUEUE,
|
||||
new TaskMatcher().url("/the/servlet/com"),
|
||||
new TaskMatcher().url("/the/servlet/net"),
|
||||
new TaskMatcher().url("/the/servlet/org"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_methodPostIsDefault() throws Exception {
|
||||
run(getParamsMap("runInEmpty", ""));
|
||||
assertTasksEnqueued(QUEUE, new TaskMatcher().method("POST"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_noTlds() throws Exception {
|
||||
run(getParamsMap());
|
||||
assertNoTasksEnqueued(QUEUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_runInEmpty() throws Exception {
|
||||
run(getParamsMap("runInEmpty", ""));
|
||||
assertTasks("");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_forEachRealTld() throws Exception {
|
||||
run(getParamsMap("forEachRealTld", ""));
|
||||
assertTasks("com", "net", "org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_forEachTestTld() throws Exception {
|
||||
run(getParamsMap("forEachTestTld", ""));
|
||||
assertTasks("example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_runInEmptyAndRunInRealTld() throws Exception {
|
||||
run(getParamsMap("runInEmpty", "", "forEachRealTld", ""));
|
||||
assertTasks("", "com", "net", "org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_forEachTestTldAndForEachRealTld() throws Exception {
|
||||
run(getParamsMap(
|
||||
"forEachTestTld", "",
|
||||
"forEachRealTld", ""));
|
||||
assertTasks("com", "net", "org", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_runInEmptyAndForEachTestTld() throws Exception {
|
||||
run(getParamsMap("runInEmpty", "", "forEachTestTld", ""));
|
||||
assertTasks("", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_runEverywhere() throws Exception {
|
||||
run(getParamsMap("runInEmpty", "", "forEachTestTld", "", "forEachRealTld", ""));
|
||||
assertTasks("", "com", "net", "org", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_excludeRealTlds() throws Exception {
|
||||
run(getParamsMap(
|
||||
"forEachRealTld", "",
|
||||
"exclude", "com,net"));
|
||||
assertTasks("org");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_excludeTestTlds() throws Exception {
|
||||
run(getParamsMap(
|
||||
"forEachTestTld", "",
|
||||
"exclude", "example"));
|
||||
assertNoTasksEnqueued(QUEUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_excludeNonexistentTlds() throws Exception {
|
||||
run(getParamsMap(
|
||||
"runInEmpty", "",
|
||||
"forEachTestTld", "",
|
||||
"forEachRealTld", "",
|
||||
"exclude", "foo"));
|
||||
assertTasks("", "com", "net", "org", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_additionalArgsFlowThroughToPostParams() throws Exception {
|
||||
run(getParamsMap("forEachTestTld", "", "newkey", "newval"));
|
||||
assertTasksEnqueued(QUEUE,
|
||||
new TaskMatcher().url("/the/servlet").param("newkey", "newval"));
|
||||
}
|
||||
}
|
44
javatests/com/google/domain/registry/dns/BUILD
Normal file
44
javatests/com/google/domain/registry/dns/BUILD
Normal file
|
@ -0,0 +1,44 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "dns",
|
||||
srcs = glob(["*.java"]),
|
||||
resources = glob(["testdata/*.txt"]),
|
||||
deps = [
|
||||
"//java/com/google/common/annotations",
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/io",
|
||||
"//java/com/google/common/net",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//java/com/google/domain/registry/dns",
|
||||
"//java/com/google/domain/registry/dns:constants",
|
||||
"//java/com/google/domain/registry/dns/writer/api",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/module/backend",
|
||||
"//java/com/google/domain/registry/request",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/dagger",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/jsr330_inject",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":dns"],
|
||||
)
|
106
javatests/com/google/domain/registry/dns/DnsInjectionTest.java
Normal file
106
javatests/com/google/domain/registry/dns/DnsInjectionTest.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveSubordinateHost;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.request.HttpException.NotFoundException;
|
||||
import com.google.domain.registry.request.RequestModule;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
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;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Unit tests for Dagger injection of the DNS package. */
|
||||
@RunWith(JUnit4.class)
|
||||
public final class DnsInjectionTest {
|
||||
|
||||
@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 HttpServletRequest req = mock(HttpServletRequest.class);
|
||||
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
|
||||
private final StringWriter httpOutput = new StringWriter();
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2014-01-01TZ"));
|
||||
private DnsTestComponent component;
|
||||
private DnsQueue dnsQueue;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
||||
component = DaggerDnsTestComponent.builder()
|
||||
.requestModule(new RequestModule(req, rsp))
|
||||
.build();
|
||||
dnsQueue = component.dnsQueue();
|
||||
createTld("lol");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteDnsTask_injectsAndWorks() throws Exception {
|
||||
persistActiveSubordinateHost("ns1.example.lol", persistActiveDomain("example.lol"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example.lol");
|
||||
when(req.getParameter("tld")).thenReturn("lol");
|
||||
component.writeDnsTask().run();
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhoisHttpServer_injectsAndWorks() throws Exception {
|
||||
persistActiveDomain("example.lol");
|
||||
when(req.getParameter("type")).thenReturn("domain");
|
||||
when(req.getParameter("name")).thenReturn("example.lol");
|
||||
component.refreshDns().run();
|
||||
assertDnsTasksEnqueued("example.lol");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWhoisHttpServer_missingDomain_throwsNotFound() throws Exception {
|
||||
when(req.getParameter("type")).thenReturn("domain");
|
||||
when(req.getParameter("name")).thenReturn("example.lol");
|
||||
thrown.expect(NotFoundException.class, "DOMAIN example.lol not found");
|
||||
component.refreshDns().run();
|
||||
}
|
||||
}
|
93
javatests/com/google/domain/registry/dns/DnsQueueTest.java
Normal file
93
javatests/com/google/domain/registry/dns/DnsQueueTest.java
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link DnsQueue}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DnsQueueTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
private DnsQueue dnsQueue;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
dnsQueue = new DnsQueue();
|
||||
dnsQueue.queue = getQueue("dns-pull");
|
||||
dnsQueue.writeBatchSize = 10;
|
||||
dnsQueue.writeLockTimeout = Duration.standardSeconds(30);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_addHostRefreshTask_success() throws Exception {
|
||||
createTld("tld");
|
||||
dnsQueue.addHostRefreshTask("octopus.tld");
|
||||
assertTasksEnqueued("dns-pull",
|
||||
new TaskMatcher().tag("tld").payload("Target-Type=HOST&Target-Name=octopus.tld&tld=tld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_addHostRefreshTask_failsOnUnknownTld() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class,
|
||||
"octopus.notatld is not a subordinate host to a known tld");
|
||||
try {
|
||||
dnsQueue.addHostRefreshTask("octopus.notatld");
|
||||
} finally {
|
||||
assertNoTasksEnqueued("dns-pull");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_addDomainRefreshTask_success() throws Exception {
|
||||
createTld("tld");
|
||||
dnsQueue.addDomainRefreshTask("octopus.tld");
|
||||
assertTasksEnqueued("dns-pull",
|
||||
new TaskMatcher().tag("tld").payload("Target-Type=DOMAIN&Target-Name=octopus.tld&tld=tld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_addDomainRefreshTask_failsOnUnknownTld() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class, "TLD notatld does not exist");
|
||||
try {
|
||||
dnsQueue.addDomainRefreshTask("fake.notatld");
|
||||
} finally {
|
||||
assertNoTasksEnqueued("dns-pull");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import com.google.domain.registry.config.ConfigModule;
|
||||
import com.google.domain.registry.dns.writer.api.VoidDnsWriterModule;
|
||||
import com.google.domain.registry.module.backend.BackendModule;
|
||||
import com.google.domain.registry.request.RequestModule;
|
||||
import com.google.domain.registry.util.SystemClock.SystemClockModule;
|
||||
|
||||
import dagger.Component;
|
||||
|
||||
@Component(modules = {
|
||||
SystemClockModule.class,
|
||||
ConfigModule.class,
|
||||
BackendModule.class,
|
||||
DnsModule.class,
|
||||
RequestModule.class,
|
||||
VoidDnsWriterModule.class,
|
||||
})
|
||||
interface DnsTestComponent {
|
||||
DnsQueue dnsQueue();
|
||||
RefreshDns refreshDns();
|
||||
WriteDnsTask writeDnsTask();
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveSubordinateHost;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.dns.writer.api.DnsWriter;
|
||||
import com.google.domain.registry.model.domain.DomainResource;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
/** Unit tests for {@link WriteDnsTask}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PublishDnsUpdatesActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("1971-01-01TZ"));
|
||||
private final DnsWriter dnsWriter = mock(DnsWriter.class);
|
||||
private PublishDnsUpdatesAction action;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
createTld("xn--q9jyb4c");
|
||||
DomainResource domain1 = persistActiveDomain("example.xn--q9jyb4c");
|
||||
persistActiveSubordinateHost("ns1.example.xn--q9jyb4c", domain1);
|
||||
persistActiveSubordinateHost("ns2.example.xn--q9jyb4c", domain1);
|
||||
DomainResource domain2 = persistActiveDomain("example2.xn--q9jyb4c");
|
||||
persistActiveSubordinateHost("ns1.example.xn--q9jyb4c", domain2);
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
private PublishDnsUpdatesAction createAction(String tld) {
|
||||
PublishDnsUpdatesAction action = new PublishDnsUpdatesAction();
|
||||
action.timeout = Duration.standardSeconds(10);
|
||||
action.tld = tld;
|
||||
action.hosts = ImmutableSet.<String>of();
|
||||
action.domains = ImmutableSet.<String>of();
|
||||
action.writerProvider = new Provider<DnsWriter>() {
|
||||
@Override
|
||||
public DnsWriter get() {
|
||||
return dnsWriter;
|
||||
}};
|
||||
return action;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHost_published() throws Exception {
|
||||
action = createAction("xn--q9jyb4c");
|
||||
action.hosts = ImmutableSet.of("ns1.example.xn--q9jyb4c");
|
||||
action.run();
|
||||
verify(dnsWriter).publishHost("ns1.example.xn--q9jyb4c");
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomain_published() throws Exception {
|
||||
action = createAction("xn--q9jyb4c");
|
||||
action.domains = ImmutableSet.of("example.xn--q9jyb4c");
|
||||
action.run();
|
||||
verify(dnsWriter).publishDomain("example.xn--q9jyb4c");
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostAndDomain_published() throws Exception {
|
||||
action = createAction("xn--q9jyb4c");
|
||||
action.domains = ImmutableSet.of("example.xn--q9jyb4c", "example2.xn--q9jyb4c");
|
||||
action.hosts = ImmutableSet.of(
|
||||
"ns1.example.xn--q9jyb4c", "ns2.example.xn--q9jyb4c", "ns1.example2.xn--q9jyb4c");
|
||||
action.run();
|
||||
verify(dnsWriter).publishDomain("example.xn--q9jyb4c");
|
||||
verify(dnsWriter).publishDomain("example2.xn--q9jyb4c");
|
||||
verify(dnsWriter).publishHost("ns1.example.xn--q9jyb4c");
|
||||
verify(dnsWriter).publishHost("ns2.example.xn--q9jyb4c");
|
||||
verify(dnsWriter).publishHost("ns1.example2.xn--q9jyb4c");
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongTld_notPublished() throws Exception {
|
||||
action = createAction("xn--q9jyb4c");
|
||||
action.domains = ImmutableSet.of("example.com", "example2.com");
|
||||
action.hosts = ImmutableSet.of("ns1.example.com", "ns2.example.com", "ns1.example2.com");
|
||||
action.run();
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,267 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import static com.google.common.collect.Lists.transform;
|
||||
import static com.google.domain.registry.dns.DnsConstants.DNS_PUBLISH_PUSH_QUEUE_NAME;
|
||||
import static com.google.domain.registry.dns.DnsConstants.DNS_TARGET_NAME_PARAM;
|
||||
import static com.google.domain.registry.dns.DnsConstants.DNS_TARGET_TYPE_PARAM;
|
||||
import static com.google.domain.registry.request.RequestParameters.PARAM_TLD;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTlds;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.InternetDomainName;
|
||||
import com.google.domain.registry.dns.DnsConstants.TargetType;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.registry.Registry.TldType;
|
||||
import com.google.domain.registry.request.RequestParameters;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import com.google.domain.registry.util.Retrier;
|
||||
import com.google.domain.registry.util.TaskEnqueuer;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/** Unit tests for {@link ReadDnsQueueAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ReadDnsQueueActionTest {
|
||||
|
||||
private static final int TEST_TLD_UPDATE_BATCH_SIZE = 100;
|
||||
private DnsQueue dnsQueue;
|
||||
private FakeClock clock = new FakeClock(DateTime.now(DateTimeZone.UTC));
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue(Joiner.on('\n').join(
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>",
|
||||
"<queue-entries>",
|
||||
" <queue>",
|
||||
" <name>dns-publish</name>",
|
||||
" <rate>1/s</rate>",
|
||||
" </queue>",
|
||||
" <queue>",
|
||||
" <name>dns-pull</name>",
|
||||
" <mode>pull</mode>",
|
||||
" </queue>",
|
||||
"</queue-entries>"))
|
||||
.withClock(clock)
|
||||
.build();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
clock.setTo(DateTime.now(DateTimeZone.UTC));
|
||||
createTlds("com", "net", "example");
|
||||
persistResource(Registry.get("example").asBuilder().setTldType(TldType.TEST).build());
|
||||
dnsQueue = DnsQueue.create();
|
||||
dnsQueue.writeLockTimeout = Duration.standardSeconds(10);
|
||||
}
|
||||
|
||||
private void run(boolean keepTasks) throws Exception {
|
||||
ReadDnsQueueAction action = new ReadDnsQueueAction();
|
||||
action.tldUpdateBatchSize = TEST_TLD_UPDATE_BATCH_SIZE;
|
||||
action.dnsQueue = dnsQueue;
|
||||
action.dnsPublishPushQueue = QueueFactory.getQueue(DNS_PUBLISH_PUSH_QUEUE_NAME);
|
||||
action.taskEnqueuer = new TaskEnqueuer(new Retrier(null, 1));
|
||||
action.jitterSeconds = Optional.absent();
|
||||
action.keepTasks = keepTasks;
|
||||
// Advance the time a little, to ensure that leaseTasks() returns all tasks.
|
||||
clock.setTo(DateTime.now(DateTimeZone.UTC).plusMillis(1));
|
||||
action.run();
|
||||
}
|
||||
|
||||
// TODO(b/24564175): remove
|
||||
private enum RefreshTld { AS_TAG, AS_PARAM }
|
||||
|
||||
private static TaskOptions createRefreshTask(
|
||||
String name, TargetType type, RefreshTld refreshTld) {
|
||||
TaskOptions options = TaskOptions.Builder
|
||||
.withMethod(Method.PULL)
|
||||
.param(DNS_TARGET_TYPE_PARAM, type.toString())
|
||||
.param(DNS_TARGET_NAME_PARAM, name);
|
||||
String tld = InternetDomainName.from(name).parts().reverse().get(0);
|
||||
switch (refreshTld) {
|
||||
case AS_TAG:
|
||||
return options.tag(tld);
|
||||
default:
|
||||
return options.param(PARAM_TLD, tld);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertTldsEnqueuedInPushQueue(String... tlds) throws Exception {
|
||||
assertTasksEnqueued(
|
||||
DNS_PUBLISH_PUSH_QUEUE_NAME,
|
||||
transform(asList(tlds), new Function<String, TaskMatcher>() {
|
||||
@Override
|
||||
public TaskMatcher apply(String tld) {
|
||||
return new TaskMatcher()
|
||||
.url(PublishDnsUpdatesAction.PATH)
|
||||
.param(RequestParameters.PARAM_TLD, tld)
|
||||
.header("content-type", "application/x-www-form-urlencoded");
|
||||
}}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_methodPostIsDefault() throws Exception {
|
||||
dnsQueue.addDomainRefreshTask("domain.com");
|
||||
dnsQueue.addDomainRefreshTask("domain.net");
|
||||
dnsQueue.addDomainRefreshTask("domain.example");
|
||||
run(false);
|
||||
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
assertTasksEnqueued(
|
||||
DNS_PUBLISH_PUSH_QUEUE_NAME,
|
||||
new TaskMatcher().method("POST"),
|
||||
new TaskMatcher().method("POST"),
|
||||
new TaskMatcher().method("POST"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allTlds() throws Exception {
|
||||
dnsQueue.addDomainRefreshTask("domain.com");
|
||||
dnsQueue.addDomainRefreshTask("domain.net");
|
||||
dnsQueue.addDomainRefreshTask("domain.example");
|
||||
run(false);
|
||||
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
assertTldsEnqueuedInPushQueue("com", "net", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allTldsKeepTasks() throws Exception {
|
||||
dnsQueue.addDomainRefreshTask("domain.com");
|
||||
dnsQueue.addDomainRefreshTask("domain.net");
|
||||
dnsQueue.addDomainRefreshTask("domain.example");
|
||||
run(true);
|
||||
assertTasksEnqueued(
|
||||
DnsConstants.DNS_PULL_QUEUE_NAME,
|
||||
new TaskMatcher().tag("com"),
|
||||
new TaskMatcher().tag("net"),
|
||||
new TaskMatcher().tag("example"));
|
||||
assertTldsEnqueuedInPushQueue("com", "net", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allTldsNoTag() throws Exception {
|
||||
dnsQueue.queue.add(createRefreshTask("domain.com", TargetType.DOMAIN, RefreshTld.AS_PARAM));
|
||||
dnsQueue.queue.add(createRefreshTask("domain.net", TargetType.DOMAIN, RefreshTld.AS_PARAM));
|
||||
dnsQueue.queue.add(createRefreshTask("domain.example", TargetType.DOMAIN, RefreshTld.AS_PARAM));
|
||||
run(false);
|
||||
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
assertTldsEnqueuedInPushQueue("com", "net", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_allTldsMixedOldAndNewTldStyles() throws Exception {
|
||||
dnsQueue.addDomainRefreshTask("domain.com");
|
||||
dnsQueue.queue.add(createRefreshTask("domain.net", TargetType.DOMAIN, RefreshTld.AS_PARAM));
|
||||
dnsQueue.queue.add(createRefreshTask("domain.example", TargetType.DOMAIN, RefreshTld.AS_TAG));
|
||||
run(false);
|
||||
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
assertTldsEnqueuedInPushQueue("com", "net", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_oneTldPaused() throws Exception {
|
||||
persistResource(Registry.get("net").asBuilder().setDnsPaused(true).build());
|
||||
dnsQueue.addDomainRefreshTask("domain.com");
|
||||
dnsQueue.addDomainRefreshTask("domain.net");
|
||||
dnsQueue.addDomainRefreshTask("domain.example");
|
||||
run(false);
|
||||
assertTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME, new TaskMatcher().tag("net"));
|
||||
assertTldsEnqueuedInPushQueue("com", "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_zone_getsIgnored() throws Exception {
|
||||
dnsQueue.addHostRefreshTask("ns1.domain.com");
|
||||
dnsQueue.addDomainRefreshTask("domain.net");
|
||||
dnsQueue.addZoneRefreshTask("example");
|
||||
run(false);
|
||||
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
assertTasksEnqueued(DNS_PUBLISH_PUSH_QUEUE_NAME,
|
||||
new TaskMatcher()
|
||||
.url(PublishDnsUpdatesAction.PATH)
|
||||
.param("domains", "domain.net"),
|
||||
new TaskMatcher()
|
||||
.url(PublishDnsUpdatesAction.PATH)
|
||||
.param("hosts", "ns1.domain.com"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_manyDomainsAndHosts() throws Exception {
|
||||
List<TaskMatcher> expectedTasks = new ArrayList<>();
|
||||
for (String tld : ImmutableList.of("com", "net")) {
|
||||
int refreshItemsInTask = 0;
|
||||
TaskMatcher task = null;
|
||||
// 0: domain; 1: host 1; 2: host 2
|
||||
for (int thingType = 0; thingType < 3; thingType++) {
|
||||
for (int i = 0; i < 150; i++) {
|
||||
String domainName = String.format("domain%04d.%s", i, tld);
|
||||
// If we don't have an existing task into which to dump new refreshes, create one.
|
||||
if (task == null) {
|
||||
task = new TaskMatcher().url(PublishDnsUpdatesAction.PATH);
|
||||
expectedTasks.add(task);
|
||||
refreshItemsInTask = 0;
|
||||
}
|
||||
switch (thingType) {
|
||||
default:
|
||||
dnsQueue.addDomainRefreshTask(domainName);
|
||||
task.param("domains", domainName);
|
||||
break;
|
||||
case 1:
|
||||
dnsQueue.queue.add(
|
||||
createRefreshTask("ns1." + domainName, TargetType.HOST, RefreshTld.AS_TAG));
|
||||
task.param("hosts", "ns1." + domainName);
|
||||
break;
|
||||
case 2:
|
||||
dnsQueue.queue.add(
|
||||
createRefreshTask("ns2." + domainName, TargetType.HOST, RefreshTld.AS_PARAM));
|
||||
task.param("hosts", "ns2." + domainName);
|
||||
break;
|
||||
}
|
||||
// If this task is now full up, wash our hands of it, so that we'll start a new one the
|
||||
// next time through the loop.
|
||||
refreshItemsInTask++;
|
||||
if (refreshItemsInTask >= TEST_TLD_UPDATE_BATCH_SIZE) {
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
run(false);
|
||||
assertNoTasksEnqueued(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
assertTasksEnqueued(DNS_PUBLISH_PUSH_QUEUE_NAME, expectedTasks);
|
||||
}
|
||||
}
|
116
javatests/com/google/domain/registry/dns/RefreshDnsTest.java
Normal file
116
javatests/com/google/domain/registry/dns/RefreshDnsTest.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveSubordinateHost;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import com.google.domain.registry.dns.DnsConstants.TargetType;
|
||||
import com.google.domain.registry.model.domain.DomainResource;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
import com.google.domain.registry.request.HttpException.NotFoundException;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RefreshDns}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RefreshDnsTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
private final FakeClock clock = new FakeClock();
|
||||
|
||||
private void run(TargetType type, String name) {
|
||||
RefreshDns refreshDns = new RefreshDns();
|
||||
refreshDns.clock = clock;
|
||||
refreshDns.domainOrHostName = name;
|
||||
refreshDns.type = type;
|
||||
refreshDns.dnsQueue = dnsQueue;
|
||||
refreshDns.run();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
createTld("xn--q9jyb4c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_host() throws Exception {
|
||||
DomainResource domain = persistActiveDomain("example.xn--q9jyb4c");
|
||||
persistActiveSubordinateHost("ns1.example.xn--q9jyb4c", domain);
|
||||
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
|
||||
verify(dnsQueue).addHostRefreshTask("ns1.example.xn--q9jyb4c");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_externalHostNotEnqueued() throws Exception {
|
||||
persistActiveDomain("example.xn--q9jyb4c");
|
||||
persistActiveHost("ns1.example.xn--q9jyb4c");
|
||||
thrown.expect(BadRequestException.class,
|
||||
"ns1.example.xn--q9jyb4c isn't a subordinate hostname");
|
||||
try {
|
||||
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
|
||||
} finally {
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domain() throws Exception {
|
||||
persistActiveDomain("example.xn--q9jyb4c");
|
||||
run(TargetType.DOMAIN, "example.xn--q9jyb4c");
|
||||
verify(dnsQueue).addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unqualifiedName() throws Exception {
|
||||
thrown.expect(BadRequestException.class);
|
||||
run(TargetType.DOMAIN, "example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_hostDoesNotExist() throws Exception {
|
||||
thrown.expect(NotFoundException.class);
|
||||
run(TargetType.HOST, "ns1.example.xn--q9jyb4c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainDoesNotExist() throws Exception {
|
||||
thrown.expect(NotFoundException.class);
|
||||
run(TargetType.DOMAIN, "example.xn--q9jyb4c");
|
||||
}
|
||||
}
|
197
javatests/com/google/domain/registry/dns/WriteDnsTaskTest.java
Normal file
197
javatests/com/google/domain/registry/dns/WriteDnsTaskTest.java
Normal file
|
@ -0,0 +1,197 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.dns;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveSubordinateHost;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoDnsTasksEnqueued;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.clearTaskQueue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
||||
import com.google.domain.registry.dns.writer.api.DnsWriter;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import javax.inject.Provider;
|
||||
|
||||
/** Unit tests for {@link WriteDnsTask}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class WriteDnsTaskTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("1971-01-01TZ"));
|
||||
|
||||
private final DnsWriter dnsWriter = mock(DnsWriter.class);
|
||||
private final DnsQueue dnsQueue = new DnsQueue();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
createTld("xn--q9jyb4c");
|
||||
dnsQueue.queue = QueueFactory.getQueue(DnsConstants.DNS_PULL_QUEUE_NAME);
|
||||
dnsQueue.writeBatchSize = 7;
|
||||
dnsQueue.writeLockTimeout = Duration.standardSeconds(10);
|
||||
}
|
||||
|
||||
private void run(String tld) {
|
||||
WriteDnsTask task = new WriteDnsTask();
|
||||
task.dnsQueue = dnsQueue;
|
||||
task.timeout = Duration.standardSeconds(10);
|
||||
task.tld = tld;
|
||||
task.writerProvider = new Provider<DnsWriter>() {
|
||||
@Override
|
||||
public DnsWriter get() {
|
||||
return dnsWriter;
|
||||
}};
|
||||
task.run();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanUp() throws Exception {
|
||||
clearTaskQueue("dns-pull");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_host() throws Exception {
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example.xn--q9jyb4c", persistActiveDomain("example.xn--q9jyb4c"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addHostRefreshTask("ns1.example.xn--q9jyb4c");
|
||||
assertDnsTasksEnqueued("ns1.example.xn--q9jyb4c");
|
||||
run("xn--q9jyb4c");
|
||||
verify(dnsWriter).publishHost("ns1.example.xn--q9jyb4c");
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domain() throws Exception {
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example.xn--q9jyb4c", persistActiveDomain("example.xn--q9jyb4c"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
assertDnsTasksEnqueued("example.xn--q9jyb4c");
|
||||
run("xn--q9jyb4c");
|
||||
verify(dnsWriter).publishDomain("example.xn--q9jyb4c");
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_zone() throws Exception {
|
||||
dnsQueue.addZoneRefreshTask("xn--q9jyb4c");
|
||||
assertDnsTasksEnqueued("xn--q9jyb4c");
|
||||
run("xn--q9jyb4c");
|
||||
verify(dnsWriter).close();
|
||||
verifyNoMoreInteractions(dnsWriter);
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_dnsPaused() throws Exception {
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example.xn--q9jyb4c", persistActiveDomain("example.xn--q9jyb4c"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
assertDnsTasksEnqueued("example.xn--q9jyb4c");
|
||||
persistResource(Registry.get("xn--q9jyb4c").asBuilder().setDnsPaused(true).build());
|
||||
clock.advanceOneMilli();
|
||||
run("xn--q9jyb4c");
|
||||
verifyZeroInteractions(dnsWriter);
|
||||
assertDnsTasksEnqueued("example.xn--q9jyb4c");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_twoTasksFromTheSameTld() throws Exception {
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example.xn--q9jyb4c", persistActiveDomain("example.xn--q9jyb4c"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example2.xn--q9jyb4c", persistActiveDomain("example2.xn--q9jyb4c"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example2.xn--q9jyb4c");
|
||||
assertDnsTasksEnqueued("example.xn--q9jyb4c", "example2.xn--q9jyb4c");
|
||||
|
||||
run("xn--q9jyb4c");
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_twoTasksInDifferentTlds() throws Exception {
|
||||
// refresh example.xn--q9jyb4c
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example.xn--q9jyb4c", persistActiveDomain("example.xn--q9jyb4c"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
// refresh example.example
|
||||
createTld("example");
|
||||
persistActiveSubordinateHost(
|
||||
"ns1.example.example", persistActiveDomain("example.example"));
|
||||
clock.advanceOneMilli();
|
||||
dnsQueue.addDomainRefreshTask("example.example");
|
||||
// there should now be two tasks enqueued
|
||||
assertDnsTasksEnqueued("example.example", "example.xn--q9jyb4c");
|
||||
// process one, leaving one
|
||||
run("example");
|
||||
assertDnsTasksEnqueued("example.xn--q9jyb4c");
|
||||
// process the other, leaving none
|
||||
run("xn--q9jyb4c");
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainDeleted() throws Exception {
|
||||
dnsQueue.addDomainRefreshTask("example.xn--q9jyb4c");
|
||||
assertDnsTasksEnqueued("example.xn--q9jyb4c");
|
||||
|
||||
run("xn--q9jyb4c");
|
||||
assertNoDnsTasksEnqueued();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
52
javatests/com/google/domain/registry/export/BUILD
Normal file
52
javatests/com/google/domain/registry/export/BUILD
Normal file
|
@ -0,0 +1,52 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
java_library(
|
||||
name = "export",
|
||||
srcs = glob(["*.java"]),
|
||||
resources = glob([
|
||||
"testdata/*",
|
||||
"backup_kinds.txt",
|
||||
]),
|
||||
deps = [
|
||||
"//apiserving/discoverydata/bigquery:bigqueryv2",
|
||||
"//apiserving/discoverydata/drive",
|
||||
"//java/com/google/api/client/http",
|
||||
"//java/com/google/api/client/json",
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/io",
|
||||
"//java/com/google/common/net",
|
||||
"//java/com/google/domain/registry/bigquery",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//java/com/google/domain/registry/export",
|
||||
"//java/com/google/domain/registry/gcs",
|
||||
"//java/com/google/domain/registry/groups",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/request",
|
||||
"//java/com/google/domain/registry/storage/drive",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/appengine:appengine-stubs",
|
||||
"//third_party/java/appengine_gcs_client",
|
||||
"//third_party/java/dagger",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":export"],
|
||||
)
|
|
@ -0,0 +1,224 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assert_;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static java.util.logging.Level.INFO;
|
||||
import static java.util.logging.Level.SEVERE;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.services.bigquery.Bigquery;
|
||||
import com.google.api.services.bigquery.model.ErrorProto;
|
||||
import com.google.api.services.bigquery.model.Job;
|
||||
import com.google.api.services.bigquery.model.JobReference;
|
||||
import com.google.api.services.bigquery.model.JobStatus;
|
||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||
import com.google.appengine.api.taskqueue.dev.QueueStateInfo.TaskStateInfo;
|
||||
import com.google.domain.registry.export.BigqueryPollJobAction.BigqueryPollJobEnqueuer;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
import com.google.domain.registry.request.HttpException.NotModifiedException;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.FakeSleeper;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
import com.google.domain.registry.util.CapturingLogHandler;
|
||||
import com.google.domain.registry.util.Retrier;
|
||||
import com.google.domain.registry.util.TaskEnqueuer;
|
||||
|
||||
import dagger.Lazy;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/** Unit tests for {@link BigqueryPollJobAction}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class BigqueryPollJobActionTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Mock Bigquery bigquery;
|
||||
@Mock Bigquery.Jobs bigqueryJobs;
|
||||
@Mock Bigquery.Jobs.Get bigqueryJobsGet;
|
||||
|
||||
static final String PROJECT_ID = "project_id";
|
||||
static final String JOB_ID = "job_id";
|
||||
static final String CHAINED_QUEUE_NAME = "default";
|
||||
static final TaskEnqueuer ENQUEUER =
|
||||
new TaskEnqueuer(new Retrier(new FakeSleeper(new FakeClock()), 1));
|
||||
|
||||
private final CapturingLogHandler logHandler = new CapturingLogHandler();
|
||||
private BigqueryPollJobAction action = new BigqueryPollJobAction();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
action.bigquery = bigquery;
|
||||
when(bigquery.jobs()).thenReturn(bigqueryJobs);
|
||||
when(bigqueryJobs.get(PROJECT_ID, JOB_ID)).thenReturn(bigqueryJobsGet);
|
||||
action.enqueuer = ENQUEUER;
|
||||
action.projectId = PROJECT_ID;
|
||||
action.jobId = JOB_ID;
|
||||
action.chainedQueueName =
|
||||
new Lazy<String>() {
|
||||
@Override
|
||||
public String get() {
|
||||
return CHAINED_QUEUE_NAME;
|
||||
}};
|
||||
Logger.getLogger(BigqueryPollJobAction.class.getName()).addHandler(logHandler);
|
||||
}
|
||||
|
||||
private static TaskMatcher newPollJobTaskMatcher(String method) throws Exception {
|
||||
return new TaskMatcher()
|
||||
.method(method)
|
||||
.url(BigqueryPollJobAction.PATH)
|
||||
.header(BigqueryPollJobAction.PROJECT_ID_HEADER, PROJECT_ID)
|
||||
.header(BigqueryPollJobAction.JOB_ID_HEADER, JOB_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_enqueuePollTask() throws Exception {
|
||||
new BigqueryPollJobEnqueuer(ENQUEUER).enqueuePollTask(
|
||||
new JobReference().setProjectId(PROJECT_ID).setJobId(JOB_ID));
|
||||
assertTasksEnqueued(BigqueryPollJobAction.QUEUE, newPollJobTaskMatcher("GET"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_enqueuePollTask_withChainedTask() throws Exception {
|
||||
TaskOptions chainedTask = TaskOptions.Builder
|
||||
.withUrl("/_dr/something")
|
||||
.method(Method.POST)
|
||||
.header("X-Testing", "foo")
|
||||
.param("testing", "bar");
|
||||
new BigqueryPollJobEnqueuer(ENQUEUER).enqueuePollTask(
|
||||
new JobReference().setProjectId(PROJECT_ID).setJobId(JOB_ID),
|
||||
chainedTask,
|
||||
QueueFactory.getQueue(CHAINED_QUEUE_NAME));
|
||||
assertTasksEnqueued(BigqueryPollJobAction.QUEUE, newPollJobTaskMatcher("POST"));
|
||||
TaskStateInfo taskInfo = getOnlyElement(
|
||||
TaskQueueHelper.getQueueInfo(BigqueryPollJobAction.QUEUE).getTaskInfo());
|
||||
ByteArrayInputStream taskBodyBytes = new ByteArrayInputStream(taskInfo.getBodyAsBytes());
|
||||
TaskOptions taskOptions = (TaskOptions) new ObjectInputStream(taskBodyBytes).readObject();
|
||||
assertThat(taskOptions).isEqualTo(chainedTask);
|
||||
}
|
||||
|
||||
private void assertLogMessage(Level level, String message) {
|
||||
for (LogRecord logRecord : logHandler.getRecords()) {
|
||||
if (logRecord.getLevel() == level && logRecord.getMessage().contains(message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert_().fail(String.format("Log message \"%s\" not found", message));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_jobCompletedSuccessfully() throws Exception {
|
||||
when(bigqueryJobsGet.execute()).thenReturn(
|
||||
new Job().setStatus(new JobStatus().setState("DONE")));
|
||||
action.run();
|
||||
assertLogMessage(INFO,
|
||||
String.format("Bigquery job succeeded - %s:%s", PROJECT_ID, JOB_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_chainedPayloadAndJobSucceeded_enqueuesChainedTask() throws Exception {
|
||||
when(bigqueryJobsGet.execute()).thenReturn(
|
||||
new Job().setStatus(new JobStatus().setState("DONE")));
|
||||
|
||||
TaskOptions chainedTask = TaskOptions.Builder
|
||||
.withUrl("/_dr/something")
|
||||
.method(Method.POST)
|
||||
.header("X-Testing", "foo")
|
||||
.param("testing", "bar")
|
||||
.taskName("my_task_name");
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
new ObjectOutputStream(bytes).writeObject(chainedTask);
|
||||
action.payload = bytes.toByteArray();
|
||||
|
||||
action.run();
|
||||
assertLogMessage(INFO,
|
||||
String.format("Bigquery job succeeded - %s:%s", PROJECT_ID, JOB_ID));
|
||||
assertLogMessage(INFO,
|
||||
String.format(
|
||||
"Added chained task my_task_name for /_dr/something to queue default:",
|
||||
PROJECT_ID, JOB_ID));
|
||||
assertTasksEnqueued(CHAINED_QUEUE_NAME, new TaskMatcher()
|
||||
.url("/_dr/something")
|
||||
.method("POST")
|
||||
.header("X-Testing", "foo")
|
||||
.param("testing", "bar")
|
||||
.taskName("my_task_name"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobFailed() throws Exception {
|
||||
when(bigqueryJobsGet.execute()).thenReturn(new Job().setStatus(
|
||||
new JobStatus()
|
||||
.setState("DONE")
|
||||
.setErrorResult(new ErrorProto().setMessage("Job failed"))));
|
||||
action.run();
|
||||
assertLogMessage(SEVERE, String.format("Bigquery job failed - %s:%s", PROJECT_ID, JOB_ID));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobPending() throws Exception {
|
||||
when(bigqueryJobsGet.execute()).thenReturn(
|
||||
new Job().setStatus(new JobStatus().setState("PENDING")));
|
||||
thrown.expect(NotModifiedException.class);
|
||||
action.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testJobStatusUnreadable() throws Exception {
|
||||
when(bigqueryJobsGet.execute()).thenThrow(IOException.class);
|
||||
thrown.expect(NotModifiedException.class);
|
||||
action.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badChainedTaskPayload() throws Exception {
|
||||
when(bigqueryJobsGet.execute()).thenReturn(
|
||||
new Job().setStatus(new JobStatus().setState("DONE")));
|
||||
action.payload = "payload".getBytes();
|
||||
thrown.expect(BadRequestException.class, "Cannot deserialize task from payload");
|
||||
action.run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Unit tests for {@link CheckSnapshotServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class CheckSnapshotServletTest {
|
||||
|
||||
static final DateTime START_TIME = DateTime.parse("2014-08-01T01:02:03Z");
|
||||
static final DateTime COMPLETE_TIME = START_TIME.plus(Duration.standardMinutes(30));
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse rsp;
|
||||
|
||||
private DatastoreBackupInfo backupInfo;
|
||||
|
||||
@Mock
|
||||
private DatastoreBackupService backupService;
|
||||
|
||||
@Mock
|
||||
private LoadSnapshotServlet loadSnapshotServlet;
|
||||
|
||||
private final FakeClock clock = new FakeClock(COMPLETE_TIME.plusMillis(1000));
|
||||
private final StringWriter httpOutput = new StringWriter();
|
||||
private final CheckSnapshotServlet servlet = new CheckSnapshotServlet();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
inject.setStaticField(CheckSnapshotServlet.class, "backupService", backupService);
|
||||
inject.setStaticField(CheckSnapshotServlet.class, "loadSnapshotServlet", loadSnapshotServlet);
|
||||
inject.setStaticField(DatastoreBackupInfo.class, "clock", clock);
|
||||
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
||||
|
||||
servlet.init(mock(ServletConfig.class));
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
|
||||
backupInfo = new DatastoreBackupInfo(
|
||||
"some_backup",
|
||||
START_TIME,
|
||||
Optional.of(COMPLETE_TIME),
|
||||
ImmutableSet.of("one", "two", "three"),
|
||||
Optional.of("gs://somebucket/some_backup_20140801.backup_info"));
|
||||
}
|
||||
|
||||
private void setPendingBackup() {
|
||||
backupInfo = new DatastoreBackupInfo(
|
||||
backupInfo.getName(),
|
||||
backupInfo.getStartTime(),
|
||||
Optional.<DateTime>absent(),
|
||||
backupInfo.getKinds(),
|
||||
backupInfo.getGcsFilename());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_enqueuePollTask() throws Exception {
|
||||
servlet.enqueuePollTask("some_snapshot_name", ImmutableSet.of("one", "two", "three"));
|
||||
assertTasksEnqueued(CheckSnapshotServlet.QUEUE,
|
||||
new TaskMatcher()
|
||||
.url(CheckSnapshotServlet.PATH)
|
||||
.param(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM, "some_snapshot_name")
|
||||
.param(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM, "one,two,three")
|
||||
.method("POST"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forPendingBackup_returnsNotModified() throws Exception {
|
||||
setPendingBackup();
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_NOT_MODIFIED, "Datastore backup some_backup still pending");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forStalePendingBackupBackup_returnsAccepted() throws Exception {
|
||||
setPendingBackup();
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
clock.setTo(START_TIME
|
||||
.plus(Duration.standardHours(20))
|
||||
.plus(Duration.standardMinutes(3))
|
||||
.plus(Duration.millis(1234)));
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_ACCEPTED,
|
||||
"Datastore backup some_backup abandoned - "
|
||||
+ "not complete after 20 hours, 3 minutes and 1 second");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forCompleteBackup_enqueuesLoadTask() throws Exception {
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
||||
"20140801_010203",
|
||||
"gs://somebucket/some_backup_20140801.backup_info",
|
||||
ImmutableSet.of("one", "two"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forCompleteAutoBackup_enqueuesLoadTask_usingBackupName() throws Exception {
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM))
|
||||
.thenReturn("auto_snapshot_somestring");
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||
when(backupService.findByName("auto_snapshot_somestring")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
||||
"somestring",
|
||||
"gs://somebucket/some_backup_20140801.backup_info",
|
||||
ImmutableSet.of("one", "two"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forCompleteBackup_missingKindsToLoad_enqueuesLoadTask() throws Exception {
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
||||
"20140801_010203",
|
||||
"gs://somebucket/some_backup_20140801.backup_info",
|
||||
ImmutableSet.of("one", "two", "three"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forCompleteBackup_withExtraKindsToLoad_enqueuesLoadTask() throws Exception {
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,foo");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
||||
"20140801_010203",
|
||||
"gs://somebucket/some_backup_20140801.backup_info",
|
||||
ImmutableSet.of("one"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forCompleteBackup_withEmptyKindsToLoad_skipsLoadTask() throws Exception {
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verifyZeroInteractions(loadSnapshotServlet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_forBadBackup_returnsBadRequest() throws Exception {
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(backupService.findByName("some_backup")).thenThrow(
|
||||
new IllegalArgumentException("No backup found"));
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Bad backup name some_backup: No backup found");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_noBackupSpecified_returnsError() throws Exception {
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: name");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet_returnsInformation() throws Exception {
|
||||
when(req.getMethod()).thenReturn("GET");
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
assertThat(httpOutput.toString()).isEqualTo("OK\n\n" + Joiner.on("\n").join(ImmutableList.of(
|
||||
"Backup name: some_backup",
|
||||
"Status: COMPLETE",
|
||||
"Started: 2014-08-01T01:02:03.000Z",
|
||||
"Ended: 2014-08-01T01:32:03.000Z",
|
||||
"Duration: 30m",
|
||||
"GCS: gs://somebucket/some_backup_20140801.backup_info",
|
||||
"Kinds: [one, two, three]",
|
||||
"")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet_forBadBackup_returnsError() throws Exception {
|
||||
when(req.getMethod()).thenReturn("GET");
|
||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||
when(backupService.findByName("some_backup")).thenThrow(
|
||||
new IllegalArgumentException("No backup found"));
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "No backup found");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGet_noBackupSpecified_returnsError() throws Exception {
|
||||
when(req.getMethod()).thenReturn("GET");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: name");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.appengine.api.datastore.EntityNotFoundException;
|
||||
import com.google.appengine.api.datastore.Text;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.domain.registry.export.DatastoreBackupInfo.BackupStatus;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** Unit tests for {@link DatastoreBackupInfo}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DatastoreBackupInfoTest {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
private FakeClock clock = new FakeClock();
|
||||
|
||||
private DateTime startTime = DateTime.parse("2014-08-01T01:02:03Z");
|
||||
|
||||
private Entity backupEntity; // Can't initialize until AppEngineRule has set up datastore.
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
inject.setStaticField(DatastoreBackupInfo.class, "clock", clock);
|
||||
backupEntity = new Entity("_unused_");
|
||||
backupEntity.setProperty("name", "backup1");
|
||||
backupEntity.setProperty("kinds", ImmutableList.of("one", "two", "three"));
|
||||
backupEntity.setProperty("start_time", new Date(startTime.getMillis()));
|
||||
}
|
||||
|
||||
/** Force a roundtrip to datastore to ensure that we're simulating a freshly fetched entity. */
|
||||
private static Entity persistEntity(Entity entity) throws EntityNotFoundException {
|
||||
return getDatastoreService().get(getDatastoreService().put(entity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_pendingBackup() throws Exception {
|
||||
DatastoreBackupInfo backup = new DatastoreBackupInfo(persistEntity(backupEntity));
|
||||
|
||||
assertThat(backup.getName()).isEqualTo("backup1");
|
||||
assertThat(backup.getKinds()).containsExactly("one", "two", "three");
|
||||
assertThat(backup.getStartTime()).isEqualTo(startTime);
|
||||
assertThat(backup.getCompleteTime()).isAbsent();
|
||||
assertThat(backup.getGcsFilename()).isAbsent();
|
||||
assertThat(backup.getStatus()).isEqualTo(BackupStatus.PENDING);
|
||||
|
||||
clock.setTo(startTime.plusMinutes(1));
|
||||
assertThat(backup.getRunningTime()).isEqualTo(Duration.standardMinutes(1));
|
||||
clock.setTo(startTime.plusMinutes(1).plusSeconds(42));
|
||||
assertThat(backup.getRunningTime()).isEqualTo(Duration.standardSeconds(102));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_completeBackup() throws Exception {
|
||||
DateTime completeTime = startTime.plusMinutes(1).plusSeconds(42);
|
||||
backupEntity.setProperty("complete_time", new Date(completeTime.getMillis()));
|
||||
backupEntity.setProperty("gs_handle", new Text("/gs/somebucket/timestamp.backup_info"));
|
||||
DatastoreBackupInfo backup = new DatastoreBackupInfo(persistEntity(backupEntity));
|
||||
|
||||
assertThat(backup.getName()).isEqualTo("backup1");
|
||||
assertThat(backup.getKinds()).containsExactly("one", "two", "three");
|
||||
assertThat(backup.getStartTime()).isEqualTo(startTime);
|
||||
assertThat(backup.getCompleteTime().get()).isEqualTo(completeTime);
|
||||
assertThat(backup.getGcsFilename()).hasValue("gs://somebucket/timestamp.backup_info");
|
||||
assertThat(backup.getStatus()).isEqualTo(BackupStatus.COMPLETE);
|
||||
assertThat(backup.getRunningTime()).isEqualTo(Duration.standardSeconds(102));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_missingName() throws Exception {
|
||||
thrown.expect(NullPointerException.class);
|
||||
backupEntity.removeProperty("name");
|
||||
new DatastoreBackupInfo(persistEntity(backupEntity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_missingKinds() throws Exception {
|
||||
thrown.expect(NullPointerException.class);
|
||||
backupEntity.removeProperty("kinds");
|
||||
new DatastoreBackupInfo(persistEntity(backupEntity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_missingStartTime() throws Exception {
|
||||
thrown.expect(NullPointerException.class);
|
||||
backupEntity.removeProperty("start_time");
|
||||
new DatastoreBackupInfo(persistEntity(backupEntity));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badGcsFilenameFormat() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
backupEntity.setProperty("gs_handle", new Text("foo"));
|
||||
new DatastoreBackupInfo(persistEntity(backupEntity));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.appengine.api.modules.ModulesService;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/** Unit tests for {@link DatastoreBackupService}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DatastoreBackupServiceTest {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
private ModulesService modulesService;
|
||||
|
||||
private static final DateTime START_TIME = DateTime.parse("2014-08-01T01:02:03Z");
|
||||
|
||||
private final DatastoreBackupService backupService = DatastoreBackupService.get();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
inject.setStaticField(DatastoreBackupService.class, "modulesService", modulesService);
|
||||
when(modulesService.getVersionHostname("default", "ah-builtin-python-bundle"))
|
||||
.thenReturn("ah-builtin-python-bundle.default.localhost");
|
||||
|
||||
persistBackupEntityWithName("backupA1");
|
||||
persistBackupEntityWithName("backupA2");
|
||||
persistBackupEntityWithName("backupA3");
|
||||
persistBackupEntityWithName("backupB1");
|
||||
persistBackupEntityWithName("backupB42");
|
||||
}
|
||||
|
||||
private static void persistBackupEntityWithName(String name) {
|
||||
Entity entity = new Entity(DatastoreBackupService.BACKUP_INFO_KIND);
|
||||
entity.setProperty("name", name);
|
||||
entity.setProperty("kinds", ImmutableList.of("one", "two", "three"));
|
||||
entity.setProperty("start_time", new Date(START_TIME.getMillis()));
|
||||
getDatastoreService().put(entity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_launchBackup() throws Exception {
|
||||
backupService.launchNewBackup(
|
||||
"default", "backup1", "somebucket", ImmutableSet.of("foo", "bar"));
|
||||
assertTasksEnqueued("default",
|
||||
new TaskMatcher()
|
||||
.url("/_ah/datastore_admin/backup.create")
|
||||
.header("Host", "ah-builtin-python-bundle.default.localhost")
|
||||
.method("GET")
|
||||
.param("name", "backup1_")
|
||||
.param("filesystem", "gs")
|
||||
.param("gs_bucket_name", "somebucket")
|
||||
.param("queue", "default")
|
||||
.param("run_as_a_service", "true")
|
||||
.param("kind", "foo")
|
||||
.param("kind", "bar"));
|
||||
}
|
||||
|
||||
private static final Function<DatastoreBackupInfo, String> BACKUP_NAME_GETTER =
|
||||
new Function<DatastoreBackupInfo, String>() {
|
||||
@Override
|
||||
public String apply(DatastoreBackupInfo backup) {
|
||||
return backup.getName();
|
||||
}};
|
||||
|
||||
@Test
|
||||
public void testSuccess_findAllByNamePrefix() throws Exception {
|
||||
assertThat(transform(backupService.findAllByNamePrefix("backupA"), BACKUP_NAME_GETTER))
|
||||
.containsExactly("backupA1", "backupA2", "backupA3");
|
||||
assertThat(transform(backupService.findAllByNamePrefix("backupB"), BACKUP_NAME_GETTER))
|
||||
.containsExactly("backupB1", "backupB42");
|
||||
assertThat(transform(backupService.findAllByNamePrefix("backupB4"), BACKUP_NAME_GETTER))
|
||||
.containsExactly("backupB42");
|
||||
assertThat(backupService.findAllByNamePrefix("backupX")).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_findByName() throws Exception {
|
||||
assertThat(BACKUP_NAME_GETTER.apply(backupService.findByName("backupA1")))
|
||||
.isEqualTo("backupA1");
|
||||
assertThat(BACKUP_NAME_GETTER.apply(backupService.findByName("backupB4")))
|
||||
.isEqualTo("backupB42");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_findByName_multipleMatchingBackups() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
backupService.findByName("backupA");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_findByName_noMatchingBackups() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
backupService.findByName("backupX");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.io.Resources.getResource;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.io.Resources;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
/** Unit tests for {@link ExportConstants}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ExportConstantsTest {
|
||||
|
||||
private static final String GOLDEN_BACKUP_KINDS_FILENAME = "backup_kinds.txt";
|
||||
|
||||
private static final String UPDATE_INSTRUCTIONS_TEMPLATE = Joiner.on('\n').join(
|
||||
"",
|
||||
"---------------------------------------------------------------------------------",
|
||||
"Your changes affect the list of backed-up kinds in the golden file:",
|
||||
" %s",
|
||||
"If these changes are desired, update the golden file with the following contents:",
|
||||
"=================================================================================",
|
||||
"%s",
|
||||
"=================================================================================",
|
||||
"");
|
||||
|
||||
@Test
|
||||
public void testBackupKinds_matchGoldenBackupKindsFile() throws Exception {
|
||||
URL goldenBackupKindsResource =
|
||||
getResource(ExportConstantsTest.class, GOLDEN_BACKUP_KINDS_FILENAME);
|
||||
List<String> goldenKinds = Splitter.on('\n').splitToList(
|
||||
Resources.toString(goldenBackupKindsResource, UTF_8).trim());
|
||||
ImmutableSet<String> actualKinds = ExportConstants.getBackupKinds();
|
||||
String updateInstructions = String.format(
|
||||
UPDATE_INSTRUCTIONS_TEMPLATE,
|
||||
goldenBackupKindsResource.toString(),
|
||||
Joiner.on('\n').join(actualKinds));
|
||||
assertWithMessage(updateInstructions)
|
||||
.that(actualKinds)
|
||||
.containsExactlyElementsIn(goldenKinds)
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportingKinds_areSubsetOfBackupKinds() throws Exception {
|
||||
assertThat(ExportConstants.getBackupKinds()).containsAllIn(ExportConstants.getReportingKinds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReportingEntityClasses_areAllBaseEntityClasses() throws Exception {
|
||||
for (Class<? extends ImmutableObject> clazz : ExportConstants.REPORTING_ENTITY_CLASSES) {
|
||||
assertThat(clazz.isAnnotationPresent(Entity.class))
|
||||
.named(String.format("class %s is an @Entity", clazz.getSimpleName()))
|
||||
.isTrue();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.domain.registry.export.ExportReservedTermsTask.EXPORT_MIME_TYPE;
|
||||
import static com.google.domain.registry.export.ExportReservedTermsTask.RESERVED_TERMS_FILENAME;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistReservedList;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.registry.Registry.RegistryNotFoundException;
|
||||
import com.google.domain.registry.model.registry.label.ReservedList;
|
||||
import com.google.domain.registry.request.Response;
|
||||
import com.google.domain.registry.storage.drive.DriveConnection;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/** Unit tests for {@link ExportReservedTermsTask}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ExportReservedTermsTaskTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Mock
|
||||
private DriveConnection driveConnection;
|
||||
|
||||
@Mock
|
||||
private Response response;
|
||||
|
||||
private void runTask(String tld) {
|
||||
ExportReservedTermsTask task = new ExportReservedTermsTask();
|
||||
task.response = response;
|
||||
task.driveConnection = driveConnection;
|
||||
task.tld = tld;
|
||||
task.run();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
ReservedList rl = persistReservedList(
|
||||
"tld-reserved",
|
||||
"lol,FULLY_BLOCKED",
|
||||
"cat,FULLY_BLOCKED",
|
||||
"jimmy,UNRESERVED");
|
||||
createTld("tld");
|
||||
persistResource(Registry.get("tld").asBuilder()
|
||||
.setReservedLists(rl)
|
||||
.setDriveFolderId("brouhaha").build());
|
||||
when(driveConnection.createOrUpdateFile(
|
||||
anyString(),
|
||||
any(MediaType.class),
|
||||
anyString(),
|
||||
any(byte[].class))).thenReturn("1001");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uploadFileToDrive_succeeds() throws Exception {
|
||||
runTask("tld");
|
||||
byte[] expected =
|
||||
("This is a disclaimer.\ncat\nlol\n")
|
||||
.getBytes(UTF_8);
|
||||
verify(driveConnection)
|
||||
.createOrUpdateFile(RESERVED_TERMS_FILENAME, EXPORT_MIME_TYPE, "brouhaha", expected);
|
||||
verify(response).setStatus(SC_OK);
|
||||
verify(response).setPayload("1001");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uploadFileToDrive_doesNothingIfReservedListsNotConfigured() throws Exception {
|
||||
persistResource(Registry.get("tld").asBuilder()
|
||||
.setReservedLists(ImmutableSet.<ReservedList>of())
|
||||
.setDriveFolderId(null)
|
||||
.build());
|
||||
runTask("tld");
|
||||
verify(response).setStatus(SC_OK);
|
||||
verify(response).setPayload("No reserved lists configured");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uploadFileToDrive_failsWhenDriveFolderIdIsNull() throws Exception {
|
||||
thrown.expectRootCause(NullPointerException.class, "No drive folder associated with this TLD");
|
||||
persistResource(Registry.get("tld").asBuilder().setDriveFolderId(null).build());
|
||||
runTask("tld");
|
||||
verify(response).setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uploadFileToDrive_failsWhenDriveCannotBeReached() throws Exception {
|
||||
thrown.expectRootCause(IOException.class, "errorMessage");
|
||||
when(driveConnection.createOrUpdateFile(
|
||||
anyString(),
|
||||
any(MediaType.class),
|
||||
anyString(),
|
||||
any(byte[].class))).thenThrow(new IOException("errorMessage"));
|
||||
runTask("tld");
|
||||
verify(response).setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_uploadFileToDrive_failsWhenTldDoesntExist() throws Exception {
|
||||
thrown.expectRootCause(
|
||||
RegistryNotFoundException.class, "No registry object found for fakeTld");
|
||||
runTask("fakeTld");
|
||||
verify(response).setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Unit tests for {@link ExportSnapshotServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ExportSnapshotServletTest {
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule(new TestRegistryConfig() {
|
||||
@Override public String getSnapshotsBucket() {
|
||||
return "Bucket-Id";
|
||||
}});
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse rsp;
|
||||
|
||||
@Mock
|
||||
private DatastoreBackupService backupService;
|
||||
|
||||
@Mock
|
||||
private CheckSnapshotServlet checkSnapshotServlet;
|
||||
|
||||
private final FakeClock clock = new FakeClock();
|
||||
private final StringWriter httpOutput = new StringWriter();
|
||||
private final ExportSnapshotServlet servlet = new ExportSnapshotServlet();
|
||||
|
||||
private static final DateTime START_TIME = DateTime.parse("2014-08-01T01:02:03Z");
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
clock.setTo(START_TIME);
|
||||
inject.setStaticField(ExportSnapshotServlet.class, "clock", clock);
|
||||
inject.setStaticField(ExportSnapshotServlet.class, "backupService", backupService);
|
||||
inject.setStaticField(
|
||||
ExportSnapshotServlet.class, "checkSnapshotServlet", checkSnapshotServlet);
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
||||
|
||||
servlet.init(mock(ServletConfig.class));
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_launchesBackup_andEnqueuesPollTask() throws Exception {
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
verify(backupService).launchNewBackup(
|
||||
ExportSnapshotServlet.QUEUE,
|
||||
"auto_snapshot_20140801_010203",
|
||||
"Bucket-Id",
|
||||
ExportConstants.getBackupKinds());
|
||||
verify(checkSnapshotServlet)
|
||||
.enqueuePollTask("auto_snapshot_20140801_010203", ExportConstants.getReportingKinds());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistReservedList;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.registry.label.ReservedList;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link ExportUtils}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ExportUtilsTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void test_exportReservedTerms() {
|
||||
ReservedList rl1 = persistReservedList(
|
||||
"tld-reserved1",
|
||||
"lol,FULLY_BLOCKED",
|
||||
"cat,FULLY_BLOCKED",
|
||||
"jimmy,UNRESERVED");
|
||||
ReservedList rl2 = persistReservedList(
|
||||
"tld-reserved2",
|
||||
"lol,NAME_COLLISION",
|
||||
"cat,UNRESERVED",
|
||||
"snow,FULLY_BLOCKED");
|
||||
ReservedList rl3 = persistReservedList(
|
||||
"tld-reserved3",
|
||||
false,
|
||||
"tine,FULLY_BLOCKED",
|
||||
"oval,UNRESERVED");
|
||||
createTld("tld");
|
||||
persistResource(Registry.get("tld").asBuilder().setReservedLists(rl1, rl2, rl3).build());
|
||||
// Should not contain jimmy, tine, or oval.
|
||||
assertThat(ExportUtils.exportReservedTerms(Registry.get("tld")))
|
||||
.isEqualTo("This is a disclaimer.\ncat\nlol\nsnow\n");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,294 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.collect.Iterables.transform;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.http.HttpRequestInitializer;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.services.bigquery.Bigquery;
|
||||
import com.google.api.services.bigquery.model.Dataset;
|
||||
import com.google.api.services.bigquery.model.Job;
|
||||
import com.google.api.services.bigquery.model.JobConfigurationLoad;
|
||||
import com.google.api.services.bigquery.model.JobReference;
|
||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.domain.registry.bigquery.BigqueryFactory;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.export.BigqueryPollJobAction.BigqueryPollJobEnqueuer;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Unit tests for {@link LoadSnapshotServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class LoadSnapshotServletTest {
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule(new TestRegistryConfig() {
|
||||
@Override public String getProjectId() {
|
||||
return "Project-Id";
|
||||
}
|
||||
|
||||
@Override public String getSnapshotsDataset() {
|
||||
return "testdataset";
|
||||
}
|
||||
});
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse rsp;
|
||||
|
||||
@Mock
|
||||
private BigqueryFactory bigqueryFactory;
|
||||
|
||||
@Mock
|
||||
private Bigquery bigquery;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Jobs bigqueryJobs;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Jobs.Insert bigqueryJobsInsert;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Datasets bigqueryDatasets;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Datasets.Insert bigqueryDatasetsInsert;
|
||||
|
||||
@Mock
|
||||
private BigqueryPollJobEnqueuer bigqueryPollEnqueuer;
|
||||
|
||||
private static final DateTime NOW = new DateTime(1391096117045L, UTC);
|
||||
|
||||
private FakeClock clock = new FakeClock();
|
||||
private final StringWriter httpOutput = new StringWriter();
|
||||
private final LoadSnapshotServlet servlet = new LoadSnapshotServlet();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
clock.setTo(NOW);
|
||||
inject.setStaticField(LoadSnapshotServlet.class, "clock", clock);
|
||||
inject.setStaticField(LoadSnapshotServlet.class, "bigqueryFactory", bigqueryFactory);
|
||||
inject.setStaticField(LoadSnapshotServlet.class, "bigqueryPollEnqueuer", bigqueryPollEnqueuer);
|
||||
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
||||
|
||||
when(bigqueryFactory.create(
|
||||
anyString(),
|
||||
any(HttpTransport.class),
|
||||
any(JsonFactory.class),
|
||||
any(HttpRequestInitializer.class)))
|
||||
.thenReturn(bigquery);
|
||||
|
||||
when(bigquery.jobs()).thenReturn(bigqueryJobs);
|
||||
when(bigqueryJobs.insert(eq("Project-Id"), any(Job.class))).thenReturn(bigqueryJobsInsert);
|
||||
|
||||
when(bigquery.datasets()).thenReturn(bigqueryDatasets);
|
||||
when(bigqueryDatasets.insert(eq("Project-Id"), any(Dataset.class)))
|
||||
.thenReturn(bigqueryDatasetsInsert);
|
||||
|
||||
servlet.init(mock(ServletConfig.class));
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_enqueueLoadTask() throws Exception {
|
||||
servlet.enqueueLoadTask(
|
||||
"id12345", "gs://bucket/snapshot.backup_info", ImmutableSet.of("one", "two", "three"));
|
||||
assertTasksEnqueued(LoadSnapshotServlet.QUEUE,
|
||||
new TaskMatcher()
|
||||
.url(LoadSnapshotServlet.PATH)
|
||||
.method("POST")
|
||||
.param(LoadSnapshotServlet.SNAPSHOT_ID_PARAM, "id12345")
|
||||
.param(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM, "gs://bucket/snapshot.backup_info")
|
||||
.param(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM, "one,two,three"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_doPost() throws Exception {
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
||||
.thenReturn("gs://bucket/snapshot.backup_info");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
||||
.thenReturn("one,two,three");
|
||||
|
||||
servlet.service(req, rsp);
|
||||
|
||||
// Check that we attempted to create the snapshots dataset.
|
||||
ArgumentCaptor<Dataset> datasetArgument = ArgumentCaptor.forClass(Dataset.class);
|
||||
verify(bigqueryDatasets).insert(eq("Project-Id"), datasetArgument.capture());
|
||||
assertThat(datasetArgument.getValue().getDatasetReference().getProjectId())
|
||||
.isEqualTo("Project-Id");
|
||||
assertThat(datasetArgument.getValue().getDatasetReference().getDatasetId())
|
||||
.isEqualTo("testdataset");
|
||||
verify(bigqueryDatasetsInsert).execute();
|
||||
|
||||
// Capture the load jobs we inserted to do additional checking on them.
|
||||
ArgumentCaptor<Job> jobArgument = ArgumentCaptor.forClass(Job.class);
|
||||
verify(bigqueryJobs, times(3)).insert(eq("Project-Id"), jobArgument.capture());
|
||||
List<Job> jobs = jobArgument.getAllValues();
|
||||
assertThat(jobs).hasSize(3);
|
||||
|
||||
// Check properties that should be common to all load jobs.
|
||||
for (Job job : jobs) {
|
||||
assertThat(job.getJobReference().getProjectId()).isEqualTo("Project-Id");
|
||||
JobConfigurationLoad config = job.getConfiguration().getLoad();
|
||||
assertThat(config.getSourceFormat()).isEqualTo("DATASTORE_BACKUP");
|
||||
assertThat(config.getDestinationTable().getProjectId()).isEqualTo("Project-Id");
|
||||
assertThat(config.getDestinationTable().getDatasetId()).isEqualTo("testdataset");
|
||||
}
|
||||
|
||||
// Check the job IDs for each load job.
|
||||
assertThat(transform(jobs, new Function<Job, String>() {
|
||||
@Override
|
||||
public String apply(Job job) {
|
||||
return job.getJobReference().getJobId();
|
||||
}})).containsExactly(
|
||||
"load-snapshot-id12345-one-1391096117045",
|
||||
"load-snapshot-id12345-two-1391096117045",
|
||||
"load-snapshot-id12345-three-1391096117045");
|
||||
|
||||
// Check the source URI for each load job.
|
||||
assertThat(transform(jobs, new Function<Job, String>() {
|
||||
@Override
|
||||
public String apply(Job job) {
|
||||
return Iterables.getOnlyElement(job.getConfiguration().getLoad().getSourceUris());
|
||||
}})).containsExactly(
|
||||
"gs://bucket/snapshot.one.backup_info",
|
||||
"gs://bucket/snapshot.two.backup_info",
|
||||
"gs://bucket/snapshot.three.backup_info");
|
||||
|
||||
// Check the destination table ID for each load job.
|
||||
assertThat(transform(jobs, new Function<Job, String>() {
|
||||
@Override
|
||||
public String apply(Job job) {
|
||||
return job.getConfiguration().getLoad().getDestinationTable().getTableId();
|
||||
}})).containsExactly("id12345_one", "id12345_two", "id12345_three");
|
||||
|
||||
// Check that we executed the inserted jobs.
|
||||
verify(bigqueryJobsInsert, times(3)).execute();
|
||||
|
||||
// Check that the poll tasks for each load job were enqueued.
|
||||
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
||||
new JobReference()
|
||||
.setProjectId("Project-Id")
|
||||
.setJobId("load-snapshot-id12345-one-1391096117045"),
|
||||
UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_one", "one"),
|
||||
QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE));
|
||||
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
||||
new JobReference()
|
||||
.setProjectId("Project-Id")
|
||||
.setJobId("load-snapshot-id12345-two-1391096117045"),
|
||||
UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_two", "two"),
|
||||
QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE));
|
||||
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
||||
new JobReference()
|
||||
.setProjectId("Project-Id")
|
||||
.setJobId("load-snapshot-id12345-three-1391096117045"),
|
||||
UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_three", "three"),
|
||||
QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE));
|
||||
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_missingIdHeader() throws Exception {
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
||||
.thenReturn("gs://bucket/snapshot.backup_info");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
||||
.thenReturn("one,two,three");
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: id");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_missingFileHeader() throws Exception {
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
||||
.thenReturn("one,two,three");
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: file");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_missingKindHeader() throws Exception {
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
||||
.thenReturn("gs://bucket/snapshot.backup_info");
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: kinds");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_badGcsFilename() throws Exception {
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
||||
.thenReturn("gs://bucket/snapshot");
|
||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
||||
.thenReturn("one,two,three");
|
||||
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "backup info file extension missing");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.export.PublishDetailReportAction.DETAIL_REPORT_NAME_PARAM;
|
||||
import static com.google.domain.registry.export.PublishDetailReportAction.GCS_BUCKET_PARAM;
|
||||
import static com.google.domain.registry.export.PublishDetailReportAction.GCS_FOLDER_PREFIX_PARAM;
|
||||
import static com.google.domain.registry.export.PublishDetailReportAction.REGISTRAR_ID_PARAM;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.tools.cloudstorage.GcsFileOptions;
|
||||
import com.google.appengine.tools.cloudstorage.GcsFilename;
|
||||
import com.google.appengine.tools.cloudstorage.GcsService;
|
||||
import com.google.appengine.tools.cloudstorage.GcsServiceFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.net.MediaType;
|
||||
import com.google.domain.registry.gcs.GcsUtils;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
||||
import com.google.domain.registry.storage.drive.DriveConnection;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
|
||||
/** Unit tests for {@link PublishDetailReportAction}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class PublishDetailReportActionTest {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Mock
|
||||
private DriveConnection driveConnection;
|
||||
|
||||
private final PublishDetailReportAction action = new PublishDetailReportAction();
|
||||
private final GcsService gcsService = GcsServiceFactory.createGcsService();
|
||||
private final GcsUtils gcsUtils = new GcsUtils(gcsService, 1024);
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
action.driveConnection = driveConnection;
|
||||
action.gcsUtils = gcsUtils;
|
||||
|
||||
when(driveConnection.createFile(
|
||||
anyString(), any(MediaType.class), anyString(), any(byte[].class)))
|
||||
.thenReturn("drive-id-123");
|
||||
|
||||
persistResource(
|
||||
Registrar.loadByClientId("TheRegistrar").asBuilder().setDriveFolderId("0B-12345").build());
|
||||
|
||||
// Persist an empty GCS file to the local GCS service so that failure tests won't fail
|
||||
// prematurely on the file not existing.
|
||||
gcsService.createOrReplace(
|
||||
new GcsFilename("mah-buckit", "some/folder/detail_report.csv"),
|
||||
GcsFileOptions.getDefaultInstance(),
|
||||
ByteBuffer.allocate(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
// Create a dummy file in the local GCS service to read in the servlet.
|
||||
gcsService.createOrReplace(
|
||||
new GcsFilename("mah-buckit", "some/folder/detail_report.csv"),
|
||||
GcsFileOptions.getDefaultInstance(),
|
||||
ByteBuffer.wrap("one,two,three\n".getBytes(UTF_8)));
|
||||
|
||||
Map<String, Object> response =
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
|
||||
verify(driveConnection).createFile(
|
||||
"detail_report.csv", MediaType.CSV_UTF_8, "0B-12345", "one,two,three\n".getBytes(UTF_8));
|
||||
assertThat(response).containsEntry("driveId", "drive-id-123");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noRegistrarParameter() throws Exception {
|
||||
thrown.expect(BadRequestException.class, REGISTRAR_ID_PARAM);
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noGcsBucketParameter() throws Exception {
|
||||
thrown.expect(BadRequestException.class, GCS_BUCKET_PARAM);
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noGcsFolderPrefixParameter() throws Exception {
|
||||
thrown.expect(BadRequestException.class, GCS_FOLDER_PREFIX_PARAM);
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noReportNameParameter() throws Exception {
|
||||
thrown.expect(BadRequestException.class, DETAIL_REPORT_NAME_PARAM);
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_registrarNotFound() throws Exception {
|
||||
thrown.expect(BadRequestException.class, "FakeRegistrar");
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "FakeRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_registrarHasNoDriveFolder() throws Exception {
|
||||
persistResource(
|
||||
Registrar.loadByClientId("TheRegistrar").asBuilder().setDriveFolderId(null).build());
|
||||
thrown.expect(BadRequestException.class, "drive folder");
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_gcsBucketNotFound() throws Exception {
|
||||
thrown.expect(BadRequestException.class, "fake-buckit");
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "fake-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_gcsFileNotFound() throws Exception {
|
||||
thrown.expect(BadRequestException.class, "some/folder/fake_file.csv");
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "fake_file.csv"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_driveApiThrowsException() throws Exception {
|
||||
when(driveConnection.createFile(
|
||||
anyString(), any(MediaType.class), anyString(), any(byte[].class)))
|
||||
.thenThrow(new IOException("Drive is down"));
|
||||
thrown.expect(InternalServerErrorException.class, "Drive is down");
|
||||
action.handleJsonRequest(ImmutableMap.of(
|
||||
REGISTRAR_ID_PARAM, "TheRegistrar",
|
||||
GCS_BUCKET_PARAM, "mah-buckit",
|
||||
GCS_FOLDER_PREFIX_PARAM, "some/folder/",
|
||||
DETAIL_REPORT_NAME_PARAM, "detail_report.csv"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,224 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.export.SyncGroupMembersTask.getGroupEmailAddressForContactType;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.model.registrar.RegistrarContact.Type.ADMIN;
|
||||
import static com.google.domain.registry.model.registrar.RegistrarContact.Type.MARKETING;
|
||||
import static com.google.domain.registry.model.registrar.RegistrarContact.Type.TECH;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.domain.registry.groups.DirectoryGroupsConnection;
|
||||
import com.google.domain.registry.groups.GroupsConnection.Role;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarContact;
|
||||
import com.google.domain.registry.request.Response;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SyncGroupMembersTask}.
|
||||
*
|
||||
* <p>Note that this relies on the registrars NewRegistrar and TheRegistrar created by default in
|
||||
* {@link AppEngineRule}.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SyncGroupMembersTaskTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Mock
|
||||
private DirectoryGroupsConnection connection;
|
||||
|
||||
@Mock
|
||||
private Response response;
|
||||
|
||||
private void runTask() {
|
||||
SyncGroupMembersTask task = new SyncGroupMembersTask();
|
||||
task.groupsConnection = connection;
|
||||
task.response = response;
|
||||
task.publicDomainName = "domain-registry.example";
|
||||
task.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getGroupEmailAddressForContactType_convertsToLowercase() {
|
||||
assertThat(getGroupEmailAddressForContactType(
|
||||
"SomeRegistrar",
|
||||
RegistrarContact.Type.ADMIN,
|
||||
"domain-registry.example"))
|
||||
.isEqualTo("someregistrar-primary-contacts@domain-registry.example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getGroupEmailAddressForContactType_convertsNonAlphanumericChars() {
|
||||
assertThat(getGroupEmailAddressForContactType(
|
||||
"Weird.ಠ_ಠRegistrar",
|
||||
MARKETING,
|
||||
"domain-registry.example"))
|
||||
.isEqualTo("weirdregistrar-marketing-contacts@domain-registry.example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doPost_noneModified() throws Exception {
|
||||
persistResource(Registrar.loadByClientId("NewRegistrar")
|
||||
.asBuilder()
|
||||
.setContactsRequireSyncing(false)
|
||||
.build());
|
||||
persistResource(Registrar.loadByClientId("TheRegistrar")
|
||||
.asBuilder()
|
||||
.setContactsRequireSyncing(false)
|
||||
.build());
|
||||
runTask();
|
||||
verify(response).setStatus(SC_OK);
|
||||
verify(response).setPayload("NOT_MODIFIED No registrar contacts have been updated "
|
||||
+ "since the last time servlet ran.\n");
|
||||
assertThat(Registrar.loadByClientId("NewRegistrar").getContactsRequireSyncing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doPost_syncsNewContact() throws Exception {
|
||||
runTask();
|
||||
verify(connection).addMemberToGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example",
|
||||
"janedoe@theregistrar.com",
|
||||
Role.MEMBER);
|
||||
verify(response).setStatus(SC_OK);
|
||||
verify(response).setPayload("OK Group memberships successfully updated.\n");
|
||||
assertThat(Registrar.loadByClientId("NewRegistrar").getContactsRequireSyncing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doPost_removesOldContact() throws Exception {
|
||||
when(connection.getMembersOfGroup("newregistrar-primary-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.of("defunct@example.com", "janedoe@theregistrar.com"));
|
||||
runTask();
|
||||
verify(connection).removeMemberFromGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example", "defunct@example.com");
|
||||
verify(response).setStatus(SC_OK);
|
||||
assertThat(Registrar.loadByClientId("NewRegistrar").getContactsRequireSyncing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doPost_removesAllContactsFromGroup() throws Exception {
|
||||
when(connection.getMembersOfGroup("newregistrar-primary-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.of("defunct@example.com", "janedoe@theregistrar.com"));
|
||||
ofy().deleteWithoutBackup()
|
||||
.entities(Registrar.loadByClientId("NewRegistrar").getContacts())
|
||||
.now();
|
||||
runTask();
|
||||
verify(connection).removeMemberFromGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example", "defunct@example.com");
|
||||
verify(connection).removeMemberFromGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example", "janedoe@theregistrar.com");
|
||||
verify(response).setStatus(SC_OK);
|
||||
assertThat(Registrar.loadByClientId("NewRegistrar").getContactsRequireSyncing()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doPost_addsAndRemovesContacts_acrossMultipleRegistrars() throws Exception {
|
||||
when(connection.getMembersOfGroup("newregistrar-primary-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.of("defunct@example.com", "janedoe@theregistrar.com"));
|
||||
when(connection.getMembersOfGroup("newregistrar-marketing-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.<String> of());
|
||||
when(connection.getMembersOfGroup("theregistrar-technical-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.<String> of());
|
||||
when(connection.getMembersOfGroup("theregistrar-primary-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.<String> of());
|
||||
persistResource(
|
||||
new RegistrarContact.Builder()
|
||||
.setParent(Registrar.loadByClientId("NewRegistrar"))
|
||||
.setName("Binary Star")
|
||||
.setEmailAddress("binarystar@example.tld")
|
||||
.setTypes(ImmutableSet.of(ADMIN, MARKETING))
|
||||
.build());
|
||||
persistResource(
|
||||
new RegistrarContact.Builder()
|
||||
.setParent(Registrar.loadByClientId("TheRegistrar"))
|
||||
.setName("Hexadecimal")
|
||||
.setEmailAddress("hexadecimal@snow.fall")
|
||||
.setTypes(ImmutableSet.of(TECH))
|
||||
.build());
|
||||
runTask();
|
||||
verify(connection).removeMemberFromGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example", "defunct@example.com");
|
||||
verify(connection).addMemberToGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example",
|
||||
"binarystar@example.tld",
|
||||
Role.MEMBER);
|
||||
verify(connection).addMemberToGroup(
|
||||
"newregistrar-marketing-contacts@domain-registry.example",
|
||||
"binarystar@example.tld",
|
||||
Role.MEMBER);
|
||||
verify(connection).addMemberToGroup(
|
||||
"theregistrar-primary-contacts@domain-registry.example",
|
||||
"johndoe@theregistrar.com",
|
||||
Role.MEMBER);
|
||||
verify(connection).addMemberToGroup(
|
||||
"theregistrar-technical-contacts@domain-registry.example",
|
||||
"hexadecimal@snow.fall",
|
||||
Role.MEMBER);
|
||||
verify(response).setStatus(SC_OK);
|
||||
assertThat(Iterables.filter(Registrar.loadAll(), new Predicate<Registrar>() {
|
||||
@Override
|
||||
public boolean apply(Registrar registrar) {
|
||||
return registrar.getContactsRequireSyncing();
|
||||
}})).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doPost_gracefullyHandlesExceptionForSingleRegistrar() throws Exception {
|
||||
when(connection.getMembersOfGroup("newregistrar-primary-contacts@domain-registry.example"))
|
||||
.thenReturn(ImmutableSet.<String> of());
|
||||
when(connection.getMembersOfGroup("theregistrar-primary-contacts@domain-registry.example"))
|
||||
.thenThrow(new IOException("Internet was deleted"));
|
||||
runTask();
|
||||
verify(connection).addMemberToGroup(
|
||||
"newregistrar-primary-contacts@domain-registry.example",
|
||||
"janedoe@theregistrar.com",
|
||||
Role.MEMBER);
|
||||
verify(response).setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
verify(response).setPayload("FAILED Error occurred while updating registrar contacts.\n");
|
||||
assertThat(Registrar.loadByClientId("NewRegistrar").getContactsRequireSyncing()).isFalse();
|
||||
assertThat(Registrar.loadByClientId("TheRegistrar").getContactsRequireSyncing()).isTrue();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,203 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.api.client.http.HttpRequestInitializer;
|
||||
import com.google.api.client.http.HttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.services.bigquery.Bigquery;
|
||||
import com.google.api.services.bigquery.model.Dataset;
|
||||
import com.google.api.services.bigquery.model.Table;
|
||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
||||
import com.google.domain.registry.bigquery.BigqueryFactory;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/** Unit tests for {@link UpdateSnapshotViewServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class UpdateSnapshotViewServletTest {
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule(new TestRegistryConfig() {
|
||||
@Override public String getProjectId() {
|
||||
return "Project-Id";
|
||||
}
|
||||
|
||||
@Override public String getLatestSnapshotDataset() {
|
||||
return "testdataset";
|
||||
}
|
||||
});
|
||||
|
||||
@Mock
|
||||
private HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
private HttpServletResponse rsp;
|
||||
|
||||
@Mock
|
||||
private BigqueryFactory bigqueryFactory;
|
||||
|
||||
@Mock
|
||||
private Bigquery bigquery;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Datasets bigqueryDatasets;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Datasets.Insert bigqueryDatasetsInsert;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Tables bigqueryTables;
|
||||
|
||||
@Mock
|
||||
private Bigquery.Tables.Update bigqueryTablesUpdate;
|
||||
|
||||
private final StringWriter httpOutput = new StringWriter();
|
||||
private final UpdateSnapshotViewServlet servlet = new UpdateSnapshotViewServlet();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
inject.setStaticField(UpdateSnapshotViewServlet.class, "bigqueryFactory", bigqueryFactory);
|
||||
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
||||
|
||||
when(bigqueryFactory.create(
|
||||
anyString(),
|
||||
any(HttpTransport.class),
|
||||
any(JsonFactory.class),
|
||||
any(HttpRequestInitializer.class)))
|
||||
.thenReturn(bigquery);
|
||||
|
||||
when(bigquery.datasets()).thenReturn(bigqueryDatasets);
|
||||
when(bigqueryDatasets.insert(eq("Project-Id"), any(Dataset.class)))
|
||||
.thenReturn(bigqueryDatasetsInsert);
|
||||
|
||||
when(bigquery.tables()).thenReturn(bigqueryTables);
|
||||
when(bigqueryTables.update(
|
||||
eq("Project-Id"), any(String.class), any(String.class), any(Table.class)))
|
||||
.thenReturn(bigqueryTablesUpdate);
|
||||
|
||||
servlet.init(mock(ServletConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_createViewUpdateTask() throws Exception {
|
||||
QueueFactory.getDefaultQueue().add(
|
||||
UpdateSnapshotViewServlet.createViewUpdateTask("some_dataset", "12345_fookind", "fookind"));
|
||||
assertTasksEnqueued("default",
|
||||
new TaskMatcher()
|
||||
.url(UpdateSnapshotViewServlet.PATH)
|
||||
.method("POST")
|
||||
.param(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM, "some_dataset")
|
||||
.param(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM, "12345_fookind")
|
||||
.param(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM, "fookind"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_doPost() throws Exception {
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM))
|
||||
.thenReturn("some_dataset");
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM))
|
||||
.thenReturn("12345_fookind");
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM))
|
||||
.thenReturn("fookind");
|
||||
|
||||
servlet.service(req, rsp);
|
||||
|
||||
// Check that we attempted to create the latest_snapshot dataset.
|
||||
ArgumentCaptor<Dataset> datasetArgument = ArgumentCaptor.forClass(Dataset.class);
|
||||
verify(bigqueryDatasets).insert(eq("Project-Id"), datasetArgument.capture());
|
||||
assertThat(datasetArgument.getValue().getDatasetReference().getProjectId())
|
||||
.isEqualTo("Project-Id");
|
||||
assertThat(datasetArgument.getValue().getDatasetReference().getDatasetId())
|
||||
.isEqualTo("testdataset");
|
||||
verify(bigqueryDatasetsInsert).execute();
|
||||
|
||||
// Check that we updated the view.
|
||||
ArgumentCaptor<Table> tableArg = ArgumentCaptor.forClass(Table.class);
|
||||
verify(bigqueryTables).update(
|
||||
eq("Project-Id"), eq("testdataset"), eq("fookind"), tableArg.capture());
|
||||
assertThat(tableArg.getValue().getView().getQuery())
|
||||
.isEqualTo("SELECT * FROM [some_dataset.12345_fookind]");
|
||||
|
||||
verify(rsp).setStatus(SC_OK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_missingDatasetIdHeader() throws Exception {
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM))
|
||||
.thenReturn("12345_fookind");
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM)).thenReturn("fookind");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: dataset");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_missingTableIdHeader() throws Exception {
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM))
|
||||
.thenReturn("some_dataset");
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM)).thenReturn("fookind");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: table");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doPost_missingKindHeader() throws Exception {
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM))
|
||||
.thenReturn("some_dataset");
|
||||
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM))
|
||||
.thenReturn("12345_fookind");
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: kind");
|
||||
}
|
||||
}
|
27
javatests/com/google/domain/registry/export/backup_kinds.txt
Normal file
27
javatests/com/google/domain/registry/export/backup_kinds.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
Cancellation
|
||||
ContactResource
|
||||
DomainApplicationIndex
|
||||
DomainBase
|
||||
EntityGroupRoot
|
||||
EppResourceIndex
|
||||
ForeignKeyContactIndex
|
||||
ForeignKeyDomainIndex
|
||||
ForeignKeyHostIndex
|
||||
HistoryEntry
|
||||
HostResource
|
||||
LogsExportCursor
|
||||
Modification
|
||||
OneTime
|
||||
PollMessage
|
||||
PremiumList
|
||||
PremiumListEntry
|
||||
RdeRevision
|
||||
Recurring
|
||||
Registrar
|
||||
RegistrarBillingEntry
|
||||
RegistrarContact
|
||||
RegistrarCredit
|
||||
RegistrarCreditBalance
|
||||
Registry
|
||||
RegistryCursor
|
||||
ReservedList
|
31
javatests/com/google/domain/registry/export/sheet/BUILD
Normal file
31
javatests/com/google/domain/registry/export/sheet/BUILD
Normal file
|
@ -0,0 +1,31 @@
|
|||
package(default_visibility = ["//java/com/google/domain/registry:registry_project"])
|
||||
|
||||
|
||||
java_library(
|
||||
name = "sheet",
|
||||
srcs = glob(["*.java"]),
|
||||
deps = [
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/net",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//java/com/google/domain/registry/export/sheet",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/gdata:spreadsheet",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
test_files = glob(["*Test.java"]),
|
||||
deps = [":sheet"],
|
||||
)
|
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export.sheet;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gdata.client.spreadsheet.SpreadsheetService;
|
||||
import com.google.gdata.data.spreadsheet.CustomElementCollection;
|
||||
import com.google.gdata.data.spreadsheet.ListEntry;
|
||||
import com.google.gdata.data.spreadsheet.ListFeed;
|
||||
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
|
||||
import com.google.gdata.data.spreadsheet.WorksheetEntry;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.net.URL;
|
||||
|
||||
/** Unit tests for {@link SheetSynchronizer}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class SheetSynchronizerTest {
|
||||
|
||||
private final SpreadsheetService spreadsheetService = mock(SpreadsheetService.class);
|
||||
private final SpreadsheetEntry spreadsheet = mock(SpreadsheetEntry.class);
|
||||
private final WorksheetEntry worksheet = mock(WorksheetEntry.class);
|
||||
private final ListFeed listFeed = mock(ListFeed.class);
|
||||
private final SheetSynchronizer sheetSynchronizer = new SheetSynchronizer();
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
sheetSynchronizer.spreadsheetService = spreadsheetService;
|
||||
when(spreadsheetService.getEntry(any(URL.class), eq(SpreadsheetEntry.class)))
|
||||
.thenReturn(spreadsheet);
|
||||
when(spreadsheet.getWorksheets())
|
||||
.thenReturn(ImmutableList.of(worksheet));
|
||||
when(worksheet.getListFeedUrl())
|
||||
.thenReturn(new URL("http://example.com/spreadsheet"));
|
||||
when(spreadsheetService.getFeed(any(URL.class), eq(ListFeed.class)))
|
||||
.thenReturn(listFeed);
|
||||
when(worksheet.update())
|
||||
.thenReturn(worksheet);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
verify(spreadsheetService).getEntry(
|
||||
new URL("https://spreadsheets.google.com/feeds/spreadsheets/foobar"),
|
||||
SpreadsheetEntry.class);
|
||||
verify(spreadsheet).getWorksheets();
|
||||
verify(worksheet).getListFeedUrl();
|
||||
verify(spreadsheetService).getFeed(new URL("http://example.com/spreadsheet"), ListFeed.class);
|
||||
verify(listFeed).getEntries();
|
||||
verifyNoMoreInteractions(spreadsheetService, spreadsheet, worksheet, listFeed);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronize_bothEmpty_doNothing() throws Exception {
|
||||
when(listFeed.getEntries()).thenReturn(ImmutableList.<ListEntry>of());
|
||||
sheetSynchronizer.synchronize("foobar", ImmutableList.<ImmutableMap<String, String>>of());
|
||||
verify(worksheet).setRowCount(0);
|
||||
verify(worksheet).update();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronize_bothContainSameRow_doNothing() throws Exception {
|
||||
ListEntry entry = makeListEntry(ImmutableMap.of("key", "value"));
|
||||
when(listFeed.getEntries()).thenReturn(ImmutableList.of(entry));
|
||||
sheetSynchronizer.synchronize("foobar", ImmutableList.of(
|
||||
ImmutableMap.of("key", "value")));
|
||||
verify(worksheet).setRowCount(1);
|
||||
verify(worksheet).update();
|
||||
verify(entry, atLeastOnce()).getCustomElements();
|
||||
verifyNoMoreInteractions(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronize_cellIsDifferent_updateRow() throws Exception {
|
||||
ListEntry entry = makeListEntry(ImmutableMap.of("key", "value"));
|
||||
when(listFeed.getEntries()).thenReturn(ImmutableList.of(entry));
|
||||
sheetSynchronizer.synchronize("foobar", ImmutableList.of(
|
||||
ImmutableMap.of("key", "new value")));
|
||||
verify(entry.getCustomElements()).setValueLocal("key", "new value");
|
||||
verify(entry).update();
|
||||
verify(worksheet).setRowCount(1);
|
||||
verify(worksheet).update();
|
||||
verify(entry, atLeastOnce()).getCustomElements();
|
||||
verifyNoMoreInteractions(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronize_spreadsheetMissingRow_insertRow() throws Exception {
|
||||
ListEntry entry = makeListEntry(ImmutableMap.<String, String>of());
|
||||
when(listFeed.getEntries()).thenReturn(ImmutableList.<ListEntry>of());
|
||||
when(listFeed.createEntry()).thenReturn(entry);
|
||||
sheetSynchronizer.synchronize("foobar", ImmutableList.of(
|
||||
ImmutableMap.of("key", "value")));
|
||||
verify(entry.getCustomElements()).setValueLocal("key", "value");
|
||||
verify(listFeed).insert(entry);
|
||||
verify(worksheet).setRowCount(1);
|
||||
verify(worksheet).update();
|
||||
verify(listFeed).createEntry();
|
||||
verify(entry, atLeastOnce()).getCustomElements();
|
||||
verifyNoMoreInteractions(entry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSynchronize_spreadsheetRowNoLongerInData_deleteRow() throws Exception {
|
||||
ListEntry entry = makeListEntry(ImmutableMap.of("key", "value"));
|
||||
when(listFeed.getEntries()).thenReturn(ImmutableList.of(entry));
|
||||
sheetSynchronizer.synchronize("foobar", ImmutableList.<ImmutableMap<String, String>>of());
|
||||
verify(worksheet).setRowCount(0);
|
||||
verify(worksheet).update();
|
||||
verifyNoMoreInteractions(entry);
|
||||
}
|
||||
|
||||
private static ListEntry makeListEntry(ImmutableMap<String, String> values) {
|
||||
CustomElementCollection collection = mock(CustomElementCollection.class);
|
||||
for (ImmutableMap.Entry<String, String> entry : values.entrySet()) {
|
||||
when(collection.getValue(eq(entry.getKey()))).thenReturn(entry.getValue());
|
||||
}
|
||||
ListEntry listEntry = mock(ListEntry.class);
|
||||
when(listEntry.getCustomElements()).thenReturn(collection);
|
||||
return listEntry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export.sheet;
|
||||
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.domain.registry.model.server.Lock;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeResponse;
|
||||
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Unit tests for {@link SyncRegistrarsSheetTask}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class SyncRegistrarsSheetTaskTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final SyncRegistrarsSheet syncRegistrarsSheet = mock(SyncRegistrarsSheet.class);
|
||||
|
||||
private void runTask(@Nullable String idConfig, @Nullable String idParam) {
|
||||
SyncRegistrarsSheetTask task = new SyncRegistrarsSheetTask();
|
||||
task.response = response;
|
||||
task.syncRegistrarsSheet = syncRegistrarsSheet;
|
||||
task.idConfig = Optional.fromNullable(idConfig);
|
||||
task.idParam = Optional.fromNullable(idParam);
|
||||
task.interval = Duration.standardHours(1);
|
||||
task.timeout = Duration.standardHours(1);
|
||||
task.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_withoutParamsOrSystemProperty_dropsTask() throws Exception {
|
||||
runTask(null, null);
|
||||
assertThat(response.getPayload()).startsWith("MISSINGNO");
|
||||
verifyZeroInteractions(syncRegistrarsSheet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_withoutParams_runsSyncWithDefaultIdAndChecksIfModified() throws Exception {
|
||||
when(syncRegistrarsSheet.wasRegistrarsModifiedInLast(any(Duration.class))).thenReturn(true);
|
||||
runTask("jazz", null);
|
||||
assertThat(response.getStatus()).isEqualTo(200);
|
||||
assertThat(response.getContentType()).isEqualTo(PLAIN_TEXT_UTF_8);
|
||||
assertThat(response.getPayload()).startsWith("OK");
|
||||
verify(syncRegistrarsSheet).wasRegistrarsModifiedInLast(any(Duration.class));
|
||||
verify(syncRegistrarsSheet).run(eq("jazz"));
|
||||
verifyNoMoreInteractions(syncRegistrarsSheet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_noModificationsToRegistrarEntities_doesNothing() throws Exception {
|
||||
when(syncRegistrarsSheet.wasRegistrarsModifiedInLast(any(Duration.class))).thenReturn(false);
|
||||
runTask("NewRegistrar", null);
|
||||
assertThat(response.getPayload()).startsWith("NOTMODIFIED");
|
||||
verify(syncRegistrarsSheet).wasRegistrarsModifiedInLast(any(Duration.class));
|
||||
verifyNoMoreInteractions(syncRegistrarsSheet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_overrideId_runsSyncWithCustomIdAndDoesNotCheckModified() throws Exception {
|
||||
runTask(null, "foobar");
|
||||
assertThat(response.getPayload()).startsWith("OK");
|
||||
verify(syncRegistrarsSheet).run(eq("foobar"));
|
||||
verifyNoMoreInteractions(syncRegistrarsSheet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPost_failToAquireLock_servletDoesNothingAndReturns() throws Exception {
|
||||
String lockName = "Synchronize registrars sheet: foobar";
|
||||
Lock.executeWithLocks(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
runTask(null, "foobar");
|
||||
return null;
|
||||
}
|
||||
}, SyncRegistrarsSheetTask.class, "", Duration.standardHours(1), lockName);
|
||||
assertThat(response.getPayload()).startsWith("LOCKED");
|
||||
verifyZeroInteractions(syncRegistrarsSheet);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,349 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.export.sheet;
|
||||
|
||||
import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.deleteResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistSimpleGlobalResources;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.joda.time.Duration.standardHours;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.config.RegistryEnvironment;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarAddress;
|
||||
import com.google.domain.registry.model.registrar.RegistrarContact;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Unit tests for {@link SyncRegistrarsSheet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class SyncRegistrarsSheetTest {
|
||||
|
||||
private static final RegistryEnvironment ENVIRONMENT = RegistryEnvironment.get();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<ImmutableList<ImmutableMap<String, String>>> rowsCaptor;
|
||||
|
||||
@Mock
|
||||
private SheetSynchronizer sheetSynchronizer;
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
private SyncRegistrarsSheet newSyncRegistrarsSheet() {
|
||||
SyncRegistrarsSheet result = new SyncRegistrarsSheet();
|
||||
result.clock = clock;
|
||||
result.sheetSynchronizer = sheetSynchronizer;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
createTld("example");
|
||||
// Remove Registrar entities created by AppEngineRule.
|
||||
for (Registrar registrar : Registrar.loadAll()) {
|
||||
deleteResource(registrar);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWasRegistrarsModifiedInLast_noRegistrars_returnsFalse() throws Exception {
|
||||
SyncRegistrarsSheet sync = newSyncRegistrarsSheet();
|
||||
assertThat(sync.wasRegistrarsModifiedInLast(Duration.standardHours(1))).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWasRegistrarsModifiedInLastInterval() throws Exception {
|
||||
Duration interval = standardHours(1);
|
||||
persistResource(new Registrar.Builder()
|
||||
.setClientIdentifier("SomeRegistrar")
|
||||
.setRegistrarName("Some Registrar Inc.")
|
||||
.setType(Registrar.Type.REAL)
|
||||
.setIanaIdentifier(8L)
|
||||
.setState(Registrar.State.ACTIVE)
|
||||
.build());
|
||||
clock.advanceBy(interval);
|
||||
assertThat(newSyncRegistrarsSheet().wasRegistrarsModifiedInLast(interval)).isTrue();
|
||||
clock.advanceOneMilli();
|
||||
assertThat(newSyncRegistrarsSheet().wasRegistrarsModifiedInLast(interval)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun() throws Exception {
|
||||
persistResource(new Registrar.Builder()
|
||||
.setClientIdentifier("anotherregistrar")
|
||||
.setRegistrarName("Another Registrar LLC")
|
||||
.setType(Registrar.Type.REAL)
|
||||
.setIanaIdentifier(1L)
|
||||
.setState(Registrar.State.ACTIVE)
|
||||
.setInternationalizedAddress(new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("I will get ignored :'("))
|
||||
.setCity("Williamsburg")
|
||||
.setState("NY")
|
||||
.setZip("11211")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.setLocalizedAddress(new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of(
|
||||
"123 Main St",
|
||||
"Suite 100"))
|
||||
.setCity("Smalltown")
|
||||
.setState("NY")
|
||||
.setZip("11211")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.setPhoneNumber("+1.2125551212")
|
||||
.setFaxNumber("+1.2125551213")
|
||||
.setEmailAddress("contact-us@example.com")
|
||||
.setWhoisServer("whois.example.com")
|
||||
.setUrl("http://www.example.org/another_registrar")
|
||||
.setIcannReferralEmail("jim@example.net")
|
||||
.build());
|
||||
|
||||
Registrar registrar = new Registrar.Builder()
|
||||
.setClientIdentifier("aaaregistrar")
|
||||
.setRegistrarName("AAA Registrar Inc.")
|
||||
.setType(Registrar.Type.REAL)
|
||||
.setIanaIdentifier(8L)
|
||||
.setState(Registrar.State.SUSPENDED)
|
||||
.setPassword("pa$$word")
|
||||
.setEmailAddress("nowhere@example.org")
|
||||
.setInternationalizedAddress(new RegistrarAddress.Builder()
|
||||
.setStreet(ImmutableList.of("I get fallen back upon since there's no l10n addr"))
|
||||
.setCity("Williamsburg")
|
||||
.setState("NY")
|
||||
.setZip("11211")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.setAllowedTlds(ImmutableSet.of("example"))
|
||||
.setPhoneNumber("+1.2223334444")
|
||||
.setUrl("http://www.example.org/aaa_registrar")
|
||||
.build();
|
||||
ImmutableList<RegistrarContact> contacts = ImmutableList.of(
|
||||
new RegistrarContact.Builder()
|
||||
.setParent(registrar)
|
||||
.setName("Jane Doe")
|
||||
.setEmailAddress("contact@example.com")
|
||||
.setPhoneNumber("+1.1234567890")
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.ADMIN, RegistrarContact.Type.BILLING))
|
||||
.build(),
|
||||
new RegistrarContact.Builder()
|
||||
.setParent(registrar)
|
||||
.setName("John Doe")
|
||||
.setEmailAddress("john.doe@example.tld")
|
||||
.setPhoneNumber("+1.1234567890")
|
||||
.setFaxNumber("+1.1234567891")
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.ADMIN))
|
||||
// Purposely flip the internal/external admin/tech
|
||||
// distinction to make sure we're not relying on it. Sigh.
|
||||
.setVisibleInWhoisAsAdmin(false)
|
||||
.setVisibleInWhoisAsTech(true)
|
||||
.setGaeUserId("light")
|
||||
.build(),
|
||||
new RegistrarContact.Builder()
|
||||
.setParent(registrar)
|
||||
.setName("Jane Smith")
|
||||
.setEmailAddress("pride@example.net")
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.TECH))
|
||||
.build());
|
||||
// Use registrar ref for contacts' parent.
|
||||
persistSimpleGlobalResources(contacts);
|
||||
persistResource(registrar);
|
||||
|
||||
newSyncRegistrarsSheet().run("foobar");
|
||||
|
||||
verify(sheetSynchronizer).synchronize(eq("foobar"), rowsCaptor.capture());
|
||||
ImmutableList<ImmutableMap<String, String>> rows = getOnlyElement(rowsCaptor.getAllValues());
|
||||
assertThat(rows).hasSize(2);
|
||||
|
||||
ImmutableMap<String, String> row = rows.get(0);
|
||||
assertThat(row).containsEntry("clientIdentifier", "aaaregistrar");
|
||||
assertThat(row).containsEntry("registrarName", "AAA Registrar Inc.");
|
||||
assertThat(row).containsEntry("state", "SUSPENDED");
|
||||
assertThat(row).containsEntry("ianaIdentifier", "8");
|
||||
assertThat(row).containsEntry("billingIdentifier", "");
|
||||
assertThat(row).containsEntry("primaryContacts", ""
|
||||
+ "Jane Doe\n"
|
||||
+ "contact@example.com\n"
|
||||
+ "Tel: +1.1234567890\n"
|
||||
+ "Types: [ADMIN, BILLING]\n"
|
||||
+ "Visible in WHOIS as Admin contact: No\n"
|
||||
+ "Visible in WHOIS as Technical contact: No\n"
|
||||
+ "\n"
|
||||
+ "John Doe\n"
|
||||
+ "john.doe@example.tld\n"
|
||||
+ "Tel: +1.1234567890\n"
|
||||
+ "Fax: +1.1234567891\n"
|
||||
+ "Types: [ADMIN]\n"
|
||||
+ "Visible in WHOIS as Admin contact: No\n"
|
||||
+ "Visible in WHOIS as Technical contact: Yes\n"
|
||||
+ "GAE-UserID: light\n");
|
||||
assertThat(row).containsEntry("techContacts", ""
|
||||
+ "Jane Smith\n"
|
||||
+ "pride@example.net\n"
|
||||
+ "Types: [TECH]\n"
|
||||
+ "Visible in WHOIS as Admin contact: No\n"
|
||||
+ "Visible in WHOIS as Technical contact: No\n");
|
||||
assertThat(row).containsEntry("marketingContacts", "");
|
||||
assertThat(row).containsEntry("abuseContacts", "");
|
||||
assertThat(row).containsEntry("whoisInquiryContacts", "");
|
||||
assertThat(row).containsEntry("legalContacts", "");
|
||||
assertThat(row).containsEntry("billingContacts", ""
|
||||
+ "Jane Doe\n"
|
||||
+ "contact@example.com\n"
|
||||
+ "Tel: +1.1234567890\n"
|
||||
+ "Types: [ADMIN, BILLING]\n"
|
||||
+ "Visible in WHOIS as Admin contact: No\n"
|
||||
+ "Visible in WHOIS as Technical contact: No\n");
|
||||
assertThat(row).containsEntry("contactsMarkedAsWhoisAdmin", "");
|
||||
assertThat(row).containsEntry("contactsMarkedAsWhoisTech", ""
|
||||
+ "John Doe\n"
|
||||
+ "john.doe@example.tld\n"
|
||||
+ "Tel: +1.1234567890\n"
|
||||
+ "Fax: +1.1234567891\n"
|
||||
+ "Types: [ADMIN]\n"
|
||||
+ "Visible in WHOIS as Admin contact: No\n"
|
||||
+ "Visible in WHOIS as Technical contact: Yes\n"
|
||||
+ "GAE-UserID: light\n");
|
||||
assertThat(row).containsEntry("emailAddress", "nowhere@example.org");
|
||||
assertThat(row).containsEntry(
|
||||
"address.street", "I get fallen back upon since there's no l10n addr");
|
||||
assertThat(row).containsEntry("address.city", "Williamsburg");
|
||||
assertThat(row).containsEntry("address.state", "NY");
|
||||
assertThat(row).containsEntry("address.zip", "11211");
|
||||
assertThat(row).containsEntry("address.countryCode", "US");
|
||||
assertThat(row).containsEntry("phoneNumber", "+1.2223334444");
|
||||
assertThat(row).containsEntry("faxNumber", "");
|
||||
assertThat(row.get("creationTime")).isEqualTo(clock.nowUtc().toString());
|
||||
assertThat(row.get("lastUpdateTime")).isEqualTo(clock.nowUtc().toString());
|
||||
assertThat(row).containsEntry("allowedTlds", "example");
|
||||
assertThat(row).containsEntry("blockPremiumNames", "false");
|
||||
assertThat(row).containsEntry("ipAddressWhitelist", "");
|
||||
assertThat(row).containsEntry("url", "http://www.example.org/aaa_registrar");
|
||||
assertThat(row).containsEntry("icannReferralEmail", "");
|
||||
assertThat(row).containsEntry("whoisServer",
|
||||
ENVIRONMENT.config().getRegistrarDefaultWhoisServer());
|
||||
assertThat(row).containsEntry("referralUrl",
|
||||
ENVIRONMENT.config().getRegistrarDefaultReferralUrl().toString());
|
||||
|
||||
row = rows.get(1);
|
||||
assertThat(row).containsEntry("clientIdentifier", "anotherregistrar");
|
||||
assertThat(row).containsEntry("registrarName", "Another Registrar LLC");
|
||||
assertThat(row).containsEntry("state", "ACTIVE");
|
||||
assertThat(row).containsEntry("ianaIdentifier", "1");
|
||||
assertThat(row).containsEntry("billingIdentifier", "");
|
||||
assertThat(row).containsEntry("primaryContacts", "");
|
||||
assertThat(row).containsEntry("techContacts", "");
|
||||
assertThat(row).containsEntry("marketingContacts", "");
|
||||
assertThat(row).containsEntry("abuseContacts", "");
|
||||
assertThat(row).containsEntry("whoisInquiryContacts", "");
|
||||
assertThat(row).containsEntry("legalContacts", "");
|
||||
assertThat(row).containsEntry("billingContacts", "");
|
||||
assertThat(row).containsEntry("contactsMarkedAsWhoisAdmin", "");
|
||||
assertThat(row).containsEntry("contactsMarkedAsWhoisTech", "");
|
||||
assertThat(row).containsEntry("emailAddress", "contact-us@example.com");
|
||||
assertThat(row).containsEntry("address.street", "123 Main St\nSuite 100");
|
||||
assertThat(row).containsEntry("address.city", "Smalltown");
|
||||
assertThat(row).containsEntry("address.state", "NY");
|
||||
assertThat(row).containsEntry("address.zip", "11211");
|
||||
assertThat(row).containsEntry("address.countryCode", "US");
|
||||
assertThat(row).containsEntry("phoneNumber", "+1.2125551212");
|
||||
assertThat(row).containsEntry("faxNumber", "+1.2125551213");
|
||||
assertThat(row.get("creationTime")).isEqualTo(clock.nowUtc().toString());
|
||||
assertThat(row.get("lastUpdateTime")).isEqualTo(clock.nowUtc().toString());
|
||||
assertThat(row).containsEntry("allowedTlds", "");
|
||||
assertThat(row).containsEntry("whoisServer", "whois.example.com");
|
||||
assertThat(row).containsEntry("blockPremiumNames", "false");
|
||||
assertThat(row).containsEntry("ipAddressWhitelist", "");
|
||||
assertThat(row).containsEntry("url", "http://www.example.org/another_registrar");
|
||||
assertThat(row).containsEntry("referralUrl",
|
||||
ENVIRONMENT.config().getRegistrarDefaultReferralUrl().toString());
|
||||
assertThat(row).containsEntry("icannReferralEmail", "jim@example.net");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRun_missingValues_stillWorks() throws Exception {
|
||||
persistResource(new Registrar.Builder()
|
||||
.setClientIdentifier("SomeRegistrar")
|
||||
.setType(Registrar.Type.REAL)
|
||||
.setIanaIdentifier(8L)
|
||||
.build());
|
||||
|
||||
newSyncRegistrarsSheet().run("foobar");
|
||||
|
||||
verify(sheetSynchronizer).synchronize(eq("foobar"), rowsCaptor.capture());
|
||||
ImmutableMap<String, String> row = getOnlyElement(getOnlyElement(rowsCaptor.getAllValues()));
|
||||
assertThat(row).containsEntry("clientIdentifier", "SomeRegistrar");
|
||||
assertThat(row).containsEntry("registrarName", "");
|
||||
assertThat(row).containsEntry("state", "");
|
||||
assertThat(row).containsEntry("ianaIdentifier", "8");
|
||||
assertThat(row).containsEntry("billingIdentifier", "");
|
||||
assertThat(row).containsEntry("primaryContacts", "");
|
||||
assertThat(row).containsEntry("techContacts", "");
|
||||
assertThat(row).containsEntry("marketingContacts", "");
|
||||
assertThat(row).containsEntry("abuseContacts", "");
|
||||
assertThat(row).containsEntry("whoisInquiryContacts", "");
|
||||
assertThat(row).containsEntry("legalContacts", "");
|
||||
assertThat(row).containsEntry("billingContacts", "");
|
||||
assertThat(row).containsEntry("contactsMarkedAsWhoisAdmin", "");
|
||||
assertThat(row).containsEntry("contactsMarkedAsWhoisTech", "");
|
||||
assertThat(row).containsEntry("emailAddress", "");
|
||||
assertThat(row).containsEntry("address.street", "UNKNOWN");
|
||||
assertThat(row).containsEntry("address.city", "UNKNOWN");
|
||||
assertThat(row).containsEntry("address.state", "");
|
||||
assertThat(row).containsEntry("address.zip", "");
|
||||
assertThat(row).containsEntry("address.countryCode", "US");
|
||||
assertThat(row).containsEntry("phoneNumber", "");
|
||||
assertThat(row).containsEntry("faxNumber", "");
|
||||
assertThat(row).containsEntry("allowedTlds", "");
|
||||
assertThat(row).containsEntry("whoisServer",
|
||||
ENVIRONMENT.config().getRegistrarDefaultWhoisServer());
|
||||
assertThat(row).containsEntry("blockPremiumNames", "false");
|
||||
assertThat(row).containsEntry("ipAddressWhitelist", "");
|
||||
assertThat(row).containsEntry("url", "");
|
||||
assertThat(row).containsEntry("referralUrl",
|
||||
ENVIRONMENT.config().getRegistrarDefaultReferralUrl().toString());
|
||||
assertThat(row).containsEntry("icannReferralEmail", "");
|
||||
}
|
||||
}
|
33
javatests/com/google/domain/registry/export/testdata/contact_create.xml
vendored
Normal file
33
javatests/com/google/domain/registry/export/testdata/contact_create.xml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<contact:create
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="0">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:create>
|
||||
</create>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
28
javatests/com/google/domain/registry/export/testdata/domain_allocate.xml
vendored
Normal file
28
javatests/com/google/domain/registry/export/testdata/domain_allocate.xml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<domain:create
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example-one.tld</domain:name>
|
||||
<domain:period unit="y">2</domain:period>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.net</domain:hostObj>
|
||||
<domain:hostObj>ns2.example.net</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:registrant>jd1234</domain:registrant>
|
||||
<domain:contact type="admin">sh8013</domain:contact>
|
||||
<domain:contact type="tech">sh8013</domain:contact>
|
||||
<domain:authInfo>
|
||||
<domain:pw>2fooBAR</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:create>
|
||||
</create>
|
||||
<extension>
|
||||
<allocate:create xmlns:allocate="urn:google:params:xml:ns:allocate-1.0">
|
||||
<allocate:applicationRoid>1-TLD</allocate:applicationRoid>
|
||||
<allocate:applicationTime>2010-08-16T10:00:00.0Z</allocate:applicationTime>
|
||||
</allocate:create>
|
||||
</extension>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
22
javatests/com/google/domain/registry/export/testdata/domain_create.xml
vendored
Normal file
22
javatests/com/google/domain/registry/export/testdata/domain_create.xml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<domain:create
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.com</domain:name>
|
||||
<domain:period unit="y">2</domain:period>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.net</domain:hostObj>
|
||||
<domain:hostObj>ns2.example.net</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:registrant>jd1234</domain:registrant>
|
||||
<domain:contact type="admin">sh8013</domain:contact>
|
||||
<domain:contact type="tech">sh8013</domain:contact>
|
||||
<domain:authInfo>
|
||||
<domain:pw>2fooBAR</domain:pw>
|
||||
</domain:authInfo>
|
||||
</domain:create>
|
||||
</create>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
File diff suppressed because one or more lines are too long
13
javatests/com/google/domain/registry/export/testdata/domain_renew.xml
vendored
Normal file
13
javatests/com/google/domain/registry/export/testdata/domain_renew.xml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<renew>
|
||||
<domain:renew
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:curExpDate>2000-04-03</domain:curExpDate>
|
||||
<domain:period unit="y">5</domain:period>
|
||||
</domain:renew>
|
||||
</renew>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
72
javatests/com/google/domain/registry/flows/BUILD
Normal file
72
javatests/com/google/domain/registry/flows/BUILD
Normal file
|
@ -0,0 +1,72 @@
|
|||
package(
|
||||
default_visibility = ["//java/com/google/domain/registry:registry_project"],
|
||||
)
|
||||
|
||||
load("//java/com/google/testing/builddefs:GenTestRules.bzl", "GenTestRules")
|
||||
|
||||
|
||||
# Needed for the documentation tests
|
||||
filegroup(
|
||||
name = "flows_files",
|
||||
srcs = glob([
|
||||
"*.java",
|
||||
"**/*.java",
|
||||
]),
|
||||
)
|
||||
|
||||
java_library(
|
||||
name = "flows",
|
||||
srcs = glob([
|
||||
"*.java",
|
||||
"**/*.java",
|
||||
]),
|
||||
resources = glob(["**/testdata/*.xml"]),
|
||||
deps = [
|
||||
"//java/com/google/common/base",
|
||||
"//java/com/google/common/collect",
|
||||
"//java/com/google/common/io",
|
||||
"//java/com/google/common/net",
|
||||
"//java/com/google/domain/registry/config",
|
||||
"//java/com/google/domain/registry/dns",
|
||||
"//java/com/google/domain/registry/flows",
|
||||
"//java/com/google/domain/registry/mapreduce",
|
||||
"//java/com/google/domain/registry/model",
|
||||
"//java/com/google/domain/registry/request",
|
||||
"//java/com/google/domain/registry/security",
|
||||
"//java/com/google/domain/registry/security:servlets",
|
||||
"//java/com/google/domain/registry/tmch",
|
||||
"//java/com/google/domain/registry/util",
|
||||
"//java/com/google/domain/registry/xml",
|
||||
"//javatests/com/google/domain/registry/model",
|
||||
"//javatests/com/google/domain/registry/testing",
|
||||
"//javatests/com/google/domain/registry/testing/mapreduce",
|
||||
"//javatests/com/google/domain/registry/xml",
|
||||
"//third_party/java/appengine:appengine-api-testonly",
|
||||
"//third_party/java/appengine:appengine-testing",
|
||||
"//third_party/java/joda_money",
|
||||
"//third_party/java/joda_time",
|
||||
"//third_party/java/jsr305_annotations",
|
||||
"//third_party/java/junit",
|
||||
"//third_party/java/mockito",
|
||||
"//third_party/java/objectify:objectify-v4_1",
|
||||
"//third_party/java/servlet/servlet_api",
|
||||
"//third_party/java/truth",
|
||||
],
|
||||
)
|
||||
|
||||
# If the flows tests should grow again to the point that they last longer than
|
||||
# sixty seconds, then shard_count should be tuned. You can binary search for a
|
||||
# good value that balances time reduction with environmental impact. However,
|
||||
# any unit test that contains fewer @Test methods than the shard count will
|
||||
# If you grep for testNothing you can find the existing dummy methods.
|
||||
GenTestRules(
|
||||
name = "GeneratedTestRules",
|
||||
default_test_size = "medium",
|
||||
jvm_flags = ["-XX:MaxPermSize=256m"],
|
||||
shard_count = 4,
|
||||
test_files = glob([
|
||||
"*Test.java",
|
||||
"*/*Test.java",
|
||||
]),
|
||||
deps = [":flows"],
|
||||
)
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.UserInfo;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Tests for {@link EppConsoleServlet} running in admin mode. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EppConsoleAsAdminServletTest extends EppServletXmlLoginTestCase<EppConsoleServlet> {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.withUserService(UserInfo.createAdmin(GAE_USER_EMAIL, GAE_USER_ID))
|
||||
.build();
|
||||
|
||||
private static final String GAE_USER_ID = "12345";
|
||||
private static final String GAE_USER_EMAIL = "someone@example.com";
|
||||
|
||||
// Note that the setup done in EppConsoleServletTest, of allowing
|
||||
// the test user to login as the Registrar, is not done here.
|
||||
@Before
|
||||
public void initTest() throws Exception {
|
||||
persistResource(
|
||||
Registrar.loadByClientId("NewRegistrar").asBuilder().setPassword("PwAdminDNKnow").build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonAuthedLogin() throws Exception {
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiLogin() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarContact;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.UserInfo;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Tests for {@link EppConsoleServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EppConsoleServletTest extends EppServletXmlLoginTestCase<EppConsoleServlet> {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.withUserService(UserInfo.create(GAE_USER_EMAIL, GAE_USER_ID))
|
||||
.build();
|
||||
|
||||
private static final String GAE_USER_ID = "12345";
|
||||
private static final String GAE_USER_EMAIL = "person@example.com";
|
||||
|
||||
@Before
|
||||
public void initTest() throws Exception {
|
||||
Registrar registrar = Registrar.loadByClientId("NewRegistrar");
|
||||
RegistrarContact contact = new RegistrarContact.Builder()
|
||||
.setParent(registrar)
|
||||
.setEmailAddress(GAE_USER_EMAIL)
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.ADMIN))
|
||||
.setGaeUserId(GAE_USER_ID)
|
||||
.build();
|
||||
persistResource(contact);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonAuthedLogin() throws Exception {
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response_unauthorized_role.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiLogin() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response_unauthorized_role.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.domain.registry.flows.EppController.getErrorResponse;
|
||||
import static com.google.domain.registry.flows.EppXmlTransformer.marshal;
|
||||
|
||||
import com.google.domain.registry.model.eppcommon.Trid;
|
||||
import com.google.domain.registry.model.eppoutput.Result;
|
||||
import com.google.domain.registry.model.eppoutput.Result.Code;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.xml.ValidationMode;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link EppController}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class EppControllerTest {
|
||||
|
||||
@Rule
|
||||
public AppEngineRule appEngineRule = new AppEngineRule.Builder().build();
|
||||
|
||||
@Test
|
||||
public void testMarshallingUnknownError() throws Exception {
|
||||
marshal(
|
||||
getErrorResponse(Result.create(Code.CommandFailed), Trid.create(null)),
|
||||
ValidationMode.STRICT);
|
||||
}
|
||||
|
||||
// Extra methods so the test runner doesn't produce empty shards.
|
||||
|
||||
@Test public void testNothing1() {}
|
||||
@Test public void testNothing2() {}
|
||||
@Test public void testNothing3() {}
|
||||
}
|
|
@ -0,0 +1,301 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
|
||||
import static com.google.domain.registry.security.XsrfTokenManager.generateToken;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTlds;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.TestDataHelper.loadFileWithSubstitutions;
|
||||
import static com.google.domain.registry.xml.XmlTestUtils.assertXmlEqualsWithMessage;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.reset;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.tmch.ClaimsListShard.ClaimsListSingleton;
|
||||
import com.google.domain.registry.security.XsrfProtectedServlet;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.FakeServletInputStream;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.util.BasicHttpSession;
|
||||
import com.google.domain.registry.util.TypeUtils.TypeInstantiator;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.ServletConfig;
|
||||
import javax.servlet.ServletOutputStream;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
/**
|
||||
* Test setup for all EppServletTest subclasses.
|
||||
*
|
||||
* @param <S> The EppXXXServlet class to test.
|
||||
*/
|
||||
public abstract class EppServletTestCase<S extends HttpServlet> {
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Mock
|
||||
HttpServletRequest req;
|
||||
|
||||
@Mock
|
||||
HttpServletResponse rsp;
|
||||
|
||||
HttpSession session;
|
||||
|
||||
FakeClock clock = new FakeClock();
|
||||
|
||||
private String currentTld = null;
|
||||
private Optional<Boolean> isSuperuser = Optional.<Boolean> absent();
|
||||
private Optional<String> clientIdentifier = Optional.<String> absent();
|
||||
|
||||
void setSuperuser(boolean isSuperuser) {
|
||||
this.isSuperuser = Optional.of(isSuperuser);
|
||||
}
|
||||
|
||||
void setClientIdentifier(String clientIdentifier) {
|
||||
this.clientIdentifier = Optional.of(clientIdentifier);
|
||||
}
|
||||
|
||||
static final DateTime START_OF_GA = DateTime.parse("2014-03-01T00:00:00Z");
|
||||
|
||||
@Before
|
||||
public final void init() throws Exception {
|
||||
inject.setStaticField(Ofy.class, "clock", clock); // For transactional flows.
|
||||
inject.setStaticField(FlowRunner.class, "clock", clock); // For non-transactional flows.
|
||||
|
||||
// Create RegistryData for all TLDs used in these tests.
|
||||
// We want to create all of these even for tests that don't use them to make sure that
|
||||
// tld-selection works correctly.
|
||||
createTlds("net", "xn--q9jyb4c", "example");
|
||||
ofy().saveWithoutBackup().entity(new ClaimsListSingleton()).now();
|
||||
|
||||
session = new BasicHttpSession();
|
||||
persistResource(
|
||||
Registrar.loadByClientId("NewRegistrar")
|
||||
.asBuilder()
|
||||
.setAllowedTlds(ImmutableSet.of("net", "example", "xn--q9jyb4c"))
|
||||
.build());
|
||||
|
||||
persistResource(
|
||||
Registrar.loadByClientId("TheRegistrar")
|
||||
.asBuilder()
|
||||
.setAllowedTlds(ImmutableSet.of("net", "example", "xn--q9jyb4c"))
|
||||
.build());
|
||||
}
|
||||
|
||||
void assertCommandAndResponse(
|
||||
String inputFilename,
|
||||
Map<String, String> inputSubstitutions,
|
||||
String outputFilename,
|
||||
Map<String, String> outputSubstitutions) throws Exception {
|
||||
assertCommandAndResponse(
|
||||
inputFilename,
|
||||
inputSubstitutions,
|
||||
outputFilename,
|
||||
outputSubstitutions,
|
||||
DateTime.now(UTC));
|
||||
}
|
||||
|
||||
String assertCommandAndResponse(String inputFilename, String outputFilename) throws Exception {
|
||||
return assertCommandAndResponse(inputFilename, outputFilename, DateTime.now(UTC));
|
||||
}
|
||||
|
||||
String assertCommandAndResponse(
|
||||
String inputFilename,
|
||||
Map<String, String> inputSubstitutions,
|
||||
String outputFilename,
|
||||
Map<String, String> outputSubstitutions,
|
||||
String nowString) throws Exception {
|
||||
return assertCommandAndResponse(
|
||||
inputFilename,
|
||||
inputSubstitutions,
|
||||
outputFilename,
|
||||
outputSubstitutions,
|
||||
DateTime.parse(nowString));
|
||||
}
|
||||
|
||||
String assertCommandAndResponse(String inputFilename, String outputFilename, String nowString)
|
||||
throws Exception {
|
||||
return assertCommandAndResponse(inputFilename, outputFilename, DateTime.parse(nowString));
|
||||
}
|
||||
|
||||
String assertCommandAndResponse(String inputFilename, String outputFilename, DateTime now)
|
||||
throws Exception {
|
||||
return assertCommandAndResponse(inputFilename, null, outputFilename, null, now);
|
||||
}
|
||||
|
||||
String assertCommandAndResponse(
|
||||
String inputFilename,
|
||||
Map<String, String> inputSubstitutions,
|
||||
String outputFilename,
|
||||
Map<String, String> outputSubstitutions,
|
||||
DateTime now) throws Exception {
|
||||
String outputFile =
|
||||
loadFileWithSubstitutions(EppServletTestCase.class, outputFilename, outputSubstitutions);
|
||||
String actualOutput = expectXmlCommand(loadFileWithSubstitutions(
|
||||
EppServletTestCase.class, inputFilename, inputSubstitutions), now);
|
||||
assertXmlEqualsWithMessage(
|
||||
outputFile,
|
||||
actualOutput,
|
||||
"Running " + inputFilename + " => " + outputFilename,
|
||||
"epp.response.resData.infData.roid",
|
||||
"epp.response.trID.svTRID");
|
||||
ofy().clearSessionCache(); // Clear the cache like OfyFilter would.
|
||||
return actualOutput;
|
||||
}
|
||||
|
||||
HttpSession getOrRenewSession() {
|
||||
// Try an idempotent op on the session to see if it's valid.
|
||||
try {
|
||||
session.getAttribute(null);
|
||||
return session;
|
||||
} catch (IllegalStateException e) {
|
||||
// Session is invalid.
|
||||
session = new BasicHttpSession();
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
String expectXmlCommand(String inputFile, DateTime now) throws Exception {
|
||||
clock.setTo(now); // Makes Ofy use 'now' as its time
|
||||
reset(req, rsp);
|
||||
HttpServlet servlet = new TypeInstantiator<S>(getClass()){}.instantiate();
|
||||
if (servlet instanceof XsrfProtectedServlet) {
|
||||
when(req.getHeader(X_CSRF_TOKEN))
|
||||
.thenReturn(generateToken(((XsrfProtectedServlet) servlet).getScope()));
|
||||
}
|
||||
when(req.getInputStream()).thenReturn(new FakeServletInputStream(inputFile.getBytes(UTF_8)));
|
||||
when(req.getParameter("xml")).thenReturn(inputFile);
|
||||
if (isSuperuser.isPresent()) {
|
||||
when(req.getParameter("superuser")).thenReturn(isSuperuser.get().toString());
|
||||
}
|
||||
if (clientIdentifier.isPresent()) {
|
||||
when(req.getParameter("clientIdentifier")).thenReturn(clientIdentifier.get());
|
||||
}
|
||||
when(req.getParameter("tld")).thenReturn(currentTld);
|
||||
when(req.getServletPath()).thenReturn("");
|
||||
when(req.getMethod()).thenReturn("POST");
|
||||
when(req.getHeader("X-Requested-With")).thenReturn("XMLHttpRequest");
|
||||
when(req.getSession(true)).thenAnswer(new Answer<HttpSession>() {
|
||||
@Override
|
||||
public HttpSession answer(InvocationOnMock invocation) {
|
||||
return getOrRenewSession();
|
||||
}});
|
||||
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
when(rsp.getOutputStream()).thenReturn(new ServletOutputStream() {
|
||||
@Override
|
||||
public void write(int b) {
|
||||
byteArrayOutputStream.write(b);
|
||||
}});
|
||||
extendedSessionConfig(inputFile);
|
||||
|
||||
servlet.init(mock(ServletConfig.class));
|
||||
servlet.service(req, rsp);
|
||||
verify(rsp).setStatus(HttpServletResponse.SC_OK);
|
||||
String result = new String(byteArrayOutputStream.toByteArray(), UTF_8);
|
||||
// Run the resulting xml through the unmarshaller to verify that it was valid.
|
||||
EppXmlTransformer.validateOutput(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Create the two administrative contacts and two hosts that are used by a lot of our tests. */
|
||||
protected void createContactsAndHosts() throws Exception {
|
||||
DateTime startTime = DateTime.parse("2000-06-01T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_sh8013.xml",
|
||||
ImmutableMap.<String, String>of(),
|
||||
"contact_create_response_sh8013.xml",
|
||||
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
|
||||
startTime);
|
||||
assertCommandAndResponse(
|
||||
"contact_create_jd1234.xml",
|
||||
"contact_create_response_jd1234.xml",
|
||||
startTime.plusMinutes(1));
|
||||
assertCommandAndResponse(
|
||||
"host_create.xml",
|
||||
"host_create_response.xml",
|
||||
startTime.plusMinutes(2));
|
||||
assertCommandAndResponse(
|
||||
"host_create2.xml",
|
||||
"host_create2_response.xml",
|
||||
startTime.plusMinutes(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the domain fakesite.example with two nameservers on it.
|
||||
*/
|
||||
protected void createFakesite() throws Exception {
|
||||
createContactsAndHosts();
|
||||
assertCommandAndResponse(
|
||||
"domain_create_fakesite.xml",
|
||||
"domain_create_response_fakesite.xml",
|
||||
"2000-06-01T00:04:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_ok.xml",
|
||||
"2000-06-06T00:00:00Z");
|
||||
}
|
||||
|
||||
// Adds ns3.fakesite.example as a host, then adds it to fakesite.
|
||||
protected void createSubordinateHost() throws Exception {
|
||||
// Add the fakesite nameserver (requires that domain is already created).
|
||||
assertCommandAndResponse(
|
||||
"host_create_fakesite.xml",
|
||||
"host_create_response_fakesite.xml",
|
||||
"2000-06-06T00:01:00Z");
|
||||
// Add new nameserver to domain.
|
||||
assertCommandAndResponse(
|
||||
"domain_update_add_nameserver_fakesite.xml",
|
||||
"domain_update_add_nameserver_response_fakesite.xml",
|
||||
"2000-06-08T00:00:00Z");
|
||||
// Verify new nameserver was added.
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_3_nameservers.xml",
|
||||
"2000-06-08T00:01:00Z");
|
||||
// Verify that nameserver's data was set correctly.
|
||||
assertCommandAndResponse(
|
||||
"host_info_fakesite.xml",
|
||||
"host_info_response_fakesite.xml",
|
||||
"2000-06-08T00:02:00Z");
|
||||
}
|
||||
|
||||
/** For subclasses to further setup the session. */
|
||||
protected void extendedSessionConfig(
|
||||
@SuppressWarnings("unused") String inputFile) throws Exception {}
|
||||
}
|
|
@ -0,0 +1,355 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static com.google.domain.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static com.google.domain.registry.xml.XmlTestUtils.assertXmlEquals;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.domain.registry.model.registry.Registry.TldState;
|
||||
import com.google.domain.registry.util.DateTimeUtils;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
||||
/**
|
||||
* Test setup for EppServletTest subclasses which use XML-based authentication.
|
||||
*
|
||||
* @param <S> The EppXXXServlet class to test.
|
||||
*/
|
||||
public abstract class EppServletXmlLoginTestCase<S extends HttpServlet> extends
|
||||
EppServletTestCase<S> {
|
||||
|
||||
@Test
|
||||
public void testHello() throws Exception {
|
||||
assertXmlEquals(
|
||||
readResourceUtf8(getClass(), "testdata/greeting_crr.xml"),
|
||||
expectXmlCommand(readResourceUtf8(getClass(), "testdata/hello.xml"), DateTime.now(UTC)),
|
||||
"epp.greeting.svDate");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginLogout() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPdtLogin() throws Exception {
|
||||
assertCommandAndResponse("pdt_login.xml", "login_response.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSyntaxError() throws Exception {
|
||||
assertCommandAndResponse("syntax_error.xml", "syntax_error_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContactLifecycle() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_sh8013.xml",
|
||||
ImmutableMap.<String, String>of(),
|
||||
"contact_create_response_sh8013.xml",
|
||||
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
|
||||
"2000-06-01T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"contact_info.xml",
|
||||
"contact_info_from_create_response.xml",
|
||||
"2000-06-01T00:01:00Z");
|
||||
assertCommandAndResponse("contact_delete_sh8013.xml", "contact_delete_response_sh8013.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainDeleteRestore() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
// Create contacts sh8013 and jd1234.
|
||||
assertCommandAndResponse(
|
||||
"contact_create_sh8013.xml",
|
||||
ImmutableMap.<String, String>of(),
|
||||
"contact_create_response_sh8013.xml",
|
||||
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
|
||||
"2000-06-01T00:00:00Z");
|
||||
|
||||
assertCommandAndResponse(
|
||||
"contact_create_jd1234.xml",
|
||||
"contact_create_response_jd1234.xml",
|
||||
"2000-06-01T00:01:00Z");
|
||||
|
||||
// Create domain example.tld.
|
||||
assertCommandAndResponse(
|
||||
"domain_create_no_hosts_or_dsdata.xml",
|
||||
"domain_create_response.xml",
|
||||
"2000-06-01T00:02:00Z");
|
||||
|
||||
// Delete domain example.com after its add grace period has expired.
|
||||
assertCommandAndResponse(
|
||||
"domain_delete.xml",
|
||||
"generic_success_action_pending_response.xml",
|
||||
"2000-07-01T00:02:00Z");
|
||||
|
||||
// Restore the domain.
|
||||
assertCommandAndResponse(
|
||||
"domain_update_restore_request.xml",
|
||||
"domain_update_restore_request_response.xml",
|
||||
"2000-07-01T00:03:00Z");
|
||||
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainDeletion_withinAddGracePeriod() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
|
||||
// Create contacts sh8013 and jd1234.
|
||||
assertCommandAndResponse(
|
||||
"contact_create_sh8013.xml",
|
||||
ImmutableMap.<String, String>of(),
|
||||
"contact_create_response_sh8013.xml",
|
||||
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
|
||||
"2000-06-01T00:00:00Z");
|
||||
|
||||
assertCommandAndResponse(
|
||||
"contact_create_jd1234.xml",
|
||||
"contact_create_response_jd1234.xml",
|
||||
"2000-06-01T00:01:00Z");
|
||||
|
||||
// Create domain example.tld.
|
||||
assertCommandAndResponse(
|
||||
"domain_create_no_hosts_or_dsdata.xml",
|
||||
"domain_create_response.xml",
|
||||
"2000-06-01T00:02:00Z");
|
||||
|
||||
// Delete domain example.tld after its add grace period has expired.
|
||||
assertCommandAndResponse(
|
||||
"domain_delete.xml",
|
||||
"generic_success_action_pending_response.xml",
|
||||
"2000-07-01T00:02:00Z");
|
||||
|
||||
// Poke the domain a little at various times to see its status
|
||||
assertCommandAndResponse(
|
||||
"domain_info.xml",
|
||||
"domain_info_response_pendingdelete.xml",
|
||||
"2000-08-01T00:02:00Z"); // 1 day out.
|
||||
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainDeletionWithSubordinateHost_fails() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
createSubordinateHost();
|
||||
assertCommandAndResponse(
|
||||
"domain_delete_fakesite.xml",
|
||||
"domain_delete_response_prohibited.xml",
|
||||
"2002-05-30T01:01:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletionOfDomain_afterRenameOfSubordinateHost_succeeds() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
createSubordinateHost();
|
||||
// Update the ns3 host to no longer be on fakesite.example domain.
|
||||
assertCommandAndResponse(
|
||||
"host_update_fakesite.xml",
|
||||
"generic_success_response.xml",
|
||||
"2002-05-30T01:01:00Z");
|
||||
// Delete the fakesite.example domain (which should succeed since it no longer has subords).
|
||||
assertCommandAndResponse(
|
||||
"domain_delete_fakesite.xml",
|
||||
"generic_success_action_pending_response.xml",
|
||||
"2002-05-30T01:02:00Z");
|
||||
// Check info on the renamed host and verify that it's still around and wasn't deleted.
|
||||
assertCommandAndResponse(
|
||||
"host_info_ns9000_example.xml",
|
||||
"host_info_response_ns9000_example.xml",
|
||||
"2002-06-30T01:03:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletionOfDomain_afterUpdateThatCreatesSubordinateHost_fails() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
// Update the ns1 host to be on the fakesite.example domain.
|
||||
assertCommandAndResponse(
|
||||
"host_update_ns1_to_fakesite.xml",
|
||||
"generic_success_response.xml",
|
||||
"2002-05-30T01:01:00Z");
|
||||
// Attempt to delete the fakesite.example domain (which should fail since it now has a
|
||||
// subordinate host).
|
||||
assertCommandAndResponse(
|
||||
"domain_delete_fakesite.xml",
|
||||
"domain_delete_response_prohibited.xml",
|
||||
"2002-05-30T01:02:00Z");
|
||||
// Check info on the renamed host and verify that it's still around and wasn't deleted.
|
||||
assertCommandAndResponse(
|
||||
"host_info_fakesite.xml",
|
||||
"host_info_response_fakesite_post_update.xml",
|
||||
"2002-06-30T01:03:00Z");
|
||||
// Verify that fakesite.example domain is still around and wasn't deleted.
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_ok_post_host_update.xml",
|
||||
"2002-05-30T01:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenamingHostToExistingHost_fails() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
// Create the two hosts.
|
||||
assertCommandAndResponse(
|
||||
"host_create.xml",
|
||||
"host_create_response.xml",
|
||||
"2000-06-01T00:02:00Z");
|
||||
assertCommandAndResponse(
|
||||
"host_create2.xml",
|
||||
"host_create2_response.xml",
|
||||
"2000-06-01T00:03:00Z");
|
||||
// Verify that host1 and host2 were created as we expect them.
|
||||
assertCommandAndResponse(
|
||||
"host_info_ns1.xml",
|
||||
"host_info_response_ns1.xml",
|
||||
"2000-06-01T00:04:00Z");
|
||||
assertCommandAndResponse(
|
||||
"host_info_ns2.xml",
|
||||
"host_info_response_ns2.xml",
|
||||
"2000-06-01T00:05:00Z");
|
||||
// Attempt overwriting of host1 on top of host2 (and verify that it fails).
|
||||
assertCommandAndResponse(
|
||||
"host_update_ns1_to_ns2.xml",
|
||||
"host_update_failed_response.xml",
|
||||
"2000-06-01T00:06:00Z");
|
||||
// Verify that host1 and host2 still exist in their unmodified states.
|
||||
assertCommandAndResponse(
|
||||
"host_info_ns1.xml",
|
||||
"host_info_response_ns1.xml",
|
||||
"2000-06-01T00:07:00Z");
|
||||
assertCommandAndResponse(
|
||||
"host_info_ns2.xml",
|
||||
"host_info_response_ns2.xml",
|
||||
"2000-06-01T00:08:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApplicationDuringSunrise_doesntCreateDomainWithoutAllocation() throws Exception {
|
||||
ImmutableSortedMap<DateTime, TldState> transitions = ImmutableSortedMap.of(
|
||||
DateTimeUtils.START_OF_TIME, TldState.SUNRISE,
|
||||
START_OF_GA, TldState.GENERAL_AVAILABILITY);
|
||||
createTld("example", transitions);
|
||||
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createContactsAndHosts();
|
||||
// Note that the trademark is valid from 2013-08-09 to 2017-07-23, hence the domain creation
|
||||
// in 2014.
|
||||
assertCommandAndResponse(
|
||||
"domain_create_sunrise_encoded_mark.xml",
|
||||
"domain_create_sunrise_encoded_signed_mark_response.xml",
|
||||
"2014-01-01T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_testvalidate.xml",
|
||||
"domain_info_response_testvalidate_doesnt_exist.xml",
|
||||
"2014-01-01T00:01:00Z");
|
||||
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainCreation_failsBeforeSunrise() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
|
||||
DateTime sunriseDate = DateTime.parse("2000-05-30T00:00:00Z");
|
||||
ImmutableSortedMap<DateTime, TldState> transitions = ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
sunriseDate, TldState.SUNRISE,
|
||||
sunriseDate.plusMonths(2), TldState.GENERAL_AVAILABILITY);
|
||||
createTld("example", transitions);
|
||||
|
||||
setClientIdentifier("NewRegistrar");
|
||||
createContactsAndHosts();
|
||||
assertCommandAndResponse(
|
||||
"domain_create_sunrise_encoded_mark.xml",
|
||||
"domain_create_testvalidate_invalid_phase.xml",
|
||||
sunriseDate.minusDays(1));
|
||||
|
||||
assertCommandAndResponse(
|
||||
"domain_info_testvalidate.xml",
|
||||
"domain_info_response_testvalidate_doesnt_exist.xml",
|
||||
sunriseDate.plusDays(1));
|
||||
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainCheckFee_succeeds() throws Exception {
|
||||
assertCommandAndResponse("login_valid_fee_extension.xml", "login_response.xml");
|
||||
|
||||
DateTime gaDate = DateTime.parse("2000-05-30T00:00:00Z");
|
||||
ImmutableSortedMap<DateTime, TldState> transitions = ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
gaDate, TldState.GENERAL_AVAILABILITY);
|
||||
createTld("example", transitions);
|
||||
|
||||
assertCommandAndResponse(
|
||||
"domain_check_fee_premium.xml",
|
||||
"domain_check_fee_premium_response.xml",
|
||||
gaDate.plusDays(1));
|
||||
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoteXmlExternalEntity() throws Exception {
|
||||
// Check go/XXE
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_remote_xxe.xml",
|
||||
"contact_create_remote_response_xxe.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalXmlExternalEntity() throws Exception {
|
||||
// Check go/XXE
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_local_xxe.xml",
|
||||
"contact_create_local_response_xxe.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBillionLaughsAttack() throws Exception {
|
||||
// Check go/XXE
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_billion_laughs.xml",
|
||||
"contact_create_response_billion_laughs.xml");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,510 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.CertificateSamples;
|
||||
import com.google.domain.registry.testing.FakeServletInputStream;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** Test setup for EppServletTest subclasses. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EppTlsServletTest extends EppServletXmlLoginTestCase<EppTlsServlet> {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
String ipAddressAndPort = "192.168.1.100:54321";
|
||||
String clientCert = CertificateSamples.SAMPLE_CERT_HASH;
|
||||
String clientCert2 = CertificateSamples.SAMPLE_CERT2_HASH;
|
||||
String requestedServername = "test.example";
|
||||
|
||||
private String gfeRequestClientCertificateHashField;
|
||||
|
||||
@Before
|
||||
public void initTest() throws Exception {
|
||||
persistResource(Registrar.loadByClientId("NewRegistrar")
|
||||
.asBuilder()
|
||||
.setClientCertificateHash(clientCert)
|
||||
.build());
|
||||
|
||||
persistResource(Registrar.loadByClientId("TheRegistrar")
|
||||
.asBuilder()
|
||||
.setClientCertificateHash(clientCert2)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetTldViaSni() throws Exception {
|
||||
requestedServername = "epp.nic.xn--q9jyb4c";
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_sh8013.xml",
|
||||
ImmutableMap.<String, String>of(),
|
||||
"contact_create_response_sh8013.xml",
|
||||
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
|
||||
"2000-06-01T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_create_minna.xml",
|
||||
"domain_create_response_minna.xml",
|
||||
"2000-06-01T01:02:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
/** This test requires multiple registrars, which EppConsoleServlet doesn't allow. */
|
||||
@Test
|
||||
public void testContactTransferPollMessage() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_create_sh8013.xml",
|
||||
ImmutableMap.<String, String>of(),
|
||||
"contact_create_response_sh8013.xml",
|
||||
ImmutableMap.of("CRDATE", "2000-06-01T00:00:00Z"),
|
||||
"2000-06-01T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Initiate a transfer of the newly created contact.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"contact_transfer_request.xml",
|
||||
"contact_transfer_request_response_alternate.xml",
|
||||
"2000-06-08T22:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Log back in with the losing registrar, read the poll message, and then ack it.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"poll.xml",
|
||||
"poll_response_contact_transfer.xml",
|
||||
"2000-06-08T22:01:00Z");
|
||||
assertCommandAndResponse(
|
||||
"poll_ack.xml",
|
||||
ImmutableMap.of("ID", "2-4-ROID-6-7"),
|
||||
"poll_ack_response_empty.xml",
|
||||
null,
|
||||
"2000-06-08T22:02:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
/** This test requires multiple registrars, which EppConsoleServlet doesn't allow. */
|
||||
@Test
|
||||
public void testDomainTransferPollMessage_serverApproved() throws Exception {
|
||||
// As the losing registrar, create the domain.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// As the winning registrar, request a transfer. Capture the server trid; we'll need it later.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
String response = assertCommandAndResponse(
|
||||
"domain_transfer_request_1_year.xml",
|
||||
"domain_transfer_response_1_year.xml",
|
||||
"2001-01-01T00:00:00Z");
|
||||
Matcher matcher = Pattern.compile("<svTRID>(.*)</svTRID>").matcher(response);
|
||||
matcher.find();
|
||||
String transferRequestTrid = matcher.group(1);
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// As the losing registrar, read the request poll message, and then ack it.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"poll.xml",
|
||||
"poll_response_domain_transfer_request.xml",
|
||||
"2001-01-01T00:01:00Z");
|
||||
assertCommandAndResponse(
|
||||
"poll_ack.xml",
|
||||
ImmutableMap.of("ID", "1-C-EXAMPLE-18-22"),
|
||||
"poll_ack_response_empty.xml",
|
||||
null,
|
||||
"2001-01-01T00:01:00Z");
|
||||
|
||||
// Five days in the future, expect a server approval poll message to the loser, and ack it.
|
||||
assertCommandAndResponse(
|
||||
"poll.xml",
|
||||
"poll_response_domain_transfer_server_approve_loser.xml",
|
||||
"2001-01-06T00:01:00Z");
|
||||
assertCommandAndResponse(
|
||||
"poll_ack.xml",
|
||||
ImmutableMap.of("ID", "1-C-EXAMPLE-18-24"),
|
||||
"poll_ack_response_empty.xml",
|
||||
null,
|
||||
"2001-01-06T00:01:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Also expect a server approval poll message to the winner, with the transfer request trid.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"poll.xml",
|
||||
null,
|
||||
"poll_response_domain_transfer_server_approve_winner.xml",
|
||||
ImmutableMap.of("SERVER_TRID", transferRequestTrid),
|
||||
"2001-01-06T00:02:00Z");
|
||||
assertCommandAndResponse(
|
||||
"poll_ack.xml",
|
||||
ImmutableMap.of("ID", "1-C-EXAMPLE-18-23"),
|
||||
"poll_ack_response_empty.xml",
|
||||
null,
|
||||
"2001-01-06T00:02:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendedSessionConfig(String inputFile) throws Exception {
|
||||
when(req.getHeader(EppTlsServlet.REQUESTED_SERVERNAME_VIA_SNI_FIELD))
|
||||
.thenReturn(requestedServername);
|
||||
when(req.getHeader(EppTlsServlet.FORWARDED_FOR_FIELD))
|
||||
.thenReturn(ipAddressAndPort);
|
||||
if (gfeRequestClientCertificateHashField != null) {
|
||||
when(req.getHeader(EppTlsServlet.SSL_CLIENT_CERTIFICATE_HASH_FIELD))
|
||||
.thenReturn(gfeRequestClientCertificateHashField);
|
||||
} else {
|
||||
when(req.getHeader(EppTlsServlet.SSL_CLIENT_CERTIFICATE_HASH_FIELD))
|
||||
.thenReturn(inputFile.contains("TheRegistrar") ? clientCert2 : clientCert);
|
||||
}
|
||||
when(req.getInputStream()).thenReturn(new FakeServletInputStream(inputFile.getBytes(UTF_8)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIgnoredTransferDuringAutoRenewPeriod_succeeds() throws Exception {
|
||||
// Register the domain as the first registrar.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Request a transfer of the domain to the second registrar.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_request_2_years.xml",
|
||||
"domain_transfer_response_2_years.xml",
|
||||
"2002-05-30T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Log back in as the first registrar and verify things.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_pending_transfer.xml",
|
||||
"2002-05-30T01:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_pending_transfer_autorenew.xml",
|
||||
"2002-06-02T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Log back in as the second registrar and verify transfer details.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
// Verify that domain is in the transfer period now with expiration date two years out.
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_transfer_period.xml",
|
||||
"2002-06-06T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_transfer_complete.xml",
|
||||
"2002-06-12T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadCertificate_failsBadCertificate2200() throws Exception {
|
||||
gfeRequestClientCertificateHashField = "laffo";
|
||||
assertCommandAndResponse("login_valid.xml", "login_response_bad_certificate.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGfeDidntProvideClientCertificate_failsMissingCertificate2200() throws Exception {
|
||||
gfeRequestClientCertificateHashField = "";
|
||||
assertCommandAndResponse("login_valid.xml", "login_response_missing_certificate.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoodPrimaryCertificate() throws Exception {
|
||||
gfeRequestClientCertificateHashField = CertificateSamples.SAMPLE_CERT_HASH;
|
||||
persistResource(Registrar.loadByClientId("NewRegistrar").asBuilder()
|
||||
.setClientCertificate(CertificateSamples.SAMPLE_CERT, clock.nowUtc())
|
||||
.setFailoverClientCertificate(CertificateSamples.SAMPLE_CERT2, clock.nowUtc())
|
||||
.build());
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGoodFailoverCertificate() throws Exception {
|
||||
gfeRequestClientCertificateHashField = CertificateSamples.SAMPLE_CERT2_HASH;
|
||||
persistResource(Registrar.loadByClientId("NewRegistrar").asBuilder()
|
||||
.setClientCertificate(CertificateSamples.SAMPLE_CERT, clock.nowUtc())
|
||||
.setFailoverClientCertificate(CertificateSamples.SAMPLE_CERT2, clock.nowUtc())
|
||||
.build());
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingPrimaryCertificateButHasFailover_usesFailover() throws Exception {
|
||||
gfeRequestClientCertificateHashField = CertificateSamples.SAMPLE_CERT2_HASH;
|
||||
persistResource(Registrar.loadByClientId("NewRegistrar").asBuilder()
|
||||
.setClientCertificate(null, clock.nowUtc())
|
||||
.setFailoverClientCertificate(CertificateSamples.SAMPLE_CERT2, clock.nowUtc())
|
||||
.build());
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegistrarHasNoCertificatesOnFile_disablesCertChecking() throws Exception {
|
||||
gfeRequestClientCertificateHashField = "laffo";
|
||||
persistResource(Registrar.loadByClientId("NewRegistrar").asBuilder()
|
||||
.setClientCertificate(null, clock.nowUtc())
|
||||
.setFailoverClientCertificate(null, clock.nowUtc())
|
||||
.build());
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNameserversTransferWithDomain_successfully() throws Exception {
|
||||
// Log in as the first registrar and set up domains with hosts.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
createSubordinateHost();
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Request a transfer of the domain to the second registrar.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_request_2_years.xml",
|
||||
"domain_transfer_response_2_years.xml",
|
||||
"2002-05-30T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Log back in as the first registrar and verify domain is pending transfer.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_3_nameservers_pending_transfer.xml",
|
||||
"2002-05-30T01:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Log back in as second registrar and verify transfer was successful.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
// Expect transfer complete with all three nameservers on it.
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_3_nameservers_transfer_successful.xml",
|
||||
"2002-06-09T00:00:00Z");
|
||||
// Verify that host's client ID was set to the new registrar and has the transfer date set.
|
||||
assertCommandAndResponse(
|
||||
"host_info_fakesite.xml",
|
||||
null,
|
||||
"host_info_response_fakesite_post_transfer.xml",
|
||||
ImmutableMap.of("trDate", "2002-06-04T00:00:00Z"),
|
||||
"2002-06-09T00:01:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainDeletionCancelsPendingTransfer() throws Exception {
|
||||
// Register the domain as the first registrar.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Request a transfer of the domain to the second registrar.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_request_2_years.xml",
|
||||
"domain_transfer_response_2_years.xml",
|
||||
"2002-05-30T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Log back in as the first registrar and delete then restore the domain while the transfer
|
||||
// is still pending.
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_pending_transfer.xml",
|
||||
"2002-05-30T01:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_delete_fakesite.xml",
|
||||
"generic_success_action_pending_response.xml",
|
||||
"2002-05-30T01:01:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_pending_delete.xml",
|
||||
"2002-05-30T01:02:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_update_restore_fakesite.xml",
|
||||
"domain_update_restore_request_response.xml",
|
||||
"2002-05-30T01:03:00Z");
|
||||
|
||||
// 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.)
|
||||
assertCommandAndResponse(
|
||||
"domain_info_fakesite.xml",
|
||||
"domain_info_response_fakesite_restored_ok.xml",
|
||||
"2002-05-30T01:04:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainTransfer_subordinateHost_showsChangeInTransferQuery() throws Exception {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
createFakesite();
|
||||
createSubordinateHost();
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_query_fakesite.xml",
|
||||
"domain_transfer_query_response_no_transfer_history.xml",
|
||||
"2000-09-02T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
// Request a transfer of the domain to the second registrar.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_request_1_year.xml",
|
||||
"domain_transfer_response_1_year.xml",
|
||||
"2001-01-01T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
// Verify that reID is set correctly.
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_query_fakesite.xml",
|
||||
"domain_transfer_query_response_fakesite.xml",
|
||||
"2001-01-02T00:00:00Z");
|
||||
// Verify that status went from 'pending' to 'serverApproved'.
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_query_fakesite.xml",
|
||||
"domain_transfer_query_response_completed_fakesite.xml",
|
||||
"2001-01-08T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
// Create fakesite.example with subordinate host ns3.fakesite.example
|
||||
createFakesite();
|
||||
createSubordinateHost();
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_query_fakesite.xml",
|
||||
"domain_transfer_query_response_no_transfer_history.xml",
|
||||
"2000-09-02T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
// Request a transfer of the domain to the second registrar.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_request_1_year.xml",
|
||||
"domain_transfer_response_1_year.xml",
|
||||
"2001-01-01T00:00:00Z");
|
||||
// Verify that the lastTransferTime now reflects the superordinate domain's transfer.
|
||||
assertCommandAndResponse(
|
||||
"host_info.xml",
|
||||
ImmutableMap.of("hostname", "ns3.fakesite.example"),
|
||||
"host_info_response_fakesite_post_transfer.xml",
|
||||
ImmutableMap.of("trDate", "2001-01-06T00:00:00.000Z"),
|
||||
"2001-01-07T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_create_secondsite.xml",
|
||||
"domain_create_response_secondsite.xml",
|
||||
"2001-01-08T00:00:00Z");
|
||||
// Update the host to be subordinate to a different domain by renaming it to
|
||||
// ns3.secondsite.example
|
||||
assertCommandAndResponse(
|
||||
"host_update_rename_only.xml",
|
||||
ImmutableMap.of("oldName", "ns3.fakesite.example", "newName", "ns3.secondsite.example"),
|
||||
"generic_success_response.xml",
|
||||
null,
|
||||
"2002-05-30T01:01:00Z");
|
||||
// The last transfer time on the host should still be what it was from the transfer.
|
||||
assertCommandAndResponse(
|
||||
"host_info.xml",
|
||||
ImmutableMap.of("hostname", "ns3.secondsite.example"),
|
||||
"host_info_response_fakesite_post_transfer_and_update.xml",
|
||||
ImmutableMap.of(
|
||||
"hostname", "ns3.secondsite.example",
|
||||
"trDate", "2001-01-06T00:00:00.000Z"),
|
||||
"2003-01-07T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
assertCommandAndResponse("login_valid.xml", "login_response.xml");
|
||||
// Create fakesite.example with subordinate host ns3.fakesite.example
|
||||
createFakesite();
|
||||
createSubordinateHost();
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_query_fakesite.xml",
|
||||
"domain_transfer_query_response_no_transfer_history.xml",
|
||||
"2000-09-02T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
// Request a transfer of the domain to the second registrar.
|
||||
assertCommandAndResponse("login2_valid.xml", "login_response.xml");
|
||||
assertCommandAndResponse(
|
||||
"domain_transfer_request_1_year.xml",
|
||||
"domain_transfer_response_1_year.xml",
|
||||
"2001-01-01T00:00:00Z");
|
||||
// Verify that the lastTransferTime now reflects the superordinate domain's transfer.
|
||||
assertCommandAndResponse(
|
||||
"host_info_fakesite.xml",
|
||||
null,
|
||||
"host_info_response_fakesite_post_transfer.xml",
|
||||
ImmutableMap.of("trDate", "2001-01-06T00:00:00.000Z"),
|
||||
"2001-01-07T00:00:00Z");
|
||||
// Update the host to be external by renaming it to ns3.notarealsite.external
|
||||
assertCommandAndResponse(
|
||||
"host_update_rename_and_remove_addresses.xml",
|
||||
ImmutableMap.of(
|
||||
"oldName", "ns3.fakesite.example",
|
||||
"newName", "ns3.notarealsite.external"),
|
||||
"generic_success_response.xml",
|
||||
null,
|
||||
"2002-05-30T01:01:00Z");
|
||||
// The last transfer time on the host should still be what it was from the transfer.
|
||||
assertCommandAndResponse(
|
||||
"host_info.xml",
|
||||
ImmutableMap.of("hostname", "ns3.notarealsite.external"),
|
||||
"host_info_response_fakesite_post_transfer_and_update_no_addresses.xml",
|
||||
ImmutableMap.of(
|
||||
"hostname", "ns3.notarealsite.external",
|
||||
"trDate", "2001-01-06T00:00:00.000Z"),
|
||||
"2001-01-07T00:00:00Z");
|
||||
assertCommandAndResponse("logout.xml", "logout_response.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.RegistrarContact;
|
||||
import com.google.domain.registry.model.registry.Registry.TldState;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.UserInfo;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
/** Tests for {@link EppToolServlet}. */
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class EppToolServletTest extends EppServletTestCase<EppToolServlet> {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.withUserService(UserInfo.createAdmin(GAE_USER_EMAIL, GAE_USER_ID))
|
||||
.build();
|
||||
|
||||
private static final String GAE_USER_ID = "12345";
|
||||
private static final String GAE_USER_EMAIL = "person@example.com";
|
||||
|
||||
@Before
|
||||
public void initTest() throws Exception {
|
||||
Registrar registrar = Registrar.loadByClientId("NewRegistrar");
|
||||
persistResource(
|
||||
new RegistrarContact.Builder()
|
||||
.setParent(registrar)
|
||||
.setEmailAddress(GAE_USER_EMAIL)
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.ADMIN))
|
||||
.setGaeUserId(GAE_USER_ID)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainAllocation_succeedsOnlyAsSuperuser() throws Exception {
|
||||
ImmutableSortedMap<DateTime, TldState> transitions = ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.SUNRISE,
|
||||
START_OF_GA, TldState.GENERAL_AVAILABILITY);
|
||||
createTld("example", transitions);
|
||||
|
||||
setClientIdentifier("NewRegistrar");
|
||||
setSuperuser(false);
|
||||
createContactsAndHosts();
|
||||
// Note that the trademark is valid from 20130809 to 20170723, hence the domain creation
|
||||
// in 2014.
|
||||
assertCommandAndResponse(
|
||||
"domain_create_sunrise_encoded_mark.xml",
|
||||
"domain_create_sunrise_encoded_signed_mark_response.xml",
|
||||
"2014-01-01T00:00:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_info_testvalidate.xml",
|
||||
"domain_info_response_testvalidate_doesnt_exist.xml",
|
||||
"2014-01-01T00:01:00Z");
|
||||
assertCommandAndResponse(
|
||||
"domain_allocate_testvalidate.xml",
|
||||
"domain_allocate_response_testvalidate_only_superuser.xml",
|
||||
START_OF_GA.plusDays(1));
|
||||
setSuperuser(true);
|
||||
assertCommandAndResponse(
|
||||
"domain_allocate_testvalidate.xml",
|
||||
"domain_allocate_response_testvalidate.xml",
|
||||
START_OF_GA.plusDays(1).plusMinutes(1));
|
||||
setSuperuser(false);
|
||||
assertCommandAndResponse(
|
||||
"domain_info_testvalidate.xml",
|
||||
"domain_info_response_testvalidate_ok.xml",
|
||||
START_OF_GA.plusDays(1).plusMinutes(2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainCreation_failsBeforeSunrise() throws Exception {
|
||||
DateTime sunriseDate = DateTime.parse("2000-05-30T00:00:00Z");
|
||||
ImmutableSortedMap<DateTime, TldState> transitions = ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
sunriseDate, TldState.SUNRISE,
|
||||
sunriseDate.plusMonths(2), TldState.GENERAL_AVAILABILITY);
|
||||
createTld("example", transitions);
|
||||
|
||||
setClientIdentifier("NewRegistrar");
|
||||
createContactsAndHosts();
|
||||
assertCommandAndResponse(
|
||||
"domain_create_sunrise_encoded_mark.xml",
|
||||
"domain_create_testvalidate_invalid_phase.xml",
|
||||
sunriseDate.minusDays(1));
|
||||
assertCommandAndResponse(
|
||||
"domain_info_testvalidate.xml",
|
||||
"domain_info_response_testvalidate_doesnt_exist.xml",
|
||||
sunriseDate.plusDays(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDomainCheckFee_succeeds() throws Exception {
|
||||
DateTime gaDate = DateTime.parse("2000-05-30T00:00:00Z");
|
||||
ImmutableSortedMap<DateTime, TldState> transitions = ImmutableSortedMap.of(
|
||||
START_OF_TIME, TldState.PREDELEGATION,
|
||||
gaDate, TldState.GENERAL_AVAILABILITY);
|
||||
createTld("example", transitions);
|
||||
|
||||
setClientIdentifier("NewRegistrar");
|
||||
assertCommandAndResponse(
|
||||
"domain_check_fee_premium.xml",
|
||||
"domain_check_fee_premium_response.xml",
|
||||
gaDate.plusDays(1));
|
||||
}
|
||||
|
||||
// Extra method so the test runner doesn't produce empty shards.
|
||||
@Test public void testNothing1() {}
|
||||
}
|
311
javatests/com/google/domain/registry/flows/FlowTestCase.java
Normal file
311
javatests/com/google/domain/registry/flows/FlowTestCase.java
Normal file
|
@ -0,0 +1,311 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.collect.Sets.difference;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.flows.EppXmlTransformer.marshal;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.BILLING_EVENT_ID_STRIPPER;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getPollMessages;
|
||||
import static com.google.domain.registry.util.ResourceUtils.readResourceUtf8;
|
||||
import static com.google.domain.registry.xml.XmlTestUtils.assertXmlEquals;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.domain.registry.flows.FlowRunner.CommitMode;
|
||||
import com.google.domain.registry.flows.FlowRunner.UserPrivileges;
|
||||
import com.google.domain.registry.flows.SessionMetadata.SessionSource;
|
||||
import com.google.domain.registry.model.billing.BillingEvent;
|
||||
import com.google.domain.registry.model.domain.GracePeriod;
|
||||
import com.google.domain.registry.model.domain.rgp.GracePeriodStatus;
|
||||
import com.google.domain.registry.model.eppcommon.ProtocolDefinition;
|
||||
import com.google.domain.registry.model.eppcommon.Trid;
|
||||
import com.google.domain.registry.model.eppinput.EppInput;
|
||||
import com.google.domain.registry.model.eppoutput.EppOutput;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.poll.PollMessage;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.tmch.ClaimsListShard.ClaimsListSingleton;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.EppLoader;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.TestSessionMetadata;
|
||||
import com.google.domain.registry.util.TypeUtils.TypeInstantiator;
|
||||
import com.google.domain.registry.xml.ValidationMode;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Base class for resource flow unit tests.
|
||||
*
|
||||
* @param <F> the flow type
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public abstract class FlowTestCase<F extends Flow> {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withTaskQueue()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
private FlowRunner flowRunner;
|
||||
|
||||
protected EppLoader eppLoader;
|
||||
protected Class<? extends Flow> flowClass;
|
||||
protected SessionMetadata sessionMetadata;
|
||||
protected FakeClock clock = new FakeClock(DateTime.now(UTC));
|
||||
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
flowRunner = null;
|
||||
sessionMetadata = new TestSessionMetadata();
|
||||
sessionMetadata.setClientId("TheRegistrar");
|
||||
sessionMetadata.setServiceExtensionUris(ProtocolDefinition.getVisibleServiceExtensionUris());
|
||||
sessionMetadata.setSessionSource(SessionSource.NONE);
|
||||
ofy().saveWithoutBackup().entity(new ClaimsListSingleton()).now();
|
||||
inject.setStaticField(Ofy.class, "clock", clock); // For transactional flows.
|
||||
inject.setStaticField(FlowRunner.class, "clock", clock); // For non-transactional flows.
|
||||
}
|
||||
|
||||
protected void removeServiceExtensionUri(String uri) {
|
||||
sessionMetadata.setServiceExtensionUris(
|
||||
difference(sessionMetadata.getServiceExtensionUris(), ImmutableSet.of(uri)));
|
||||
}
|
||||
|
||||
protected void setEppInput(String inputFilename) {
|
||||
eppLoader = new EppLoader(this, inputFilename, ImmutableMap.<String, String>of());
|
||||
}
|
||||
|
||||
protected void setEppInput(String inputFilename, Map<String, String> substitutions) {
|
||||
eppLoader = new EppLoader(this, inputFilename, substitutions);
|
||||
}
|
||||
|
||||
protected String readFile(String filename) {
|
||||
return readResourceUtf8(getClass(), "testdata/" + filename);
|
||||
}
|
||||
|
||||
/** Lazily load the flow, since it may fail to initialize if the environment isn't set up yet. */
|
||||
public FlowRunner getFlowRunner() throws Exception {
|
||||
if (flowRunner == null) {
|
||||
flowRunner = createFlowRunner();
|
||||
}
|
||||
return flowRunner;
|
||||
}
|
||||
|
||||
/** Load a flow from an epp object. */
|
||||
private FlowRunner createFlowRunner() throws Exception {
|
||||
EppInput eppInput = eppLoader.getEpp();
|
||||
flowClass = firstNonNull(flowClass, FlowRegistry.getFlowClass(eppInput));
|
||||
Class<?> expectedFlowClass = new TypeInstantiator<F>(getClass()){}.getExactType();
|
||||
assertThat(flowClass).isEqualTo(expectedFlowClass);
|
||||
return new FlowRunner(
|
||||
flowClass,
|
||||
eppInput,
|
||||
getTrid(),
|
||||
sessionMetadata,
|
||||
"<xml></xml>".getBytes(),
|
||||
null);
|
||||
}
|
||||
|
||||
protected Trid getTrid() throws Exception {
|
||||
return Trid.create(eppLoader.getEpp().getCommandWrapper().getClTrid(), "server-trid");
|
||||
}
|
||||
|
||||
/** Gets the client ID that the flow will run as. */
|
||||
protected String getClientIdForFlow() {
|
||||
return sessionMetadata.getClientId();
|
||||
}
|
||||
|
||||
/** Sets the client ID that the flow will run as. */
|
||||
protected void setClientIdForFlow(String clientId) {
|
||||
sessionMetadata.setClientId(clientId);
|
||||
}
|
||||
|
||||
public void assertTransactionalFlow(boolean isTransactional) throws Exception {
|
||||
assertThat(getFlowRunner().isTransactional()).isEqualTo(isTransactional);
|
||||
}
|
||||
|
||||
public void assertNoHistory() throws Exception {
|
||||
assertThat(ofy().load().type(HistoryEntry.class)).isEmpty();
|
||||
}
|
||||
|
||||
public <T> T getOnlyGlobalResource(Class<T> clazz) throws Exception {
|
||||
return Iterables.getOnlyElement(ofy().load().type(clazz));
|
||||
}
|
||||
|
||||
/** Helper to remove the grace period's billing event key to facilitate comparison. */
|
||||
private static final Function<GracePeriod, GracePeriod> GRACE_PERIOD_KEY_STRIPPER =
|
||||
new Function<GracePeriod, GracePeriod>() {
|
||||
@Override
|
||||
public GracePeriod apply(GracePeriod gracePeriod) {
|
||||
return GracePeriod.create(
|
||||
gracePeriod.isSunrushAddGracePeriod()
|
||||
? GracePeriodStatus.SUNRUSH_ADD
|
||||
: gracePeriod.getType(),
|
||||
gracePeriod.getExpirationTime(),
|
||||
gracePeriod.getClientId(),
|
||||
null);
|
||||
}};
|
||||
|
||||
/** A helper class that sets the billing event parent history entry to facilitate comparison. */
|
||||
public static class BillingEventParentSetter implements Function<BillingEvent, BillingEvent> {
|
||||
private HistoryEntry historyEntry;
|
||||
|
||||
public static BillingEventParentSetter withParent(HistoryEntry historyEntry) {
|
||||
BillingEventParentSetter instance = new BillingEventParentSetter();
|
||||
instance.historyEntry = historyEntry;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BillingEvent apply(BillingEvent billingEvent) {
|
||||
return billingEvent.asBuilder().setParent(historyEntry).build();
|
||||
}
|
||||
|
||||
private BillingEventParentSetter() {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to facilitate comparison of maps of GracePeriods to BillingEvents. This takes a map of
|
||||
* GracePeriods to BillingEvents and returns a map of the same entries that ignores the keys
|
||||
* on the grace periods and the IDs on the billing events (by setting them all to the same dummy
|
||||
* values), since they will vary between instantiations even when the other data is the same.
|
||||
*/
|
||||
private ImmutableMap<GracePeriod, BillingEvent>
|
||||
canonicalizeGracePeriods(ImmutableMap<GracePeriod, ? extends BillingEvent> gracePeriods) {
|
||||
ImmutableMap.Builder<GracePeriod, BillingEvent> builder = new ImmutableMap.Builder<>();
|
||||
for (Map.Entry<GracePeriod, ? extends BillingEvent> entry : gracePeriods.entrySet()) {
|
||||
builder.put(
|
||||
GRACE_PERIOD_KEY_STRIPPER.apply(entry.getKey()),
|
||||
BILLING_EVENT_ID_STRIPPER.apply(entry.getValue()));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the actual grace periods and the corresponding billing events referenced from
|
||||
* their keys match the expected map of grace periods to billing events. For the expected map,
|
||||
* the keys on the grace periods and IDs on the billing events are ignored.
|
||||
*/
|
||||
public void assertGracePeriods(
|
||||
Iterable<GracePeriod> actual,
|
||||
ImmutableMap<GracePeriod, ? extends BillingEvent> expected) {
|
||||
Function<GracePeriod, BillingEvent> gracePeriodExpander =
|
||||
new Function<GracePeriod, BillingEvent>() {
|
||||
@Override
|
||||
public BillingEvent apply(GracePeriod gracePeriod) {
|
||||
return gracePeriod.getBillingEvent().get();
|
||||
}};
|
||||
assertThat(canonicalizeGracePeriods(Maps.toMap(actual, gracePeriodExpander)))
|
||||
.isEqualTo(canonicalizeGracePeriods(expected));
|
||||
}
|
||||
|
||||
public void assertPollMessages(
|
||||
String clientId,
|
||||
PollMessage... expected) throws Exception {
|
||||
assertPollMessagesHelper(getPollMessages(clientId), expected);
|
||||
}
|
||||
|
||||
public void assertPollMessages(
|
||||
String clientId,
|
||||
DateTime now,
|
||||
PollMessage... expected) throws Exception {
|
||||
assertPollMessagesHelper(getPollMessages(clientId, now), expected);
|
||||
}
|
||||
|
||||
public void assertPollMessages(PollMessage... expected) throws Exception {
|
||||
assertPollMessagesHelper(getPollMessages(), expected);
|
||||
}
|
||||
|
||||
/** Assert that the list matches all the poll messages in the fake datastore. */
|
||||
public void assertPollMessagesHelper(Iterable<PollMessage> pollMessages, PollMessage... expected)
|
||||
throws Exception {
|
||||
// To facilitate comparison, remove the ids.
|
||||
Function<PollMessage, PollMessage> idStripper =
|
||||
new Function<PollMessage, PollMessage>() {
|
||||
@Override
|
||||
public PollMessage apply(PollMessage pollMessage) {
|
||||
return pollMessage.asBuilder().setId(1L).build();
|
||||
}};
|
||||
// Ordering is irrelevant but duplicates should be considered independently.
|
||||
assertThat(FluentIterable.from(pollMessages).transform(idStripper))
|
||||
.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. */
|
||||
public EppOutput runFlow(CommitMode commitMode, UserPrivileges userPrivileges) throws Exception {
|
||||
EppOutput output = getFlowRunner().run(commitMode, userPrivileges);
|
||||
marshal(output, ValidationMode.STRICT);
|
||||
return output;
|
||||
}
|
||||
|
||||
public EppOutput runFlow() throws Exception {
|
||||
return runFlow(CommitMode.LIVE, UserPrivileges.NORMAL);
|
||||
}
|
||||
|
||||
public void runFlowAssertResponse(
|
||||
CommitMode commitMode, UserPrivileges userPrivileges, String xml, String... ignoredPaths)
|
||||
throws Exception {
|
||||
EppOutput eppOutput = getFlowRunner().run(commitMode, userPrivileges);
|
||||
assertThat(eppOutput.isSuccess()).isTrue();
|
||||
try {
|
||||
assertXmlEquals(
|
||||
xml, new String(marshal(eppOutput, ValidationMode.STRICT), UTF_8), ignoredPaths);
|
||||
} catch (Throwable e) {
|
||||
assertXmlEquals(
|
||||
xml, new String(marshal(eppOutput, ValidationMode.LENIENT), UTF_8), ignoredPaths);
|
||||
// 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)),
|
||||
e);
|
||||
}
|
||||
// Clear the cache so that we don't see stale results in tests.
|
||||
ofy().clearSessionCache();
|
||||
}
|
||||
|
||||
public void dryRunFlowAssertResponse(String xml, String... ignoredPaths) throws Exception {
|
||||
List<Object> beforeEntities = ofy().load().list();
|
||||
runFlowAssertResponse(CommitMode.DRY_RUN, UserPrivileges.NORMAL, xml, ignoredPaths);
|
||||
assertThat(ofy().load()).containsExactlyElementsIn(beforeEntities);
|
||||
}
|
||||
|
||||
public void runFlowAssertResponse(String xml, String... ignoredPaths) throws Exception {
|
||||
runFlowAssertResponse(CommitMode.LIVE, UserPrivileges.NORMAL, xml, ignoredPaths);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
|
||||
import com.google.domain.registry.model.EppResource;
|
||||
import com.google.domain.registry.model.eppoutput.CheckData;
|
||||
|
||||
/**
|
||||
* Base class for resource check flow unit tests.
|
||||
*
|
||||
* @param <F> the flow type
|
||||
* @param <R> the resource type
|
||||
*/
|
||||
public class ResourceCheckFlowTestCase<F extends Flow, R extends EppResource>
|
||||
extends ResourceFlowTestCase<F, R> {
|
||||
|
||||
protected void doCheckTest(CheckData.Check... expected) throws Exception {
|
||||
assertTransactionalFlow(false);
|
||||
assertThat(expected).asList().containsExactlyElementsIn(
|
||||
((CheckData) runFlow().getResponse().getResponseData().get(0)).getChecks());
|
||||
assertNoHistory(); // Checks don't create a history event.
|
||||
assertNoBillingEvents(); // Checks are always free.
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.EppResourceUtils.loadByUniqueId;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.model.tmch.ClaimsListShardTest.createTestClaimsListShard;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.flows.EppException.CommandUseErrorException;
|
||||
import com.google.domain.registry.model.EppResource;
|
||||
import com.google.domain.registry.model.domain.launch.ApplicationIdTargetExtension;
|
||||
import com.google.domain.registry.model.eppinput.EppInput.ResourceCommandWrapper;
|
||||
import com.google.domain.registry.model.eppinput.ResourceCommand;
|
||||
import com.google.domain.registry.model.index.EppResourceIndex;
|
||||
import com.google.domain.registry.model.index.EppResourceIndexBucket;
|
||||
import com.google.domain.registry.model.tmch.ClaimsListShard.ClaimsListRevision;
|
||||
import com.google.domain.registry.model.tmch.ClaimsListShard.ClaimsListSingleton;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.util.TypeUtils.TypeInstantiator;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Base class for resource flow unit tests.
|
||||
*
|
||||
* @param <F> the flow type
|
||||
* @param <R> the resource type
|
||||
*/
|
||||
public abstract class ResourceFlowTestCase<F extends Flow, R extends EppResource>
|
||||
extends FlowTestCase<F> {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
private R reloadResourceByUniqueId(DateTime now) throws Exception {
|
||||
// Force the session to be cleared so that when we read it back, we read from the datastore and
|
||||
// not from the transaction cache or memcache.
|
||||
ofy().clearSessionCache();
|
||||
return loadByUniqueId(getResourceClass(), getUniqueIdFromCommand(), now);
|
||||
}
|
||||
|
||||
protected R reloadResourceByUniqueId() throws Exception {
|
||||
return reloadResourceByUniqueId(clock.nowUtc());
|
||||
}
|
||||
|
||||
protected R reloadResourceByUniqueIdYesterday() throws Exception {
|
||||
return reloadResourceByUniqueId(clock.nowUtc().minusDays(1));
|
||||
}
|
||||
|
||||
protected <T extends EppResource> T reloadResourceAndCloneAtTime(T resource, DateTime now) {
|
||||
// Force the session to be cleared.
|
||||
ofy().clearSessionCache();
|
||||
@SuppressWarnings("unchecked")
|
||||
T refreshedResource = (T) ofy().load().entity(resource).now().cloneProjectedAtTime(now);
|
||||
return refreshedResource;
|
||||
}
|
||||
|
||||
protected ResourceCommand.SingleResourceCommand getResourceCommand() throws Exception {
|
||||
return (ResourceCommand.SingleResourceCommand)
|
||||
((ResourceCommandWrapper) eppLoader.getEpp().getCommandWrapper().getCommand())
|
||||
.getResourceCommand();
|
||||
}
|
||||
|
||||
/**
|
||||
* We have to duplicate the logic from SingleResourceFlow.getTargetId() here. However, given the
|
||||
* choice between making that method public, and duplicating its logic, it seems better to muddy
|
||||
* the test code rather than the production code.
|
||||
*/
|
||||
protected String getUniqueIdFromCommand() throws Exception {
|
||||
ApplicationIdTargetExtension extension =
|
||||
eppLoader.getEpp().getSingleExtension(ApplicationIdTargetExtension.class);
|
||||
return extension == null ? getResourceCommand().getTargetId() : extension.getApplicationId();
|
||||
}
|
||||
|
||||
protected Class<R> getResourceClass() {
|
||||
return new TypeInstantiator<R>(getClass()){}.getExactType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists a testing claims list to Datastore that contains a single shard.
|
||||
*/
|
||||
protected void persistClaimsList(ImmutableMap<String, String> labelsToKeys) {
|
||||
ClaimsListSingleton singleton = new ClaimsListSingleton();
|
||||
Key<ClaimsListRevision> revision = ClaimsListRevision.createKey(singleton);
|
||||
singleton.setActiveRevision(revision);
|
||||
ofy().saveWithoutBackup().entity(singleton).now();
|
||||
if (!labelsToKeys.isEmpty()) {
|
||||
ofy().saveWithoutBackup()
|
||||
.entity(createTestClaimsListShard(clock.nowUtc(), labelsToKeys, revision))
|
||||
.now();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiresLogin() throws Exception {
|
||||
thrown.expect(CommandUseErrorException.class);
|
||||
sessionMetadata.setClientId(null);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms that an EppResourceIndex entity exists in datastore for a given resource.
|
||||
*/
|
||||
protected static <T extends EppResource> void assertEppResourceIndexEntityFor(final T resource) {
|
||||
ImmutableList<EppResourceIndex> indices = FluentIterable
|
||||
.from(ofy().load()
|
||||
.type(EppResourceIndex.class)
|
||||
.filter("kind", Key.getKind(resource.getClass())))
|
||||
.filter(new Predicate<EppResourceIndex>() {
|
||||
@Override
|
||||
public boolean apply(EppResourceIndex index) {
|
||||
return index.getReference().get().equals(resource);
|
||||
}})
|
||||
.toList();
|
||||
assertThat(indices).hasSize(1);
|
||||
assertThat(indices.get(0).getBucket())
|
||||
.isEqualTo(EppResourceIndexBucket.getBucketKey(Key.create(resource)));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,293 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.async;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.EppResourceUtils.loadByUniqueId;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getPollMessages;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newContactResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistContactWithPendingTransfer;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.domain.registry.model.contact.ContactAddress;
|
||||
import com.google.domain.registry.model.contact.ContactPhoneNumber;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.contact.PostalInfo;
|
||||
import com.google.domain.registry.model.domain.DomainResource;
|
||||
import com.google.domain.registry.model.domain.ReferenceUnion;
|
||||
import com.google.domain.registry.model.eppcommon.StatusValue;
|
||||
import com.google.domain.registry.model.eppcommon.Trid;
|
||||
import com.google.domain.registry.model.poll.PendingActionNotificationResponse;
|
||||
import com.google.domain.registry.model.poll.PollMessage;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.transfer.TransferResponse;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Ref;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link DeleteContactResourceAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DeleteContactResourceActionTest
|
||||
extends DeleteEppResourceActionTestCase<DeleteContactResourceAction> {
|
||||
|
||||
ContactResource contactUnused;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
setupDeleteEppResourceAction(new DeleteContactResourceAction());
|
||||
contactUnused = persistActiveContact("blah1235");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_contact_referencedByActiveDomain_doesNotGetDeleted() throws Exception {
|
||||
contactUsed = persistResource(
|
||||
contactUsed.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
runMapreduceWithKeyParam(Key.create(contactUsed).getString());
|
||||
contactUsed = loadByUniqueId(ContactResource.class, "blah1234", now);
|
||||
assertAboutContacts().that(contactUsed).doesNotHaveStatusValue(StatusValue.PENDING_DELETE)
|
||||
.and().hasDeletionTime(END_OF_TIME);
|
||||
domain = loadByUniqueId(DomainResource.class, "example.tld", now);
|
||||
assertThat(domain.getReferencedContacts())
|
||||
.contains(ReferenceUnion.<ContactResource>create(Ref.create(contactUsed)));
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(contactUsed, HistoryEntry.Type.CONTACT_DELETE_FAILURE);
|
||||
assertPollMessageFor(
|
||||
historyEntry,
|
||||
"TheRegistrar",
|
||||
"Can't delete contact blah1234 because it is referenced by a domain.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_contact_notReferenced_getsDeleted() throws Exception {
|
||||
contactUnused = persistResource(
|
||||
contactUnused.asBuilder()
|
||||
.setLocalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(PostalInfo.Type.LOCALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Grand Ave"))
|
||||
.build())
|
||||
.build())
|
||||
.setInternationalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(PostalInfo.Type.INTERNATIONALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Avenida Grande"))
|
||||
.build())
|
||||
.build())
|
||||
.setEmailAddress("bob@bob.com")
|
||||
.setVoiceNumber(new ContactPhoneNumber.Builder().setPhoneNumber("555-1212").build())
|
||||
.setFaxNumber(new ContactPhoneNumber.Builder().setPhoneNumber("555-1212").build())
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
assertAboutContacts().that(contactUnused).hasNonNullLocalizedPostalInfo()
|
||||
.and().hasNonNullInternationalizedPostalInfo()
|
||||
.and().hasNonNullEmailAddress()
|
||||
.and().hasNonNullVoiceNumber()
|
||||
.and().hasNonNullFaxNumber();
|
||||
Key<ContactResource> key = Key.create(contactUnused);
|
||||
runMapreduceWithKeyParam(key.getString());
|
||||
assertThat(loadByUniqueId(ContactResource.class, "blah1235", now)).isNull();
|
||||
ContactResource contactAfterDeletion = ofy().load().key(key).now();
|
||||
assertAboutContacts().that(contactAfterDeletion).hasDeletionTime(now)
|
||||
// Note that there will be another history entry of CONTACT_PENDING_DELETE, but this is
|
||||
// added by the flow and not the mapreduce itself.
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.CONTACT_DELETE);
|
||||
assertAboutContacts().that(contactAfterDeletion).hasNullLocalizedPostalInfo()
|
||||
.and().hasNullInternationalizedPostalInfo()
|
||||
.and().hasNullEmailAddress()
|
||||
.and().hasNullVoiceNumber()
|
||||
.and().hasNullFaxNumber();
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(contactAfterDeletion, HistoryEntry.Type.CONTACT_DELETE);
|
||||
assertPollMessageFor(historyEntry, "TheRegistrar", "Deleted contact blah1235.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_contactWithPendingTransfer_getsDeleted() throws Exception {
|
||||
ContactResource contact = persistContactWithPendingTransfer(
|
||||
persistActiveContact("sh8013").asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build(),
|
||||
transferRequestTime,
|
||||
transferExpirationTime,
|
||||
clock.nowUtc());
|
||||
runMapreduceWithKeyParam(Key.create(contact).getString());
|
||||
// Check that the contact is deleted as of now.
|
||||
assertThat(loadByUniqueId(ContactResource.class, "sh8013", now)).isNull();
|
||||
// Check that it's still there (it wasn't deleted yesterday) and that it has history.
|
||||
assertAboutContacts()
|
||||
.that(loadByUniqueId(ContactResource.class, "sh8013", now.minusDays(1)))
|
||||
.hasOneHistoryEntryEachOfTypes(
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_REQUEST,
|
||||
HistoryEntry.Type.CONTACT_DELETE);
|
||||
assertNoBillingEvents();
|
||||
PollMessage deletePollMessage = Iterables.getOnlyElement(
|
||||
getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1)));
|
||||
assertThat(deletePollMessage.getMsg()).isEqualTo("Deleted contact sh8013.");
|
||||
// The poll message in the future to the gaining registrar should be gone too, but there
|
||||
// should be one at the current time to the gaining registrar.
|
||||
PollMessage gainingPollMessage = Iterables.getOnlyElement(
|
||||
getPollMessages("NewRegistrar", clock.nowUtc()));
|
||||
System.out.println(gainingPollMessage);
|
||||
assertThat(gainingPollMessage.getEventTime()).isEqualTo(clock.nowUtc());
|
||||
assertThat(
|
||||
Iterables.getOnlyElement(FluentIterable.from(gainingPollMessage.getResponseData())
|
||||
.filter(TransferResponse.class))
|
||||
.getTransferStatus())
|
||||
.isEqualTo(TransferStatus.SERVER_CANCELLED);
|
||||
PendingActionNotificationResponse panData = Iterables.getOnlyElement(FluentIterable
|
||||
.from(gainingPollMessage.getResponseData())
|
||||
.filter(PendingActionNotificationResponse.class));
|
||||
assertThat(panData.getTrid())
|
||||
.isEqualTo(Trid.create("transferClient-trid", "transferServer-trid"));
|
||||
assertThat(panData.getActionResult()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_contact_referencedByDeleteDomain_getsDeleted() throws Exception {
|
||||
contactUsed = persistResource(
|
||||
contactUsed.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
domain = persistResource(
|
||||
domain.asBuilder()
|
||||
.setDeletionTime(now.minusDays(3))
|
||||
.build());
|
||||
runMapreduceWithKeyParam(Key.create(contactUsed).getString());
|
||||
assertThat(loadByUniqueId(ContactResource.class, "blah1234", now)).isNull();
|
||||
ContactResource contactBeforeDeletion =
|
||||
loadByUniqueId(ContactResource.class, "blah1234", now.minusDays(1));
|
||||
assertAboutContacts().that(contactBeforeDeletion).hasDeletionTime(now)
|
||||
.and().hasExactlyStatusValues(StatusValue.OK)
|
||||
// Note that there will be another history entry of CONTACT_PENDING_DELETE, but this is
|
||||
// added by the flow and not the mapreduce itself.
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.CONTACT_DELETE);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(contactBeforeDeletion, HistoryEntry.Type.CONTACT_DELETE);
|
||||
assertPollMessageFor(historyEntry, "TheRegistrar", "Deleted contact blah1234.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notPendingDelete() throws Exception {
|
||||
thrown.expect(IllegalStateException.class, "Resource blah1235 is not set as PENDING_DELETE");
|
||||
runMapreduceWithKeyParam(Key.create(contactUnused).getString());
|
||||
assertThat(
|
||||
loadByUniqueId(ContactResource.class, "blah1235", now)).isEqualTo(contactUnused);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_notRequestedByOwner_doesNotGetDeleted() throws Exception {
|
||||
contactUnused = persistResource(
|
||||
contactUnused.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
Key<ContactResource> key = Key.create(contactUnused);
|
||||
runMapreduceWithParams(key.getString(), "OtherRegistrar", false);
|
||||
contactUnused = loadByUniqueId(ContactResource.class, "blah1235", now);
|
||||
assertAboutContacts().that(contactUnused).doesNotHaveStatusValue(StatusValue.PENDING_DELETE)
|
||||
.and().hasDeletionTime(END_OF_TIME);
|
||||
domain = loadByUniqueId(DomainResource.class, "example.tld", now);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(contactUnused, HistoryEntry.Type.CONTACT_DELETE_FAILURE);
|
||||
assertPollMessageFor(
|
||||
historyEntry,
|
||||
"OtherRegistrar",
|
||||
"Can't delete contact blah1235 because it was transferred prior to deletion.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_notRequestedByOwner_isSuperuser_getsDeleted() throws Exception {
|
||||
contactUnused = persistResource(
|
||||
contactUnused.asBuilder()
|
||||
.setLocalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(PostalInfo.Type.LOCALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Grand Ave"))
|
||||
.build())
|
||||
.build())
|
||||
.setInternationalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(PostalInfo.Type.INTERNATIONALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Avenida Grande"))
|
||||
.build())
|
||||
.build())
|
||||
.setEmailAddress("bob@bob.com")
|
||||
.setVoiceNumber(new ContactPhoneNumber.Builder().setPhoneNumber("555-1212").build())
|
||||
.setFaxNumber(new ContactPhoneNumber.Builder().setPhoneNumber("555-1212").build())
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
Key<ContactResource> key = Key.create(contactUnused);
|
||||
runMapreduceWithParams(key.getString(), "OtherRegistrar", true);
|
||||
assertThat(loadByUniqueId(ContactResource.class, "blah1235", now)).isNull();
|
||||
ContactResource contactAfterDeletion = ofy().load().key(key).now();
|
||||
assertAboutContacts().that(contactAfterDeletion).hasDeletionTime(now)
|
||||
// Note that there will be another history entry of CONTACT_PENDING_DELETE, but this is
|
||||
// added by the flow and not the mapreduce itself.
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.CONTACT_DELETE);
|
||||
assertAboutContacts().that(contactAfterDeletion).hasNullLocalizedPostalInfo()
|
||||
.and().hasNullInternationalizedPostalInfo()
|
||||
.and().hasNullEmailAddress()
|
||||
.and().hasNullVoiceNumber()
|
||||
.and().hasNullFaxNumber();
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(contactAfterDeletion, HistoryEntry.Type.CONTACT_DELETE);
|
||||
assertPollMessageFor(historyEntry, "OtherRegistrar", "Deleted contact blah1235.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_targetResourceDoesntExist() throws Exception {
|
||||
createTld("tld");
|
||||
ContactResource notPersisted = newContactResource("somecontact");
|
||||
thrown.expect(
|
||||
BadRequestException.class,
|
||||
"Could not load resource for key: Key<?>(ContactResource(\"7-ROID\"))");
|
||||
runMapreduceWithKeyParam(Key.create(notPersisted).getString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_contactAlreadyDeleted() throws Exception {
|
||||
ContactResource contactDeleted = persistResource(
|
||||
newContactResource("blah1236").asBuilder()
|
||||
.setCreationTimeForTest(clock.nowUtc().minusDays(2))
|
||||
.setDeletionTime(clock.nowUtc().minusDays(1))
|
||||
.build());
|
||||
thrown.expect(
|
||||
IllegalStateException.class,
|
||||
"Resource blah1236 is already deleted.");
|
||||
runMapreduceWithKeyParam(Key.create(contactDeleted).getString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.async;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.EppResourceUtils.loadByUniqueId;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getOnlyPollMessageForHistoryEntry;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.mapreduce.MapreduceRunner;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.domain.DomainResource;
|
||||
import com.google.domain.registry.model.domain.ReferenceUnion;
|
||||
import com.google.domain.registry.model.host.HostResource;
|
||||
import com.google.domain.registry.model.ofy.Ofy;
|
||||
import com.google.domain.registry.model.poll.PollMessage;
|
||||
import com.google.domain.registry.model.poll.PollMessage.OneTime;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.testing.FakeResponse;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.mapreduce.MapreduceTestCase;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link DeleteEppResourceAction}. */
|
||||
public abstract class DeleteEppResourceActionTestCase<T extends DeleteEppResourceAction<?>>
|
||||
extends MapreduceTestCase<T> {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
DateTime now = DateTime.now(DateTimeZone.UTC);
|
||||
FakeClock clock = new FakeClock(now);
|
||||
final DateTime transferRequestTime = now.minusDays(3);
|
||||
final DateTime transferExpirationTime =
|
||||
transferRequestTime.plus(Registry.DEFAULT_TRANSFER_GRACE_PERIOD);
|
||||
|
||||
ContactResource contactUsed;
|
||||
HostResource hostUsed;
|
||||
DomainResource domain;
|
||||
|
||||
public void setupDeleteEppResourceAction(T deleteEppResourceAction) throws Exception {
|
||||
action = deleteEppResourceAction;
|
||||
action.mrRunner = new MapreduceRunner(Optional.<Integer>absent(), Optional.<Integer>absent());
|
||||
action.response = new FakeResponse();
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
inject.setStaticField(DeleteEppResourceAction.class, "clock", clock);
|
||||
|
||||
createTld("tld");
|
||||
contactUsed = persistActiveContact("blah1234");
|
||||
hostUsed = persistActiveHost("ns1.example.tld");
|
||||
domain = persistResource(
|
||||
newDomainResource("example.tld", contactUsed).asBuilder()
|
||||
.setNameservers(ImmutableSet.of(ReferenceUnion.create(hostUsed)))
|
||||
.build());
|
||||
}
|
||||
|
||||
void runMapreduce() throws Exception {
|
||||
clock.advanceOneMilli();
|
||||
action.run();
|
||||
executeTasksUntilEmpty("mapreduce");
|
||||
ofy().clearSessionCache();
|
||||
now = clock.nowUtc();
|
||||
}
|
||||
|
||||
void runMapreduceWithParams(
|
||||
String resourceKeyString,
|
||||
String requestingClientId,
|
||||
boolean isSuperuser) throws Exception {
|
||||
action.resourceKeyString = resourceKeyString;
|
||||
action.requestingClientId = requestingClientId;
|
||||
action.isSuperuser = isSuperuser;
|
||||
runMapreduce();
|
||||
}
|
||||
|
||||
void runMapreduceWithKeyParam(String resourceKeyString) throws Exception {
|
||||
runMapreduceWithParams(resourceKeyString, "TheRegistrar", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to check that one poll message exists with a given history entry, resource,
|
||||
* client id, and message.
|
||||
*/
|
||||
void assertPollMessageFor(
|
||||
HistoryEntry historyEntry,
|
||||
String clientId,
|
||||
String msg) {
|
||||
PollMessage.OneTime pollMessage = (OneTime) getOnlyPollMessageForHistoryEntry(historyEntry);
|
||||
assertThat(msg).isEqualTo(pollMessage.getMsg());
|
||||
assertThat(now).isEqualTo(pollMessage.getEventTime());
|
||||
assertThat(clientId).isEqualTo(pollMessage.getClientId());
|
||||
assertThat(pollMessage.getClientId()).isEqualTo(clientId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainKeyPassed() throws Exception {
|
||||
DomainResource domain = persistActiveDomain("fail.tld");
|
||||
thrown.expect(
|
||||
IllegalArgumentException.class, "Cannot delete a DomainResource via this action.");
|
||||
runMapreduceWithKeyParam(Key.create(domain).getString());
|
||||
assertThat(loadByUniqueId(DomainResource.class, "fail.tld", now)).isEqualTo(domain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badKeyPassed() throws Exception {
|
||||
createTld("tld");
|
||||
thrown.expect(BadRequestException.class, "Could not parse key string: a bad key");
|
||||
runMapreduceWithKeyParam("a bad key");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.async;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.EppResourceUtils.loadByUniqueId;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newHostResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.HostResourceSubject.assertAboutHosts;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertDnsTasksEnqueued;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.domain.DomainResource;
|
||||
import com.google.domain.registry.model.domain.ReferenceUnion;
|
||||
import com.google.domain.registry.model.eppcommon.StatusValue;
|
||||
import com.google.domain.registry.model.host.HostResource;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Ref;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link DeleteHostResourceAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DeleteHostResourceActionTest
|
||||
extends DeleteEppResourceActionTestCase<DeleteHostResourceAction> {
|
||||
|
||||
HostResource hostUnused;
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
setupDeleteEppResourceAction(new DeleteHostResourceAction());
|
||||
hostUnused = persistActiveHost("ns2.example.tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_host_referencedByActiveDomain_doesNotGetDeleted() throws Exception {
|
||||
hostUsed = persistResource(
|
||||
hostUsed.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
runMapreduceWithKeyParam(Key.create(hostUsed).getString());
|
||||
hostUsed = loadByUniqueId(HostResource.class, "ns1.example.tld", now);
|
||||
assertAboutHosts().that(hostUsed).doesNotHaveStatusValue(StatusValue.PENDING_DELETE)
|
||||
.and().hasDeletionTime(END_OF_TIME);
|
||||
domain = loadByUniqueId(DomainResource.class, "example.tld", now);
|
||||
assertThat(domain.getNameservers())
|
||||
.contains(ReferenceUnion.<HostResource>create(Ref.create(hostUsed)));
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(hostUsed, HistoryEntry.Type.HOST_DELETE_FAILURE);
|
||||
assertPollMessageFor(
|
||||
historyEntry,
|
||||
"TheRegistrar",
|
||||
"Can't delete host ns1.example.tld because it is referenced by a domain.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_host_notReferenced_getsDeleted() throws Exception {
|
||||
hostUnused = persistResource(
|
||||
hostUnused.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
runMapreduceWithKeyParam(Key.create(hostUnused).getString());
|
||||
assertThat(loadByUniqueId(HostResource.class, "ns2.example.tld", now)).isNull();
|
||||
HostResource hostBeforeDeletion =
|
||||
loadByUniqueId(HostResource.class, "ns2.example.tld", now.minusDays(1));
|
||||
assertAboutHosts().that(hostBeforeDeletion).hasDeletionTime(now)
|
||||
.and().hasExactlyStatusValues(StatusValue.OK)
|
||||
// Note that there will be another history entry of HOST_PENDING_DELETE, but this is
|
||||
// added by the flow and not the mapreduce itself.
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.HOST_DELETE);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(hostBeforeDeletion, HistoryEntry.Type.HOST_DELETE);
|
||||
assertPollMessageFor(historyEntry, "TheRegistrar", "Deleted host ns2.example.tld.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_host_referencedByDeletedDomain_getsDeleted() throws Exception {
|
||||
hostUsed = persistResource(
|
||||
hostUsed.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
domain = persistResource(
|
||||
domain.asBuilder()
|
||||
.setDeletionTime(now.minusDays(3))
|
||||
.build());
|
||||
runMapreduceWithKeyParam(Key.create(hostUsed).getString());
|
||||
assertThat(loadByUniqueId(HostResource.class, "ns1.example.tld", now)).isNull();
|
||||
HostResource hostBeforeDeletion =
|
||||
loadByUniqueId(HostResource.class, "ns1.example.tld", now.minusDays(1));
|
||||
assertAboutHosts().that(hostBeforeDeletion).hasDeletionTime(now)
|
||||
.and().hasExactlyStatusValues(StatusValue.OK)
|
||||
// Note that there will be another history entry of HOST_PENDING_DELETE, but this is
|
||||
// added by the flow and not the mapreduce itself.
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.HOST_DELETE);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(hostBeforeDeletion, HistoryEntry.Type.HOST_DELETE);
|
||||
assertPollMessageFor(historyEntry, "TheRegistrar", "Deleted host ns1.example.tld.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_subordinateHost_getsDeleted() throws Exception {
|
||||
domain = persistResource(
|
||||
newDomainResource("example.tld").asBuilder()
|
||||
.setSubordinateHosts(ImmutableSet.of("ns2.example.tld"))
|
||||
.build());
|
||||
persistResource(
|
||||
hostUnused.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.setSuperordinateDomain(Ref.create(domain))
|
||||
.build());
|
||||
runMapreduceWithKeyParam(Key.create(hostUnused).getString());
|
||||
// Check that the host is deleted as of now.
|
||||
assertThat(loadByUniqueId(HostResource.class, "ns2.example.tld", clock.nowUtc()))
|
||||
.isNull();
|
||||
assertNoBillingEvents();
|
||||
assertThat(loadByUniqueId(DomainResource.class, "example.tld", clock.nowUtc())
|
||||
.getSubordinateHosts())
|
||||
.isEmpty();
|
||||
assertDnsTasksEnqueued("ns2.example.tld");
|
||||
HostResource hostBeforeDeletion =
|
||||
loadByUniqueId(HostResource.class, "ns2.example.tld", now.minusDays(1));
|
||||
assertAboutHosts().that(hostBeforeDeletion).hasDeletionTime(now)
|
||||
.and().hasExactlyStatusValues(StatusValue.OK)
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.HOST_DELETE);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(hostBeforeDeletion, HistoryEntry.Type.HOST_DELETE);
|
||||
assertPollMessageFor(historyEntry, "TheRegistrar", "Deleted host ns2.example.tld.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notPendingDelete() throws Exception {
|
||||
thrown.expect(
|
||||
IllegalStateException.class, "Resource ns2.example.tld is not set as PENDING_DELETE");
|
||||
runMapreduceWithKeyParam(Key.create(hostUnused).getString());
|
||||
assertThat(
|
||||
loadByUniqueId(HostResource.class, "ns2.example.tld", now)).isEqualTo(hostUnused);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_notRequestedByOwner_doesNotGetDeleted() throws Exception {
|
||||
hostUnused = persistResource(
|
||||
hostUnused.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
Key<HostResource> key = Key.create(hostUnused);
|
||||
runMapreduceWithParams(key.getString(), "OtherRegistrar", false);
|
||||
hostUnused = loadByUniqueId(HostResource.class, "ns2.example.tld", now);
|
||||
assertAboutHosts().that(hostUnused).doesNotHaveStatusValue(StatusValue.PENDING_DELETE)
|
||||
.and().hasDeletionTime(END_OF_TIME);
|
||||
domain = loadByUniqueId(DomainResource.class, "example.tld", now);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(hostUnused, HistoryEntry.Type.HOST_DELETE_FAILURE);
|
||||
assertPollMessageFor(
|
||||
historyEntry,
|
||||
"OtherRegistrar",
|
||||
"Can't delete host ns2.example.tld because it was transferred prior to deletion.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_notRequestedByOwner_isSuperuser_getsDeleted() throws Exception {
|
||||
hostUnused = persistResource(
|
||||
hostUnused.asBuilder()
|
||||
.addStatusValue(StatusValue.PENDING_DELETE)
|
||||
.build());
|
||||
Key<HostResource> key = Key.create(hostUnused);
|
||||
runMapreduceWithParams(key.getString(), "OtherRegistrar", true);
|
||||
assertThat(loadByUniqueId(HostResource.class, "ns2.example.tld", now)).isNull();
|
||||
HostResource hostBeforeDeletion =
|
||||
loadByUniqueId(HostResource.class, "ns2.example.tld", now.minusDays(1));
|
||||
assertAboutHosts().that(hostBeforeDeletion).hasDeletionTime(now)
|
||||
.and().hasExactlyStatusValues(StatusValue.OK)
|
||||
// Note that there will be another history entry of HOST_PENDING_DELETE, but this is
|
||||
// added by the flow and not the mapreduce itself.
|
||||
.and().hasOnlyOneHistoryEntryWhich().hasType(HistoryEntry.Type.HOST_DELETE);
|
||||
HistoryEntry historyEntry =
|
||||
getOnlyHistoryEntryOfType(hostBeforeDeletion, HistoryEntry.Type.HOST_DELETE);
|
||||
assertPollMessageFor(historyEntry, "OtherRegistrar", "Deleted host ns2.example.tld.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_targetResourceDoesntExist() throws Exception {
|
||||
createTld("tld");
|
||||
HostResource notPersisted = newHostResource("ns1.example.tld");
|
||||
thrown.expect(
|
||||
BadRequestException.class,
|
||||
"Could not load resource for key: Key<?>(HostResource(\"7-ROID\"))");
|
||||
runMapreduceWithKeyParam(Key.create(notPersisted).getString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_hostAlreadyDeleted() throws Exception {
|
||||
HostResource hostDeleted = persistResource(
|
||||
newHostResource("ns3.example.tld").asBuilder()
|
||||
.setCreationTimeForTest(clock.nowUtc().minusDays(2))
|
||||
.setDeletionTime(clock.nowUtc().minusDays(1))
|
||||
.build());
|
||||
thrown.expect(
|
||||
IllegalStateException.class,
|
||||
"Resource ns3.example.tld is already deleted.");
|
||||
runMapreduceWithKeyParam(Key.create(hostDeleted).getString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.async;
|
||||
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newDomainApplication;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newHostResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.dns.DnsQueue;
|
||||
import com.google.domain.registry.mapreduce.MapreduceRunner;
|
||||
import com.google.domain.registry.model.domain.ReferenceUnion;
|
||||
import com.google.domain.registry.model.host.HostResource;
|
||||
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeResponse;
|
||||
import com.google.domain.registry.testing.InjectRule;
|
||||
import com.google.domain.registry.testing.mapreduce.MapreduceTestCase;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link DnsRefreshForHostRenameAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DnsRefreshForHostRenameActionTest
|
||||
extends MapreduceTestCase<DnsRefreshForHostRenameAction> {
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public InjectRule inject = new InjectRule();
|
||||
|
||||
private final DnsQueue dnsQueue = mock(DnsQueue.class);
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
inject.setStaticField(DnsRefreshForHostRenameAction.class, "dnsQueue", dnsQueue);
|
||||
}
|
||||
|
||||
private void runMapreduce(String hostKeyString) throws Exception {
|
||||
action = new DnsRefreshForHostRenameAction();
|
||||
action.hostKeyString = hostKeyString;
|
||||
action.mrRunner = new MapreduceRunner(Optional.<Integer>absent(), Optional.<Integer>absent());
|
||||
action.response = new FakeResponse();
|
||||
action.run();
|
||||
executeTasksUntilEmpty("mapreduce");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_dnsUpdateEnqueued() throws Exception {
|
||||
createTld("tld");
|
||||
HostResource renamedHost = persistActiveHost("ns1.example.tld");
|
||||
HostResource otherHost = persistActiveHost("ns2.example.tld");
|
||||
persistResource(newDomainApplication("notadomain.tld").asBuilder()
|
||||
.setNameservers(ImmutableSet.of(ReferenceUnion.create(renamedHost)))
|
||||
.build());
|
||||
persistResource(newDomainResource("example.tld").asBuilder()
|
||||
.setNameservers(ImmutableSet.of(ReferenceUnion.create(renamedHost)))
|
||||
.build());
|
||||
persistResource(newDomainResource("otherexample.tld").asBuilder()
|
||||
.setNameservers(ImmutableSet.of(ReferenceUnion.create(renamedHost)))
|
||||
.build());
|
||||
persistResource(newDomainResource("untouched.tld").asBuilder()
|
||||
.setNameservers(ImmutableSet.of(ReferenceUnion.create(otherHost)))
|
||||
.build());
|
||||
runMapreduce(Key.create(renamedHost).getString());
|
||||
verify(dnsQueue).addDomainRefreshTask("example.tld");
|
||||
verify(dnsQueue).addDomainRefreshTask("otherexample.tld");
|
||||
verifyNoMoreInteractions(dnsQueue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_noDnsTasksForDeletedDomain() throws Exception {
|
||||
createTld("tld");
|
||||
HostResource renamedHost = persistActiveHost("ns1.example.tld");
|
||||
persistResource(newDomainResource("example.tld").asBuilder()
|
||||
.setNameservers(ImmutableSet.of(ReferenceUnion.create(renamedHost)))
|
||||
.setDeletionTime(START_OF_TIME)
|
||||
.build());
|
||||
runMapreduce(Key.create(renamedHost).getString());
|
||||
verifyZeroInteractions(dnsQueue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badKeyPassed() throws Exception {
|
||||
createTld("tld");
|
||||
thrown.expect(BadRequestException.class, "Could not parse key string: a bad key");
|
||||
runMapreduce("a bad key");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_hostDoesntExist() throws Exception {
|
||||
createTld("tld");
|
||||
HostResource notPersistedHost = newHostResource("ns1.example.tld");
|
||||
thrown.expect(
|
||||
BadRequestException.class,
|
||||
"Could not load resource for key: Key<?>(HostResource(\"2-ROID\"))");
|
||||
runMapreduce(Key.create(notPersistedHost).getString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.domain.registry.model.eppoutput.CheckData.ContactCheck.create;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistDeletedContact;
|
||||
|
||||
import com.google.domain.registry.flows.ResourceCheckFlow.TooManyResourceChecksException;
|
||||
import com.google.domain.registry.flows.ResourceCheckFlowTestCase;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactCheckFlow}. */
|
||||
public class ContactCheckFlowTest
|
||||
extends ResourceCheckFlowTestCase<ContactCheckFlow, ContactResource> {
|
||||
|
||||
public ContactCheckFlowTest() {
|
||||
setEppInput("contact_check.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNothingExists() throws Exception {
|
||||
// These ids come from the check xml.
|
||||
doCheckTest(
|
||||
create(true, "sh8013", null),
|
||||
create(true, "sah8013", null),
|
||||
create(true, "8013sah", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneExists() throws Exception {
|
||||
persistActiveContact("sh8013");
|
||||
// These ids come from the check xml.
|
||||
doCheckTest(
|
||||
create(false, "sh8013", "In use"),
|
||||
create(true, "sah8013", null),
|
||||
create(true, "8013sah", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneExistsButWasDeleted() throws Exception {
|
||||
persistDeletedContact("sh8013", clock.nowUtc());
|
||||
// These ids come from the check xml.
|
||||
doCheckTest(
|
||||
create(true, "sh8013", null),
|
||||
create(true, "sah8013", null),
|
||||
create(true, "8013sah", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXmlMatches() throws Exception {
|
||||
persistActiveContact("sah8013");
|
||||
runFlowAssertResponse(readFile("contact_check_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test50IdsAllowed() throws Exception {
|
||||
// Make sure we don't have a regression that reduces the number of allowed checks.
|
||||
setEppInput("contact_check_50.xml");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTooManyIds() throws Exception {
|
||||
setEppInput("contact_check_51.xml");
|
||||
thrown.expect(TooManyResourceChecksException.class);
|
||||
runFlow();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistDeletedContact;
|
||||
|
||||
import com.google.domain.registry.flows.ResourceCreateFlow.ResourceAlreadyExistsException;
|
||||
import com.google.domain.registry.flows.ResourceFlowTestCase;
|
||||
import com.google.domain.registry.flows.contact.ContactFlowUtils.BadInternationalizedPostalInfoException;
|
||||
import com.google.domain.registry.flows.contact.ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactCreateFlow}. */
|
||||
public class ContactCreateFlowTest
|
||||
extends ResourceFlowTestCase<ContactCreateFlow, ContactResource> {
|
||||
|
||||
public ContactCreateFlowTest() {
|
||||
setEppInput("contact_create.xml");
|
||||
clock.setTo(DateTime.parse("1999-04-03T22:00:00.0Z"));
|
||||
}
|
||||
|
||||
private void doSuccessfulTest() throws Exception {
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile("contact_create_response.xml"));
|
||||
// Check that the contact was created and persisted with a history entry.
|
||||
assertAboutContacts().that(reloadResourceByUniqueId())
|
||||
.hasOnlyOneHistoryEntryWhich().hasNoXml();
|
||||
assertNoBillingEvents();
|
||||
assertEppResourceIndexEntityFor(reloadResourceByUniqueId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
dryRunFlowAssertResponse(readFile("contact_create_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_neverExisted() throws Exception {
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_existedButWasDeleted() throws Exception {
|
||||
persistDeletedContact(getUniqueIdFromCommand(), clock.nowUtc());
|
||||
clock.advanceOneMilli();
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyExists() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceAlreadyExistsException.class,
|
||||
String.format("Object with given ID (%s) already exists", getUniqueIdFromCommand()));
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nonAsciiInLocAddress() throws Exception {
|
||||
setEppInput("contact_create_hebrew_loc.xml");
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonAsciiInIntAddress() throws Exception {
|
||||
thrown.expect(BadInternationalizedPostalInfoException.class);
|
||||
setEppInput("contact_create_hebrew_int.xml");
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_declineDisclosure() throws Exception {
|
||||
thrown.expect(DeclineContactDisclosureFieldDisallowedPolicyException.class);
|
||||
setEppInput("contact_create_decline_disclosure.xml");
|
||||
runFlow();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.domain.registry.flows.async.AsyncFlowUtils.ASYNC_FLOW_QUEUE_NAME;
|
||||
import static com.google.domain.registry.request.Actions.getPathForAction;
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newContactResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistDeletedContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.flows.FlowRunner.CommitMode;
|
||||
import com.google.domain.registry.flows.FlowRunner.UserPrivileges;
|
||||
import com.google.domain.registry.flows.ResourceAsyncDeleteFlow.ResourceToDeleteIsReferencedException;
|
||||
import com.google.domain.registry.flows.ResourceFlowTestCase;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import com.google.domain.registry.flows.ResourceMutateFlow.ResourceToMutateDoesNotExistException;
|
||||
import com.google.domain.registry.flows.SingleResourceFlow.ResourceStatusProhibitsOperationException;
|
||||
import com.google.domain.registry.flows.async.DeleteContactResourceAction;
|
||||
import com.google.domain.registry.flows.async.DeleteEppResourceAction;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.eppcommon.StatusValue;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactDeleteFlow}. */
|
||||
public class ContactDeleteFlowTest
|
||||
extends ResourceFlowTestCase<ContactDeleteFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void initFlowTest() {
|
||||
setEppInput("contact_delete.xml");
|
||||
}
|
||||
|
||||
private void doFailingStatusTest(StatusValue statusValue, Class<? extends Exception> exception)
|
||||
throws Exception {
|
||||
thrown.expect(exception);
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(statusValue))
|
||||
.build());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
dryRunFlowAssertResponse(readFile("contact_delete_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile("contact_delete_response.xml"));
|
||||
ContactResource deletedContact = reloadResourceByUniqueId();
|
||||
assertAboutContacts().that(deletedContact).hasStatusValue(StatusValue.PENDING_DELETE);
|
||||
assertTasksEnqueued(ASYNC_FLOW_QUEUE_NAME, new TaskMatcher()
|
||||
.url(getPathForAction(DeleteContactResourceAction.class))
|
||||
.etaDelta(Duration.standardSeconds(75), Duration.standardSeconds(105)) // expected: 90
|
||||
.param(
|
||||
DeleteEppResourceAction.PARAM_REQUESTING_CLIENT_ID,
|
||||
"TheRegistrar")
|
||||
.param(
|
||||
DeleteEppResourceAction.PARAM_IS_SUPERUSER,
|
||||
Boolean.toString(false))
|
||||
.param(
|
||||
DeleteEppResourceAction.PARAM_RESOURCE_KEY,
|
||||
Key.create(deletedContact).getString()));
|
||||
assertAboutContacts().that(deletedContact)
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.CONTACT_PENDING_DELETE);
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
persistDeletedContact(getUniqueIdFromCommand(), clock.nowUtc());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasClientDeleteProhibited() throws Exception {
|
||||
doFailingStatusTest(
|
||||
StatusValue.CLIENT_DELETE_PROHIBITED, ResourceStatusProhibitsOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasServerDeleteProhibited() throws Exception {
|
||||
doFailingStatusTest(
|
||||
StatusValue.SERVER_DELETE_PROHIBITED, ResourceStatusProhibitsOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasPendingDelete() throws Exception {
|
||||
doFailingStatusTest(
|
||||
StatusValue.PENDING_DELETE, ResourceStatusProhibitsOperationException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() throws Exception {
|
||||
thrown.expect(ResourceNotOwnedException.class);
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setSuperuser(true);
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, readFile("contact_delete_response.xml"));
|
||||
ContactResource deletedContact = reloadResourceByUniqueId();
|
||||
assertAboutContacts().that(deletedContact).hasStatusValue(StatusValue.PENDING_DELETE);
|
||||
assertTasksEnqueued(ASYNC_FLOW_QUEUE_NAME, new TaskMatcher()
|
||||
.url(getPathForAction(DeleteContactResourceAction.class))
|
||||
.etaDelta(Duration.standardSeconds(75), Duration.standardSeconds(105)) // expected: 90
|
||||
.param(
|
||||
DeleteEppResourceAction.PARAM_REQUESTING_CLIENT_ID,
|
||||
"NewRegistrar")
|
||||
.param(
|
||||
DeleteEppResourceAction.PARAM_IS_SUPERUSER,
|
||||
Boolean.toString(true))
|
||||
.param(
|
||||
DeleteEppResourceAction.PARAM_RESOURCE_KEY,
|
||||
Key.create(deletedContact).getString()));
|
||||
assertAboutContacts().that(deletedContact)
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.CONTACT_PENDING_DELETE);
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_failfastWhenLinkedToDomain() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
newDomainResource("example.tld", persistActiveContact(getUniqueIdFromCommand())));
|
||||
thrown.expect(ResourceToDeleteIsReferencedException.class);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_failfastWhenLinkedToApplication() throws Exception {
|
||||
createTld("tld");
|
||||
persistResource(
|
||||
newDomainResource("example.tld", persistActiveContact(getUniqueIdFromCommand())));
|
||||
thrown.expect(ResourceToDeleteIsReferencedException.class);
|
||||
runFlow();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.EppResourceUtils.isDeleted;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newDomainResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.flows.ResourceFlowTestCase;
|
||||
import com.google.domain.registry.flows.ResourceQueryFlow.ResourceToQueryDoesNotExistException;
|
||||
import com.google.domain.registry.model.contact.ContactAddress;
|
||||
import com.google.domain.registry.model.contact.ContactAuthInfo;
|
||||
import com.google.domain.registry.model.contact.ContactPhoneNumber;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.contact.Disclose;
|
||||
import com.google.domain.registry.model.contact.PostalInfo;
|
||||
import com.google.domain.registry.model.contact.PostalInfo.Type;
|
||||
import com.google.domain.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import com.google.domain.registry.model.eppcommon.PresenceMarker;
|
||||
import com.google.domain.registry.model.eppcommon.StatusValue;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactInfoFlow}. */
|
||||
public class ContactInfoFlowTest extends ResourceFlowTestCase<ContactInfoFlow, ContactResource> {
|
||||
|
||||
public ContactInfoFlowTest() {
|
||||
setEppInput("contact_info.xml");
|
||||
}
|
||||
|
||||
private ContactResource persistContactResource(boolean active) {
|
||||
ContactResource contact = persistResource(
|
||||
new ContactResource.Builder()
|
||||
.setContactId("sh8013")
|
||||
.setRepoId("2FF-ROID")
|
||||
.setDeletionTime(active ? null : DateTime.now().minusDays(1))
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_DELETE_PROHIBITED))
|
||||
.setInternationalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.INTERNATIONALIZED)
|
||||
.setName("John Doe")
|
||||
.setOrg("Example Inc.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 Example Dr.", "Suite 100"))
|
||||
.setCity("Dulles")
|
||||
.setState("VA")
|
||||
.setZip("20166-6503")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.setVoiceNumber(
|
||||
new ContactPhoneNumber.Builder()
|
||||
.setPhoneNumber("+1.7035555555")
|
||||
.setExtension("1234")
|
||||
.build())
|
||||
.setFaxNumber(
|
||||
new ContactPhoneNumber.Builder()
|
||||
.setPhoneNumber("+1.7035555556")
|
||||
.build())
|
||||
.setEmailAddress("jdoe@example.com")
|
||||
.setCurrentSponsorClientId("TheRegistrar")
|
||||
.setCreationClientId("NewRegistrar")
|
||||
.setLastEppUpdateClientId("NewRegistrar")
|
||||
.setCreationTimeForTest(DateTime.parse("1999-04-03T22:00:00.0Z"))
|
||||
.setLastEppUpdateTime(DateTime.parse("1999-12-03T09:00:00.0Z"))
|
||||
.setLastTransferTime(DateTime.parse("2000-04-08T09:00:00.0Z"))
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("2fooBAR")))
|
||||
.setDisclose(new Disclose.Builder()
|
||||
.setFlag(true)
|
||||
.setVoice(new PresenceMarker())
|
||||
.setEmail(new PresenceMarker())
|
||||
.build())
|
||||
.build());
|
||||
assertThat(isDeleted(contact, DateTime.now())).isNotEqualTo(active);
|
||||
return contact;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
persistContactResource(true);
|
||||
// Check that the persisted contact info was returned.
|
||||
assertTransactionalFlow(false);
|
||||
runFlowAssertResponse(
|
||||
readFile("contact_info_response.xml"),
|
||||
// We use a different roid scheme than the samples so ignore it.
|
||||
"epp.response.resData.infData.roid");
|
||||
assertNoHistory();
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_linked() throws Exception {
|
||||
createTld("foobar");
|
||||
persistResource(newDomainResource("example.foobar", persistContactResource(true)));
|
||||
// Check that the persisted contact info was returned.
|
||||
assertTransactionalFlow(false);
|
||||
runFlowAssertResponse(
|
||||
readFile("contact_info_response_linked.xml"),
|
||||
// We use a different roid scheme than the samples so ignore it.
|
||||
"epp.response.resData.infData.roid");
|
||||
assertNoHistory();
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToQueryDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToQueryDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
persistContactResource(false);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
// Extra methods so the test runner doesn't produce empty shards.
|
||||
@Test public void testNothing1() {}
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.deleteResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getOnlyPollMessage;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getPollMessages;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import com.google.domain.registry.flows.ResourceMutateFlow.ResourceToMutateDoesNotExistException;
|
||||
import com.google.domain.registry.flows.ResourceMutatePendingTransferFlow.NotPendingTransferException;
|
||||
import com.google.domain.registry.model.contact.ContactAuthInfo;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import com.google.domain.registry.model.eppcommon.Trid;
|
||||
import com.google.domain.registry.model.poll.PendingActionNotificationResponse;
|
||||
import com.google.domain.registry.model.poll.PollMessage;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.transfer.TransferResponse;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferApproveFlow}. */
|
||||
public class ContactTransferApproveFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferApproveFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
setEppInput("contact_transfer_approve.xml");
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
clock.advanceOneMilli();
|
||||
createTld("foobar");
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename)
|
||||
throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
// Look in the future and make sure the poll messages for implicit ack are there.
|
||||
assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusMonths(1)))
|
||||
.hasSize(1);
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1)))
|
||||
.hasSize(1);
|
||||
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile(expectedXmlFilename));
|
||||
|
||||
// Transfer should have succeeded. Verify correct fields were set.
|
||||
contact = reloadResourceByUniqueId();
|
||||
assertAboutContacts().that(contact)
|
||||
.hasCurrentSponsorClientId("NewRegistrar").and()
|
||||
.hasLastTransferTime(clock.nowUtc()).and()
|
||||
.hasTransferStatus(TransferStatus.CLIENT_APPROVED).and()
|
||||
.hasPendingTransferExpirationTime(clock.nowUtc()).and()
|
||||
.hasOneHistoryEntryEachOfTypes(
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_REQUEST,
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_APPROVE);
|
||||
assertNoBillingEvents();
|
||||
// The poll message (in the future) to the losing registrar for implicit ack should be gone.
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).isEmpty();
|
||||
// The poll message in the future to the gaining registrar should be gone too, but there
|
||||
// should be one at the current time to the gaining registrar.
|
||||
PollMessage gainingPollMessage = getOnlyPollMessage("NewRegistrar");
|
||||
assertThat(gainingPollMessage.getEventTime()).isEqualTo(clock.nowUtc());
|
||||
assertThat(
|
||||
Iterables.getOnlyElement(FluentIterable
|
||||
.from(gainingPollMessage.getResponseData())
|
||||
.filter(TransferResponse.class))
|
||||
.getTransferStatus())
|
||||
.isEqualTo(TransferStatus.CLIENT_APPROVED);
|
||||
PendingActionNotificationResponse panData = Iterables.getOnlyElement(FluentIterable
|
||||
.from(gainingPollMessage.getResponseData())
|
||||
.filter(PendingActionNotificationResponse.class));
|
||||
assertThat(panData.getTrid())
|
||||
.isEqualTo(Trid.create("transferClient-trid", "transferServer-trid"));
|
||||
assertThat(panData.getActionResult()).isTrue();
|
||||
}
|
||||
|
||||
private void doFailingTest(String commandFilename) throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_approve.xml");
|
||||
dryRunFlowAssertResponse(readFile("contact_transfer_approve_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_approve.xml", "contact_transfer_approve_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withAuthinfo() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_approve_with_authinfo.xml",
|
||||
"contact_transfer_approve_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactPassword() throws Exception {
|
||||
thrown.expect(BadAuthInfoForResourceException.class);
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
|
||||
.build());
|
||||
doFailingTest("contact_transfer_approve_with_authinfo.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(null);
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientApproved() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientRejected() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientCancelled() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverApproved() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverCancelled() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_gainingClient() throws Exception {
|
||||
thrown.expect(ResourceNotOwnedException.class);
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() throws Exception {
|
||||
thrown.expect(ResourceNotOwnedException.class);
|
||||
setClientIdForFlow("ClientZ");
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
deleteResource(contact);
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
doFailingTest("contact_transfer_approve.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.deleteResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getOnlyPollMessage;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getPollMessages;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
|
||||
import com.google.domain.registry.flows.ResourceMutateFlow.ResourceToMutateDoesNotExistException;
|
||||
import com.google.domain.registry.flows.ResourceMutatePendingTransferFlow.NotPendingTransferException;
|
||||
import com.google.domain.registry.flows.ResourceTransferCancelFlow.NotTransferInitiatorException;
|
||||
import com.google.domain.registry.model.contact.ContactAuthInfo;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import com.google.domain.registry.model.poll.PollMessage;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.transfer.TransferResponse;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferCancelFlow}. */
|
||||
public class ContactTransferCancelFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferCancelFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.setEppInput("contact_transfer_cancel.xml");
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename)
|
||||
throws Exception {
|
||||
this.setEppInput(commandFilename);
|
||||
// Look in the future and make sure the poll messages for implicit ack are there.
|
||||
assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1))).hasSize(1);
|
||||
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile(expectedXmlFilename));
|
||||
|
||||
// Transfer should have been cancelled. Verify correct fields were set.
|
||||
contact = reloadResourceByUniqueId();
|
||||
assertAboutContacts().that(contact)
|
||||
.hasCurrentSponsorClientId("TheRegistrar").and()
|
||||
.hasLastTransferTimeNotEqualTo(clock.nowUtc()).and()
|
||||
.hasTransferStatus(TransferStatus.CLIENT_CANCELLED).and()
|
||||
.hasPendingTransferExpirationTime(clock.nowUtc()).and()
|
||||
.hasOneHistoryEntryEachOfTypes(
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_REQUEST,
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_CANCEL);
|
||||
assertNoBillingEvents();
|
||||
// The poll message (in the future) to the gaining registrar for implicit ack should be gone.
|
||||
assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusMonths(1))).isEmpty();
|
||||
// The poll message in the future to the losing registrar should be gone too, but there
|
||||
// should be one at the current time to the losing registrar.
|
||||
PollMessage losingPollMessage = getOnlyPollMessage("TheRegistrar");
|
||||
assertThat(losingPollMessage.getEventTime()).isEqualTo(clock.nowUtc());
|
||||
assertThat(
|
||||
Iterables.getOnlyElement(FluentIterable
|
||||
.from(losingPollMessage.getResponseData())
|
||||
.filter(TransferResponse.class))
|
||||
.getTransferStatus())
|
||||
.isEqualTo(TransferStatus.CLIENT_CANCELLED);
|
||||
}
|
||||
|
||||
private void doFailingTest(String commandFilename) throws Exception {
|
||||
this.setEppInput(commandFilename);
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_cancel.xml");
|
||||
dryRunFlowAssertResponse(readFile("contact_transfer_cancel_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_cancel.xml", "contact_transfer_cancel_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withAuthinfo() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_cancel_with_authinfo.xml",
|
||||
"contact_transfer_cancel_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactPassword() throws Exception {
|
||||
thrown.expect(BadAuthInfoForResourceException.class);
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
|
||||
.build());
|
||||
doFailingTest("contact_transfer_cancel_with_authinfo.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(null);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientApproved() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientRejected() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientCancelled() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverApproved() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverCancelled() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sponsoringClient() throws Exception {
|
||||
thrown.expect(NotTransferInitiatorException.class);
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() throws Exception {
|
||||
thrown.expect(NotTransferInitiatorException.class);
|
||||
setClientIdForFlow("ClientZ");
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
deleteResource(contact);
|
||||
doFailingTest("contact_transfer_cancel.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newContactResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistContactWithPendingTransfer;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.domain.registry.flows.Flow;
|
||||
import com.google.domain.registry.flows.ResourceFlowTestCase;
|
||||
import com.google.domain.registry.model.EppResource;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
|
||||
/**
|
||||
* Base class for contact transfer flow unit tests.
|
||||
*
|
||||
* @param <F> the flow type
|
||||
* @param <R> the resource type
|
||||
*/
|
||||
public class ContactTransferFlowTestCase<F extends Flow, R extends EppResource>
|
||||
extends ResourceFlowTestCase<F, R>{
|
||||
|
||||
// Transfer is requested on the 6th and expires on the 11th.
|
||||
// The "now" of this flow is on the 9th, 3 days in.
|
||||
|
||||
private static final DateTime TRANSFER_REQUEST_TIME = DateTime.parse("2000-06-06T22:00:00.0Z");
|
||||
private static final DateTime TRANSFER_EXPIRATION_TIME =
|
||||
TRANSFER_REQUEST_TIME.plus(Registry.DEFAULT_TRANSFER_GRACE_PERIOD);
|
||||
private static final Duration TIME_SINCE_REQUEST = Duration.standardDays(3);
|
||||
|
||||
protected ContactResource contact;
|
||||
|
||||
public ContactTransferFlowTestCase() {
|
||||
checkState(!Registry.DEFAULT_TRANSFER_GRACE_PERIOD.isShorterThan(TIME_SINCE_REQUEST));
|
||||
clock.setTo(TRANSFER_REQUEST_TIME.plus(TIME_SINCE_REQUEST));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initContactTest() {
|
||||
// Registrar ClientZ is used in tests that need another registrar that definitely doesn't own
|
||||
// the resources in question.
|
||||
persistResource(
|
||||
AppEngineRule.makeRegistrar1().asBuilder().setClientIdentifier("ClientZ").build());
|
||||
}
|
||||
|
||||
/** Adds a contact that has a pending transfer on it from TheRegistrar to NewRegistrar. */
|
||||
protected void setupContactWithPendingTransfer() throws Exception {
|
||||
contact = persistContactWithPendingTransfer(
|
||||
newContactResource("sh8013"),
|
||||
TRANSFER_REQUEST_TIME,
|
||||
TRANSFER_EXPIRATION_TIME,
|
||||
TRANSFER_REQUEST_TIME);
|
||||
}
|
||||
|
||||
/** Changes the transfer status on the persisted contact. */
|
||||
protected void changeTransferStatus(TransferStatus transferStatus) {
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setTransferData(
|
||||
contact.getTransferData().asBuilder().setTransferStatus(transferStatus).build())
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
/** Changes the client ID that the flow will run as. */
|
||||
@Override
|
||||
protected void setClientIdForFlow(String clientId) {
|
||||
sessionMetadata.setClientId(clientId);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.deleteResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
|
||||
import com.google.domain.registry.flows.ResourceQueryFlow.ResourceToQueryDoesNotExistException;
|
||||
import com.google.domain.registry.flows.ResourceTransferQueryFlow.NoTransferHistoryToQueryException;
|
||||
import com.google.domain.registry.flows.ResourceTransferQueryFlow.NotAuthorizedToViewTransferException;
|
||||
import com.google.domain.registry.model.contact.ContactAuthInfo;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferQueryFlow}. */
|
||||
public class ContactTransferQueryFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferQueryFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
setEppInput("contact_transfer_query.xml");
|
||||
clock.setTo(DateTime.parse("2000-06-10T22:00:00.0Z"));
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename)
|
||||
throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(false);
|
||||
runFlowAssertResponse(readFile(expectedXmlFilename));
|
||||
assertAboutContacts().that(reloadResourceByUniqueIdYesterday())
|
||||
.hasOneHistoryEntryEachOfTypes(HistoryEntry.Type.CONTACT_TRANSFER_REQUEST);
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
private void doFailingTest(String commandFilename) throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
eppLoader.replaceAll("JD1234-REP", contact.getRepoId());
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(false);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_query.xml", "contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withContactRoid() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_query_with_roid.xml", "contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_sponsoringClient() throws Exception {
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
doSuccessfulTest("contact_transfer_query.xml", "contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_withAuthinfo() throws Exception {
|
||||
setClientIdForFlow("ClientZ");
|
||||
doSuccessfulTest("contact_transfer_query_with_authinfo.xml",
|
||||
"contact_transfer_query_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_client_approved.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientRejected() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_client_rejected.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_client_cancelled.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_server_approved.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_server_cancelled.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingDeleteContact() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().plusDays(1)).build());
|
||||
doSuccessfulTest("contact_transfer_query.xml",
|
||||
"contact_transfer_query_response_server_cancelled.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactPassword() throws Exception {
|
||||
thrown.expect(BadAuthInfoForResourceException.class);
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
|
||||
.build());
|
||||
doFailingTest("contact_transfer_query_with_authinfo.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badContactRoid() throws Exception {
|
||||
thrown.expect(BadAuthInfoForResourceException.class);
|
||||
// Set the contact to a different ROID, but don't persist it; this is just so the substitution
|
||||
// code above will write the wrong ROID into the file.
|
||||
contact = contact.asBuilder().setRepoId("DEADBEEF_TLD-ROID").build();
|
||||
doFailingTest("contact_transfer_query_with_roid.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() throws Exception {
|
||||
thrown.expect(NoTransferHistoryToQueryException.class);
|
||||
changeTransferStatus(null);
|
||||
doFailingTest("contact_transfer_query.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() throws Exception {
|
||||
thrown.expect(NotAuthorizedToViewTransferException.class);
|
||||
setClientIdForFlow("ClientZ");
|
||||
doFailingTest("contact_transfer_query.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToQueryDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
doFailingTest("contact_transfer_query.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToQueryDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
deleteResource(contact);
|
||||
doFailingTest("contact_transfer_query.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.deleteResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getOnlyPollMessage;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getPollMessages;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import com.google.domain.registry.flows.ResourceMutateFlow.ResourceToMutateDoesNotExistException;
|
||||
import com.google.domain.registry.flows.ResourceMutatePendingTransferFlow.NotPendingTransferException;
|
||||
import com.google.domain.registry.model.contact.ContactAuthInfo;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import com.google.domain.registry.model.eppcommon.Trid;
|
||||
import com.google.domain.registry.model.poll.PendingActionNotificationResponse;
|
||||
import com.google.domain.registry.model.poll.PollMessage;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.transfer.TransferResponse;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferRejectFlow}. */
|
||||
public class ContactTransferRejectFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferRejectFlow, ContactResource> {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
setEppInput("contact_transfer_reject.xml");
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
setupContactWithPendingTransfer();
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename)
|
||||
throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
// Look in the future and make sure the poll messages for implicit ack are there.
|
||||
assertThat(getPollMessages("NewRegistrar", clock.nowUtc().plusMonths(1)))
|
||||
.hasSize(1);
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1)))
|
||||
.hasSize(1);
|
||||
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile(expectedXmlFilename));
|
||||
|
||||
// Transfer should have failed. Verify correct fields were set.
|
||||
contact = reloadResourceByUniqueId();
|
||||
assertAboutContacts().that(contact)
|
||||
.hasCurrentSponsorClientId("TheRegistrar").and()
|
||||
.hasLastTransferTimeNotEqualTo(clock.nowUtc()).and()
|
||||
.hasTransferStatus(TransferStatus.CLIENT_REJECTED).and()
|
||||
.hasOneHistoryEntryEachOfTypes(
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_REQUEST,
|
||||
HistoryEntry.Type.CONTACT_TRANSFER_REJECT);
|
||||
// The poll message (in the future) to the losing registrar for implicit ack should be gone.
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc().plusMonths(1)))
|
||||
.isEmpty();
|
||||
// The poll message in the future to the gaining registrar should be gone too, but there
|
||||
// should be one at the current time to the gaining registrar.
|
||||
PollMessage gainingPollMessage = getOnlyPollMessage("NewRegistrar");
|
||||
assertThat(gainingPollMessage.getEventTime()).isEqualTo(clock.nowUtc());
|
||||
assertThat(
|
||||
Iterables.getOnlyElement(FluentIterable
|
||||
.from(gainingPollMessage.getResponseData())
|
||||
.filter(TransferResponse.class))
|
||||
.getTransferStatus())
|
||||
.isEqualTo(TransferStatus.CLIENT_REJECTED);
|
||||
PendingActionNotificationResponse panData = Iterables.getOnlyElement(FluentIterable
|
||||
.from(gainingPollMessage.getResponseData())
|
||||
.filter(PendingActionNotificationResponse.class));
|
||||
assertThat(panData.getTrid())
|
||||
.isEqualTo(Trid.create("transferClient-trid", "transferServer-trid"));
|
||||
assertThat(panData.getActionResult()).isFalse();
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
private void doFailingTest(String commandFilename) throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_reject.xml");
|
||||
dryRunFlowAssertResponse(readFile("contact_transfer_reject_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_reject.xml", "contact_transfer_reject_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_domainAuthInfo() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_reject_with_authinfo.xml",
|
||||
"contact_transfer_reject_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badPassword() throws Exception {
|
||||
thrown.expect(BadAuthInfoForResourceException.class);
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
|
||||
.build());
|
||||
doFailingTest("contact_transfer_reject_with_authinfo.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverBeenTransferred() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(null);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientApproved() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientRejected() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientCancelled() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverApproved() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverCancelled() throws Exception {
|
||||
thrown.expect(NotPendingTransferException.class);
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_gainingClient() throws Exception {
|
||||
thrown.expect(ResourceNotOwnedException.class);
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unrelatedClient() throws Exception {
|
||||
thrown.expect(ResourceNotOwnedException.class);
|
||||
setClientIdForFlow("ClientZ");
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
deleteResource(contact);
|
||||
doFailingTest("contact_transfer_reject.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.deleteResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.getPollMessages;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.domain.registry.config.RegistryEnvironment;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.BadAuthInfoForResourceException;
|
||||
import com.google.domain.registry.flows.ResourceMutateFlow.ResourceToMutateDoesNotExistException;
|
||||
import com.google.domain.registry.flows.ResourceTransferRequestFlow.AlreadyPendingTransferException;
|
||||
import com.google.domain.registry.flows.ResourceTransferRequestFlow.MissingTransferRequestAuthInfoException;
|
||||
import com.google.domain.registry.flows.ResourceTransferRequestFlow.ObjectAlreadySponsoredException;
|
||||
import com.google.domain.registry.model.contact.ContactAuthInfo;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.model.transfer.TransferStatus;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactTransferRequestFlow}. */
|
||||
public class ContactTransferRequestFlowTest
|
||||
extends ContactTransferFlowTestCase<ContactTransferRequestFlow, ContactResource> {
|
||||
|
||||
public ContactTransferRequestFlowTest() {
|
||||
// We need the transfer to happen at exactly this time in order for the response to match up.
|
||||
clock.setTo(DateTime.parse("2000-06-08T22:00:00.0Z"));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
setEppInput("contact_transfer_request.xml");
|
||||
setClientIdForFlow("NewRegistrar");
|
||||
contact = persistActiveContact("sh8013");
|
||||
clock.advanceOneMilli();
|
||||
}
|
||||
|
||||
private void doSuccessfulTest(String commandFilename, String expectedXmlFilename)
|
||||
throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
DateTime afterTransfer =
|
||||
clock.nowUtc().plus(RegistryEnvironment.get().config().getContactAutomaticTransferLength());
|
||||
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile(expectedXmlFilename));
|
||||
|
||||
// Transfer should have been requested. Verify correct fields were set.
|
||||
contact = reloadResourceByUniqueId();
|
||||
assertAboutContacts().that(contact)
|
||||
.hasTransferStatus(TransferStatus.PENDING).and()
|
||||
.hasTransferGainingClientId("NewRegistrar").and()
|
||||
.hasTransferLosingClientId("TheRegistrar").and()
|
||||
.hasTransferRequestTrid(getTrid()).and()
|
||||
.hasCurrentSponsorClientId("TheRegistrar").and()
|
||||
.hasPendingTransferExpirationTime(afterTransfer).and()
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasType(HistoryEntry.Type.CONTACT_TRANSFER_REQUEST);
|
||||
assertNoBillingEvents();
|
||||
assertThat(getPollMessages("TheRegistrar", clock.nowUtc())).hasSize(1);
|
||||
|
||||
// If we fast forward AUTOMATIC_TRANSFER_DAYS the transfer should have happened.
|
||||
assertAboutContacts().that(contact.cloneProjectedAtTime(afterTransfer))
|
||||
.hasCurrentSponsorClientId("NewRegistrar");
|
||||
assertThat(getPollMessages("NewRegistrar", afterTransfer)).hasSize(1);
|
||||
assertThat(getPollMessages("TheRegistrar", afterTransfer)).hasSize(2);
|
||||
}
|
||||
|
||||
private void doFailingTest(String commandFilename) throws Exception {
|
||||
setEppInput(commandFilename);
|
||||
// Setup done; run the test.
|
||||
assertTransactionalFlow(true);
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
setEppInput("contact_transfer_request.xml");
|
||||
dryRunFlowAssertResponse(readFile("contact_transfer_request_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_noAuthInfo() throws Exception {
|
||||
thrown.expect(MissingTransferRequestAuthInfoException.class);
|
||||
doFailingTest("contact_transfer_request_no_authinfo.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badPassword() throws Exception {
|
||||
thrown.expect(BadAuthInfoForResourceException.class);
|
||||
// Change the contact's password so it does not match the password in the file.
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setAuthInfo(ContactAuthInfo.create(PasswordAuth.create("badpassword")))
|
||||
.build());
|
||||
doFailingTest("contact_transfer_request.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientRejected() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_REJECTED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_clientCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.CLIENT_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverApproved() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_APPROVED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_serverCancelled() throws Exception {
|
||||
changeTransferStatus(TransferStatus.SERVER_CANCELLED);
|
||||
doSuccessfulTest("contact_transfer_request.xml", "contact_transfer_request_response.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pending() throws Exception {
|
||||
thrown.expect(AlreadyPendingTransferException.class);
|
||||
contact = persistResource(
|
||||
contact.asBuilder()
|
||||
.setTransferData(contact.getTransferData().asBuilder()
|
||||
.setTransferStatus(TransferStatus.PENDING)
|
||||
.setPendingTransferExpirationTime(clock.nowUtc().plusDays(1))
|
||||
.build())
|
||||
.build());
|
||||
doFailingTest("contact_transfer_request.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_sponsoringClient() throws Exception {
|
||||
thrown.expect(ObjectAlreadySponsoredException.class);
|
||||
setClientIdForFlow("TheRegistrar");
|
||||
doFailingTest("contact_transfer_request.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_deletedContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
contact = persistResource(
|
||||
contact.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||
doFailingTest("contact_transfer_request.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonexistentContact() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
deleteResource(contact);
|
||||
doFailingTest("contact_transfer_request.xml");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,265 @@
|
|||
// Copyright 2016 Google Inc. 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 com.google.domain.registry.flows.contact;
|
||||
|
||||
import static com.google.domain.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.assertNoBillingEvents;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.newContactResource;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistActiveContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistDeletedContact;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.flows.FlowRunner.CommitMode;
|
||||
import com.google.domain.registry.flows.FlowRunner.UserPrivileges;
|
||||
import com.google.domain.registry.flows.ResourceFlowTestCase;
|
||||
import com.google.domain.registry.flows.ResourceFlowUtils.ResourceNotOwnedException;
|
||||
import com.google.domain.registry.flows.ResourceMutateFlow.ResourceToMutateDoesNotExistException;
|
||||
import com.google.domain.registry.flows.ResourceUpdateFlow.ResourceHasClientUpdateProhibitedException;
|
||||
import com.google.domain.registry.flows.ResourceUpdateFlow.StatusNotClientSettableException;
|
||||
import com.google.domain.registry.flows.SingleResourceFlow.ResourceStatusProhibitsOperationException;
|
||||
import com.google.domain.registry.flows.contact.ContactFlowUtils.BadInternationalizedPostalInfoException;
|
||||
import com.google.domain.registry.flows.contact.ContactFlowUtils.DeclineContactDisclosureFieldDisallowedPolicyException;
|
||||
import com.google.domain.registry.model.contact.ContactAddress;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.contact.PostalInfo;
|
||||
import com.google.domain.registry.model.contact.PostalInfo.Type;
|
||||
import com.google.domain.registry.model.eppcommon.StatusValue;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/** Unit tests for {@link ContactUpdateFlow}. */
|
||||
public class ContactUpdateFlowTest
|
||||
extends ResourceFlowTestCase<ContactUpdateFlow, ContactResource> {
|
||||
|
||||
public ContactUpdateFlowTest() {
|
||||
setEppInput("contact_update.xml");
|
||||
}
|
||||
|
||||
private void doSuccessfulTest() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
assertTransactionalFlow(true);
|
||||
runFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
// Check that the contact was updated. This value came from the xml.
|
||||
assertAboutContacts().that(reloadResourceByUniqueId())
|
||||
.hasAuthInfoPwd("2fooBAR").and()
|
||||
.hasOnlyOneHistoryEntryWhich()
|
||||
.hasNoXml();
|
||||
assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDryRun() throws Exception {
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
dryRunFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception {
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_removeClientUpdateProhibited() throws Exception {
|
||||
setEppInput("contact_update_remove_client_update_prohibited.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
doSuccessfulTest();
|
||||
assertAboutContacts().that(reloadResourceByUniqueId())
|
||||
.doesNotHaveStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_updatingOnePostalInfoDeletesTheOther() throws Exception {
|
||||
ContactResource contact =
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("111 8th Ave", "4th Floor"))
|
||||
.setCity("New York")
|
||||
.setState("NY")
|
||||
.setZip("10011")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
// The test xml updates the internationalized postal info and should therefore implicitly delete
|
||||
// the localized one since they are treated as a pair for update purposes.
|
||||
assertAboutContacts().that(contact)
|
||||
.hasNonNullLocalizedPostalInfo().and()
|
||||
.hasInternationalizedPostalInfo(null);
|
||||
|
||||
runFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
assertAboutContacts().that(reloadResourceByUniqueId())
|
||||
.hasLocalizedPostalInfo(null).and()
|
||||
.hasNonNullInternationalizedPostalInfo();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_partialPostalInfoUpdate() throws Exception {
|
||||
setEppInput("contact_update_partial_postalinfo.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setLocalizedPostalInfo(new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("A. Person")
|
||||
.setOrg("Company Inc.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("123 4th st", "5th Floor"))
|
||||
.setCity("City")
|
||||
.setState("AB")
|
||||
.setZip("12345")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build())
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
// The test xml updates the address of the postal info and should leave the name untouched.
|
||||
runFlowAssertResponse(readFile("contact_update_response.xml"));
|
||||
assertAboutContacts().that(reloadResourceByUniqueId()).hasLocalizedPostalInfo(
|
||||
new PostalInfo.Builder()
|
||||
.setType(Type.LOCALIZED)
|
||||
.setName("A. Person")
|
||||
.setOrg("Company Inc.")
|
||||
.setAddress(new ContactAddress.Builder()
|
||||
.setStreet(ImmutableList.of("456 5th st"))
|
||||
.setCity("Place")
|
||||
.setState("CD")
|
||||
.setZip("54321")
|
||||
.setCountryCode("US")
|
||||
.build())
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_neverExisted() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_existedButWasDeleted() throws Exception {
|
||||
thrown.expect(
|
||||
ResourceToMutateDoesNotExistException.class,
|
||||
String.format("(%s)", getUniqueIdFromCommand()));
|
||||
persistDeletedContact(getUniqueIdFromCommand(), clock.nowUtc());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientProhibitedStatusValue() throws Exception {
|
||||
thrown.expect(StatusNotClientSettableException.class);
|
||||
setEppInput("contact_update_prohibited_status.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserClientProhibitedStatusValue() throws Exception {
|
||||
setEppInput("contact_update_prohibited_status.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE,
|
||||
UserPrivileges.SUPERUSER,
|
||||
readFile("contact_update_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unauthorizedClient() throws Exception {
|
||||
thrown.expect(ResourceNotOwnedException.class);
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserUnauthorizedClient() throws Exception {
|
||||
sessionMetadata.setSuperuser(true);
|
||||
sessionMetadata.setClientId("NewRegistrar");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE, UserPrivileges.SUPERUSER, readFile("contact_update_response.xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_superuserClientUpdateProhibited() throws Exception {
|
||||
setEppInput("contact_update_prohibited_status.xml");
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
clock.advanceOneMilli();
|
||||
runFlowAssertResponse(
|
||||
CommitMode.LIVE,
|
||||
UserPrivileges.SUPERUSER,
|
||||
readFile("contact_update_response.xml"));
|
||||
assertAboutContacts().that(reloadResourceByUniqueId())
|
||||
.hasStatusValue(StatusValue.CLIENT_UPDATE_PROHIBITED).and()
|
||||
.hasStatusValue(StatusValue.SERVER_DELETE_PROHIBITED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_clientUpdateProhibited() throws Exception {
|
||||
thrown.expect(ResourceHasClientUpdateProhibitedException.class);
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.CLIENT_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_serverUpdateProhibited() throws Exception {
|
||||
thrown.expect(ResourceStatusProhibitsOperationException.class);
|
||||
persistResource(
|
||||
newContactResource(getUniqueIdFromCommand()).asBuilder()
|
||||
.setStatusValues(ImmutableSet.of(StatusValue.SERVER_UPDATE_PROHIBITED))
|
||||
.build());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_nonAsciiInLocAddress() throws Exception {
|
||||
setEppInput("contact_update_hebrew_loc.xml");
|
||||
doSuccessfulTest();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonAsciiInIntAddress() throws Exception {
|
||||
thrown.expect(BadInternationalizedPostalInfoException.class);
|
||||
setEppInput("contact_update_hebrew_int.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
runFlow();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_declineDisclosure() throws Exception {
|
||||
thrown.expect(DeclineContactDisclosureFieldDisallowedPolicyException.class);
|
||||
setEppInput("contact_update_decline_disclosure.xml");
|
||||
persistActiveContact(getUniqueIdFromCommand());
|
||||
runFlow();
|
||||
}
|
||||
}
|
13
javatests/com/google/domain/registry/flows/contact/testdata/contact_check.xml
vendored
Normal file
13
javatests/com/google/domain/registry/flows/contact/testdata/contact_check.xml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<contact:check
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:id>sah8013</contact:id>
|
||||
<contact:id>8013sah</contact:id>
|
||||
</contact:check>
|
||||
</check>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
60
javatests/com/google/domain/registry/flows/contact/testdata/contact_check_50.xml
vendored
Normal file
60
javatests/com/google/domain/registry/flows/contact/testdata/contact_check_50.xml
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<contact:check
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>contact1</contact:id>
|
||||
<contact:id>contact2</contact:id>
|
||||
<contact:id>contact3</contact:id>
|
||||
<contact:id>contact4</contact:id>
|
||||
<contact:id>contact5</contact:id>
|
||||
<contact:id>contact6</contact:id>
|
||||
<contact:id>contact7</contact:id>
|
||||
<contact:id>contact8</contact:id>
|
||||
<contact:id>contact9</contact:id>
|
||||
<contact:id>contact10</contact:id>
|
||||
<contact:id>contact11</contact:id>
|
||||
<contact:id>contact12</contact:id>
|
||||
<contact:id>contact13</contact:id>
|
||||
<contact:id>contact14</contact:id>
|
||||
<contact:id>contact15</contact:id>
|
||||
<contact:id>contact16</contact:id>
|
||||
<contact:id>contact17</contact:id>
|
||||
<contact:id>contact18</contact:id>
|
||||
<contact:id>contact19</contact:id>
|
||||
<contact:id>contact20</contact:id>
|
||||
<contact:id>contact21</contact:id>
|
||||
<contact:id>contact22</contact:id>
|
||||
<contact:id>contact23</contact:id>
|
||||
<contact:id>contact24</contact:id>
|
||||
<contact:id>contact25</contact:id>
|
||||
<contact:id>contact26</contact:id>
|
||||
<contact:id>contact27</contact:id>
|
||||
<contact:id>contact28</contact:id>
|
||||
<contact:id>contact29</contact:id>
|
||||
<contact:id>contact30</contact:id>
|
||||
<contact:id>contact31</contact:id>
|
||||
<contact:id>contact32</contact:id>
|
||||
<contact:id>contact33</contact:id>
|
||||
<contact:id>contact34</contact:id>
|
||||
<contact:id>contact35</contact:id>
|
||||
<contact:id>contact36</contact:id>
|
||||
<contact:id>contact37</contact:id>
|
||||
<contact:id>contact38</contact:id>
|
||||
<contact:id>contact39</contact:id>
|
||||
<contact:id>contact40</contact:id>
|
||||
<contact:id>contact41</contact:id>
|
||||
<contact:id>contact42</contact:id>
|
||||
<contact:id>contact43</contact:id>
|
||||
<contact:id>contact44</contact:id>
|
||||
<contact:id>contact45</contact:id>
|
||||
<contact:id>contact46</contact:id>
|
||||
<contact:id>contact47</contact:id>
|
||||
<contact:id>contact48</contact:id>
|
||||
<contact:id>contact49</contact:id>
|
||||
<contact:id>contact50</contact:id>
|
||||
</contact:check>
|
||||
</check>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
61
javatests/com/google/domain/registry/flows/contact/testdata/contact_check_51.xml
vendored
Normal file
61
javatests/com/google/domain/registry/flows/contact/testdata/contact_check_51.xml
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<check>
|
||||
<contact:check
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>contact1</contact:id>
|
||||
<contact:id>contact2</contact:id>
|
||||
<contact:id>contact3</contact:id>
|
||||
<contact:id>contact4</contact:id>
|
||||
<contact:id>contact5</contact:id>
|
||||
<contact:id>contact6</contact:id>
|
||||
<contact:id>contact7</contact:id>
|
||||
<contact:id>contact8</contact:id>
|
||||
<contact:id>contact9</contact:id>
|
||||
<contact:id>contact10</contact:id>
|
||||
<contact:id>contact11</contact:id>
|
||||
<contact:id>contact12</contact:id>
|
||||
<contact:id>contact13</contact:id>
|
||||
<contact:id>contact14</contact:id>
|
||||
<contact:id>contact15</contact:id>
|
||||
<contact:id>contact16</contact:id>
|
||||
<contact:id>contact17</contact:id>
|
||||
<contact:id>contact18</contact:id>
|
||||
<contact:id>contact19</contact:id>
|
||||
<contact:id>contact20</contact:id>
|
||||
<contact:id>contact21</contact:id>
|
||||
<contact:id>contact22</contact:id>
|
||||
<contact:id>contact23</contact:id>
|
||||
<contact:id>contact24</contact:id>
|
||||
<contact:id>contact25</contact:id>
|
||||
<contact:id>contact26</contact:id>
|
||||
<contact:id>contact27</contact:id>
|
||||
<contact:id>contact28</contact:id>
|
||||
<contact:id>contact29</contact:id>
|
||||
<contact:id>contact30</contact:id>
|
||||
<contact:id>contact31</contact:id>
|
||||
<contact:id>contact32</contact:id>
|
||||
<contact:id>contact33</contact:id>
|
||||
<contact:id>contact34</contact:id>
|
||||
<contact:id>contact35</contact:id>
|
||||
<contact:id>contact36</contact:id>
|
||||
<contact:id>contact37</contact:id>
|
||||
<contact:id>contact38</contact:id>
|
||||
<contact:id>contact39</contact:id>
|
||||
<contact:id>contact40</contact:id>
|
||||
<contact:id>contact41</contact:id>
|
||||
<contact:id>contact42</contact:id>
|
||||
<contact:id>contact43</contact:id>
|
||||
<contact:id>contact44</contact:id>
|
||||
<contact:id>contact45</contact:id>
|
||||
<contact:id>contact46</contact:id>
|
||||
<contact:id>contact47</contact:id>
|
||||
<contact:id>contact48</contact:id>
|
||||
<contact:id>contact49</contact:id>
|
||||
<contact:id>contact50</contact:id>
|
||||
<contact:id>contact51</contact:id>
|
||||
</contact:check>
|
||||
</check>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
26
javatests/com/google/domain/registry/flows/contact/testdata/contact_check_response.xml
vendored
Normal file
26
javatests/com/google/domain/registry/flows/contact/testdata/contact_check_response.xml
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:chkData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:cd>
|
||||
<contact:id avail="1">sh8013</contact:id>
|
||||
</contact:cd>
|
||||
<contact:cd>
|
||||
<contact:id avail="0">sah8013</contact:id>
|
||||
<contact:reason>In use</contact:reason>
|
||||
</contact:cd>
|
||||
<contact:cd>
|
||||
<contact:id avail="1">8013sah</contact:id>
|
||||
</contact:cd>
|
||||
</contact:chkData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
33
javatests/com/google/domain/registry/flows/contact/testdata/contact_create.xml
vendored
Normal file
33
javatests/com/google/domain/registry/flows/contact/testdata/contact_create.xml
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<contact:create
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="1">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:create>
|
||||
</create>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -0,0 +1,33 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<contact:create
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="0">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:create>
|
||||
</create>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
45
javatests/com/google/domain/registry/flows/contact/testdata/contact_create_hebrew_int.xml
vendored
Normal file
45
javatests/com/google/domain/registry/flows/contact/testdata/contact_create_hebrew_int.xml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<contact:create
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>חנוך גולדפדר</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:postalInfo type="loc">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="1">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:create>
|
||||
</create>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
45
javatests/com/google/domain/registry/flows/contact/testdata/contact_create_hebrew_loc.xml
vendored
Normal file
45
javatests/com/google/domain/registry/flows/contact/testdata/contact_create_hebrew_loc.xml
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<create>
|
||||
<contact:create
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:postalInfo type="loc">
|
||||
<contact:name>חנוך גולדפדר</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="1">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:create>
|
||||
</create>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
18
javatests/com/google/domain/registry/flows/contact/testdata/contact_create_response.xml
vendored
Normal file
18
javatests/com/google/domain/registry/flows/contact/testdata/contact_create_response.xml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:creData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:crDate>1999-04-03T22:00:00.0Z</contact:crDate>
|
||||
</contact:creData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_delete.xml
vendored
Normal file
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_delete.xml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<delete>
|
||||
<contact:delete
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
</contact:delete>
|
||||
</delete>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_delete_response.xml
vendored
Normal file
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_delete_response.xml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1001">
|
||||
<msg>Command completed successfully; action pending</msg>
|
||||
</result>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
14
javatests/com/google/domain/registry/flows/contact/testdata/contact_info.xml
vendored
Normal file
14
javatests/com/google/domain/registry/flows/contact/testdata/contact_info.xml
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<info>
|
||||
<contact:info
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
</contact:info>
|
||||
</info>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
47
javatests/com/google/domain/registry/flows/contact/testdata/contact_info_response.xml
vendored
Normal file
47
javatests/com/google/domain/registry/flows/contact/testdata/contact_info_response.xml
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:infData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:roid>SH8013-REP</contact:roid>
|
||||
<contact:status s="clientDeleteProhibited"/>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:clID>TheRegistrar</contact:clID>
|
||||
<contact:crID>NewRegistrar</contact:crID>
|
||||
<contact:crDate>1999-04-03T22:00:00.0Z</contact:crDate>
|
||||
<contact:upID>NewRegistrar</contact:upID>
|
||||
<contact:upDate>1999-12-03T09:00:00.0Z</contact:upDate>
|
||||
<contact:trDate>2000-04-08T09:00:00.0Z</contact:trDate>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="1">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:infData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
48
javatests/com/google/domain/registry/flows/contact/testdata/contact_info_response_linked.xml
vendored
Normal file
48
javatests/com/google/domain/registry/flows/contact/testdata/contact_info_response_linked.xml
vendored
Normal file
|
@ -0,0 +1,48 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:infData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:roid>SH8013-REP</contact:roid>
|
||||
<contact:status s="linked"/>
|
||||
<contact:status s="clientDeleteProhibited"/>
|
||||
<contact:postalInfo type="int">
|
||||
<contact:name>John Doe</contact:name>
|
||||
<contact:org>Example Inc.</contact:org>
|
||||
<contact:addr>
|
||||
<contact:street>123 Example Dr.</contact:street>
|
||||
<contact:street>Suite 100</contact:street>
|
||||
<contact:city>Dulles</contact:city>
|
||||
<contact:sp>VA</contact:sp>
|
||||
<contact:pc>20166-6503</contact:pc>
|
||||
<contact:cc>US</contact:cc>
|
||||
</contact:addr>
|
||||
</contact:postalInfo>
|
||||
<contact:voice x="1234">+1.7035555555</contact:voice>
|
||||
<contact:fax>+1.7035555556</contact:fax>
|
||||
<contact:email>jdoe@example.com</contact:email>
|
||||
<contact:clID>TheRegistrar</contact:clID>
|
||||
<contact:crID>NewRegistrar</contact:crID>
|
||||
<contact:crDate>1999-04-03T22:00:00.0Z</contact:crDate>
|
||||
<contact:upID>NewRegistrar</contact:upID>
|
||||
<contact:upDate>1999-12-03T09:00:00.0Z</contact:upDate>
|
||||
<contact:trDate>2000-04-08T09:00:00.0Z</contact:trDate>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
<contact:disclose flag="1">
|
||||
<contact:voice/>
|
||||
<contact:email/>
|
||||
</contact:disclose>
|
||||
</contact:infData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_approve.xml
vendored
Normal file
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_approve.xml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="approve">
|
||||
<contact:transfer
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
</contact:transfer>
|
||||
</transfer>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>clientApproved</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-09T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,14 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="approve">
|
||||
<contact:transfer
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
</contact:transfer>
|
||||
</transfer>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_cancel.xml
vendored
Normal file
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_cancel.xml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="cancel">
|
||||
<contact:transfer
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
</contact:transfer>
|
||||
</transfer>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
22
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_cancel_response.xml
vendored
Normal file
22
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_cancel_response.xml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>clientCancelled</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-09T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,14 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="cancel">
|
||||
<contact:transfer
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:authInfo>
|
||||
<contact:pw>2fooBAR</contact:pw>
|
||||
</contact:authInfo>
|
||||
</contact:transfer>
|
||||
</transfer>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_query.xml
vendored
Normal file
11
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_query.xml
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<transfer op="query">
|
||||
<contact:transfer
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
</contact:transfer>
|
||||
</transfer>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
22
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_query_response.xml
vendored
Normal file
22
javatests/com/google/domain/registry/flows/contact/testdata/contact_transfer_query_response.xml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>pending</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-11T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>clientApproved</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-11T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>clientCancelled</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-11T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>clientRejected</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-11T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>serverApproved</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-11T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
|
@ -0,0 +1,22 @@
|
|||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<response>
|
||||
<result code="1000">
|
||||
<msg>Command completed successfully</msg>
|
||||
</result>
|
||||
<resData>
|
||||
<contact:trnData
|
||||
xmlns:contact="urn:ietf:params:xml:ns:contact-1.0">
|
||||
<contact:id>sh8013</contact:id>
|
||||
<contact:trStatus>serverCancelled</contact:trStatus>
|
||||
<contact:reID>NewRegistrar</contact:reID>
|
||||
<contact:reDate>2000-06-06T22:00:00.0Z</contact:reDate>
|
||||
<contact:acID>TheRegistrar</contact:acID>
|
||||
<contact:acDate>2000-06-11T22:00:00.0Z</contact:acDate>
|
||||
</contact:trnData>
|
||||
</resData>
|
||||
<trID>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
<svTRID>server-trid</svTRID>
|
||||
</trID>
|
||||
</response>
|
||||
</epp>
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue