mirror of
https://github.com/google/nomulus.git
synced 2025-08-06 09:45:19 +02:00
mv com/google/domain/registry google/registry
This change renames directories in preparation for the great package rename. The repository is now in a broken state because the code itself hasn't been updated. However this should ensure that git correctly preserves history for each file.
This commit is contained in:
parent
a41677aea1
commit
5012893c1d
2396 changed files with 0 additions and 0 deletions
133
javatests/google/registry/model/ofy/CommitLogBucketTest.java
Normal file
133
javatests/google/registry/model/ofy/CommitLogBucketTest.java
Normal file
|
@ -0,0 +1,133 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.getBucketKey;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.loadAllBuckets;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.loadBucket;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.persistResource;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
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.RegistryConfigRule;
|
||||
|
||||
import com.googlecode.objectify.annotation.Cache;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for {@link CommitLogBucket}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CommitLogBucketTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
CommitLogBucket bucket;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
// Use 10 buckets to make the tests below more realistic.
|
||||
configRule.override(new TestRegistryConfig() {
|
||||
@Override
|
||||
public int getCommitLogBucketCount() {
|
||||
return 10;
|
||||
}});
|
||||
// Save the bucket with some non-default properties set so that we can distinguish a correct
|
||||
// load from one that returns a newly created bucket instance.
|
||||
bucket = persistResource(
|
||||
new CommitLogBucket.Builder()
|
||||
.setLastWrittenTime(END_OF_TIME)
|
||||
.setBucketNum(1)
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBucketKey_createsBucketKeyInDefaultNamespace() {
|
||||
// Key.getNamespace() returns the empty string for the default namespace, not null.
|
||||
assertThat(getBucketKey(1).getRaw().getNamespace()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBucketKey_bucketNumberTooLow_throws() {
|
||||
thrown.expect(IllegalArgumentException.class, "0 not in [");
|
||||
getBucketKey(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBucketKey_bucketNumberTooHigh_throws() {
|
||||
thrown.expect(IllegalArgumentException.class, "11 not in [");
|
||||
getBucketKey(11);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getArbitraryBucketId_withSupplierOverridden() {
|
||||
inject.setStaticField(
|
||||
CommitLogBucket.class, "bucketIdSupplier", Suppliers.ofInstance(4)); // xkcd.com/221
|
||||
// Try multiple times just in case it's actually still random. If it is, the probability of
|
||||
// this test passing is googol^-1, so I think we're pretty safe.
|
||||
for (int i = 0; i < 100; i++) {
|
||||
assertThat(CommitLogBucket.getArbitraryBucketId()).isEqualTo(4);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_loadBucket_loadsTheBucket() {
|
||||
assertThat(loadBucket(getBucketKey(1))).isEqualTo(bucket);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_loadBucket_forNonexistentBucket_returnsNewBucket() {
|
||||
assertThat(loadBucket(getBucketKey(10))).isEqualTo(
|
||||
new CommitLogBucket.Builder().setBucketNum(10).build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_loadAllBuckets_loadsExistingBuckets_orNewOnesIfNonexistent() {
|
||||
ImmutableSet<CommitLogBucket> buckets = loadAllBuckets();
|
||||
assertThat(buckets).hasSize(10);
|
||||
assertThat(buckets).contains(bucket);
|
||||
for (int i = 2; i <= 10; ++i) {
|
||||
assertThat(buckets).contains(
|
||||
new CommitLogBucket.Builder().setBucketNum(i).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_noCacheAnnotation() {
|
||||
// Don't ever put @Cache on CommitLogBucket; it could mess up the checkpointing algorithm.
|
||||
assertThat(CommitLogBucket.class.isAnnotationPresent(Cache.class)).isFalse();
|
||||
}
|
||||
}
|
107
javatests/google/registry/model/ofy/CommitLogCheckpointTest.java
Normal file
107
javatests/google/registry/model/ofy/CommitLogCheckpointTest.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static org.joda.time.DateTimeZone.UTC;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.domain.registry.config.TestRegistryConfig;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
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.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for {@link CommitLogCheckpoint}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CommitLogCheckpointTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final RegistryConfigRule configRule = new RegistryConfigRule();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
private static final DateTime T1 = START_OF_TIME;
|
||||
private static final DateTime T2 = START_OF_TIME.plusMillis(1);
|
||||
private static final DateTime T3 = START_OF_TIME.plusMillis(2);
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
// Use 3 buckets to make the tests below more realistic.
|
||||
configRule.override(new TestRegistryConfig() {
|
||||
@Override
|
||||
public int getCommitLogBucketCount() {
|
||||
return 3;
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getCheckpointTime() {
|
||||
DateTime now = DateTime.now(UTC);
|
||||
CommitLogCheckpoint checkpoint =
|
||||
CommitLogCheckpoint.create(now, ImmutableMap.of(1, T1, 2, T2, 3, T3));
|
||||
assertThat(checkpoint.getCheckpointTime()).isEqualTo(now);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBucketTimestamps() {
|
||||
CommitLogCheckpoint checkpoint =
|
||||
CommitLogCheckpoint.create(DateTime.now(UTC), ImmutableMap.of(1, T1, 2, T2, 3, T3));
|
||||
assertThat(checkpoint.getBucketTimestamps()).containsExactly(1, T1, 2, T2, 3, T3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBucketTimestamps_whenOnlyOneBucket_stillWorks() {
|
||||
configRule.override(new TestRegistryConfig() {
|
||||
@Override
|
||||
public int getCommitLogBucketCount() {
|
||||
return 1;
|
||||
}});
|
||||
CommitLogCheckpoint checkpoint =
|
||||
CommitLogCheckpoint.create(DateTime.now(UTC), ImmutableMap.of(1, T1));
|
||||
assertThat(checkpoint.getBucketTimestamps()).containsExactly(1, T1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_create_notEnoughBucketTimestamps_throws() {
|
||||
thrown.expect(IllegalArgumentException.class, "Bucket ids are incorrect");
|
||||
CommitLogCheckpoint.create(DateTime.now(UTC), ImmutableMap.of(1, T1, 2, T2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_create_tooManyBucketTimestamps_throws() {
|
||||
thrown.expect(IllegalArgumentException.class, "Bucket ids are incorrect");
|
||||
CommitLogCheckpoint.create(DateTime.now(UTC), ImmutableMap.of(1, T1, 2, T2, 3, T3, 4, T1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_create_wrongBucketIds_throws() {
|
||||
thrown.expect(IllegalArgumentException.class, "Bucket ids are incorrect");
|
||||
CommitLogCheckpoint.create(DateTime.now(UTC), ImmutableMap.of(0, T1, 1, T2, 2, T3));
|
||||
}
|
||||
}
|
104
javatests/google/registry/model/ofy/CommitLogMutationTest.java
Normal file
104
javatests/google/registry/model/ofy/CommitLogMutationTest.java
Normal file
|
@ -0,0 +1,104 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.testing.DatastoreHelper.createTld;
|
||||
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.appengine.api.datastore.EntityTranslator;
|
||||
import com.google.appengine.api.datastore.KeyFactory;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.model.registry.Registry;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Work;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for {@link CommitLogMutation}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CommitLogMutationTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
private static final DateTime NOW = DateTime.now(DateTimeZone.UTC);
|
||||
|
||||
private Key<CommitLogManifest> manifestKey;
|
||||
private ImmutableObject someObject;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
// Initialize this late to avoid dependency on NamespaceManager prior to AppEngineRule.
|
||||
manifestKey = CommitLogManifest.createKey(CommitLogBucket.getBucketKey(1), NOW);
|
||||
createTld("tld");
|
||||
someObject = Registry.get("tld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_createKey_createsKeyWithWebsafeKeystring() {
|
||||
Key<CommitLogMutation> mutationKey =
|
||||
CommitLogMutation.createKey(manifestKey, Key.create(someObject));
|
||||
assertThat(mutationKey.getParent()).isEqualTo(manifestKey);
|
||||
assertThat(mutationKey.getName())
|
||||
.isEqualTo(KeyFactory.keyToString(Key.create(someObject).getRaw()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_create_createsExpectedMutation() {
|
||||
Entity rawEntity = convertToEntityInTxn(someObject);
|
||||
// Needs to be in a transaction so that registry-saving-to-entity will work.
|
||||
CommitLogMutation mutation = ofy().transact(new Work<CommitLogMutation>() {
|
||||
@Override
|
||||
public CommitLogMutation run() {
|
||||
return CommitLogMutation.create(manifestKey, someObject);
|
||||
}});
|
||||
assertThat(Key.create(mutation))
|
||||
.isEqualTo(CommitLogMutation.createKey(manifestKey, Key.create(someObject)));
|
||||
assertThat(mutation.getEntity()).isEqualTo(rawEntity);
|
||||
assertThat(EntityTranslator.createFromPbBytes(mutation.getEntityProtoBytes()))
|
||||
.isEqualTo(rawEntity);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_createRaw_createsExpectedMutation() {
|
||||
Entity rawEntity = convertToEntityInTxn(someObject);
|
||||
CommitLogMutation mutation = CommitLogMutation.createFromRaw(manifestKey, rawEntity);
|
||||
assertThat(Key.create(mutation))
|
||||
.isEqualTo(CommitLogMutation.createKey(manifestKey, Key.create(someObject)));
|
||||
assertThat(mutation.getEntity()).isEqualTo(rawEntity);
|
||||
assertThat(EntityTranslator.createFromPbBytes(mutation.getEntityProtoBytes()))
|
||||
.isEqualTo(rawEntity);
|
||||
}
|
||||
|
||||
private static Entity convertToEntityInTxn(final ImmutableObject object) {
|
||||
return ofy().transact(new Work<Entity>() {
|
||||
@Override
|
||||
public Entity run() {
|
||||
return ofy().save().toEntity(object);
|
||||
}});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
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;
|
||||
|
||||
/** Tests for our replacement for ObjectifyService. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class ObjectifyServiceTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Test
|
||||
public void test_initOfy_canBeCalledTwice() {
|
||||
ObjectifyService.initOfy();
|
||||
ObjectifyService.initOfy();
|
||||
}
|
||||
}
|
424
javatests/google/registry/model/ofy/OfyCommitLogTest.java
Normal file
424
javatests/google/registry/model/ofy/OfyCommitLogTest.java
Normal file
|
@ -0,0 +1,424 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
import static com.google.appengine.api.datastore.EntityTranslator.convertToPb;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static com.google.domain.registry.model.ofy.CommitLogBucket.getBucketKey;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.googlecode.objectify.ObjectifyService.register;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.domain.registry.model.BackupGroupRoot;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.model.common.EntityGroupRoot;
|
||||
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 com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
|
||||
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;
|
||||
|
||||
/** Unit tests ensuring {@link Ofy} saves transactions to {@link CommitLogManifest}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class OfyCommitLogTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
@Rule
|
||||
public final InjectRule inject = new InjectRule();
|
||||
|
||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
register(Root.class);
|
||||
register(Child.class);
|
||||
inject.setStaticField(Ofy.class, "clock", clock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_doesNothing_noCommitLogIsSaved() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {}
|
||||
});
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_savesDataAndCommitLog() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now().value)
|
||||
.isEqualTo("value");
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).hasSize(1);
|
||||
assertThat(ofy().load().type(CommitLogMutation.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_saveWithoutBackup_noCommitLogIsSaved() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().saveWithoutBackup().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now().value)
|
||||
.isEqualTo("value");
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).isEmpty();
|
||||
assertThat(ofy().load().type(CommitLogMutation.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_deleteWithoutBackup_noCommitLogIsSaved() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().saveWithoutBackup().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().deleteWithoutBackup().entity(Key.create(Root.class, 1));
|
||||
}});
|
||||
assertThat(ofy().load().key(Key.create(Root.class, 1)).now()).isNull();
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).isEmpty();
|
||||
assertThat(ofy().load().type(CommitLogMutation.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_savesEntity_itsProtobufFormIsStoredInCommitLog() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
final byte[] entityProtoBytes =
|
||||
ofy().load().type(CommitLogMutation.class).first().now().entityProtoBytes;
|
||||
// This transaction is needed so that save().toEntity() can access ofy().getTransactionTime()
|
||||
// when it attempts to set the update timestamp.
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
assertThat(entityProtoBytes).isEqualTo(
|
||||
convertToPb(ofy().save().toEntity(Root.create(1, getCrossTldKey()))).toByteArray());
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_savesEntity_mutationIsChildOfManifest() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
assertThat(ofy().load()
|
||||
.type(CommitLogMutation.class)
|
||||
.ancestor(ofy().load().type(CommitLogManifest.class).first().now()))
|
||||
.hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactNew_savesDataAndCommitLog() throws Exception {
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
assertThat(ofy().load()
|
||||
.key(Key.create(getCrossTldKey(), Root.class, 1))
|
||||
.now().value).isEqualTo("value");
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).hasSize(1);
|
||||
assertThat(ofy().load().type(CommitLogMutation.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_multipleSaves_logsMultipleMutations() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey())).now();
|
||||
ofy().save().entity(Root.create(2, getCrossTldKey())).now();
|
||||
}});
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).hasSize(1);
|
||||
assertThat(ofy().load().type(CommitLogMutation.class)).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_deletion_deletesAndLogsWithoutMutation() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().saveWithoutBackup().entity(Root.create(1, getCrossTldKey())).now();
|
||||
}});
|
||||
clock.advanceOneMilli();
|
||||
final Key<Root> otherTldKey = Key.create(getCrossTldKey(), Root.class, 1);
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().key(otherTldKey);
|
||||
}});
|
||||
assertThat(ofy().load().key(otherTldKey).now()).isNull();
|
||||
assertThat(ofy().load().type(CommitLogManifest.class)).hasSize(1);
|
||||
assertThat(ofy().load().type(CommitLogMutation.class)).isEmpty();
|
||||
assertThat(ofy().load().type(CommitLogManifest.class).first().now().getDeletions())
|
||||
.containsExactly(otherTldKey);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactNew_deleteNotBackedUpKind_throws() throws Exception {
|
||||
final CommitLogManifest backupsArentAllowedOnMe =
|
||||
CommitLogManifest.create(getBucketKey(1), DateTime.now(), ImmutableSet.<Key<?>>of());
|
||||
thrown.expect(IllegalArgumentException.class, "Can't save/delete a @NotBackedUp");
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().entity(backupsArentAllowedOnMe);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactNew_saveNotBackedUpKind_throws() throws Exception {
|
||||
final CommitLogManifest backupsArentAllowedOnMe =
|
||||
CommitLogManifest.create(getBucketKey(1), DateTime.now(), ImmutableSet.<Key<?>>of());
|
||||
ofy().saveWithoutBackup().entity(backupsArentAllowedOnMe).now();
|
||||
thrown.expect(IllegalArgumentException.class, "Can't save/delete a @NotBackedUp");
|
||||
ofy().transactNew(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(backupsArentAllowedOnMe);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_twoSavesOnSameKey_throws() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class, "Multiple entries with same key");
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_saveAndDeleteSameKey_throws() throws Exception {
|
||||
thrown.expect(IllegalArgumentException.class, "Multiple entries with same key");
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
ofy().delete().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingRootAndChild_updatesTimestampOnBackupGroupRoot() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
clock.advanceOneMilli();
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
ofy().save().entity(new Child());
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingOnlyChild_updatesTimestampOnBackupGroupRoot() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
clock.advanceOneMilli();
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(new Child());
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletingChild_updatesTimestampOnBackupGroupRoot() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
clock.advanceOneMilli();
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
// The fact that the child was never persisted is irrelevant.
|
||||
ofy().delete().entity(new Child());
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadingRoot_doesntUpdateTimestamp() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
clock.advanceOneMilli();
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
// Don't remove this line, as without saving *something* the commit log co/de will never
|
||||
// be invoked and the test will trivially pass
|
||||
ofy().save().entity(Root.create(2, getCrossTldKey()));
|
||||
ofy().load().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc().minusMillis(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadingChild_doesntUpdateTimestampOnBackupGroupRoot() throws Exception {
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
clock.advanceOneMilli();
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
// Don't remove this line, as without saving *something* the commit log co/de will never
|
||||
// be invoked and the test will trivially pass
|
||||
ofy().save().entity(Root.create(2, getCrossTldKey()));
|
||||
ofy().load().entity(new Child()); // All Child objects are under Root(1).
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc().minusMillis(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingAcrossBackupGroupRoots_updatesCorrectTimestamps() throws Exception {
|
||||
// Create three roots.
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(Root.create(1, getCrossTldKey()));
|
||||
ofy().save().entity(Root.create(2, getCrossTldKey()));
|
||||
ofy().save().entity(Root.create(3, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, i)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
}
|
||||
clock.advanceOneMilli();
|
||||
// Mutate one root, and a child of a second, ignoring the third.
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(new Child()); // All Child objects are under Root(1).
|
||||
ofy().save().entity(Root.create(2, getCrossTldKey()));
|
||||
}});
|
||||
ofy().clearSessionCache();
|
||||
// Child was touched.
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 1)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
// Directly touched.
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 2)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc());
|
||||
// Wasn't touched.
|
||||
assertThat(ofy().load().key(Key.create(getCrossTldKey(), Root.class, 3)).now()
|
||||
.getUpdateAutoTimestamp().getTimestamp()).isEqualTo(clock.nowUtc().minusMillis(1));
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class Root extends BackupGroupRoot {
|
||||
|
||||
@Parent
|
||||
Key<EntityGroupRoot> parent;
|
||||
|
||||
@Id
|
||||
long id;
|
||||
|
||||
String value;
|
||||
|
||||
static Root create(long id, Key<EntityGroupRoot> parent) {
|
||||
Root result = new Root();
|
||||
result.parent = parent;
|
||||
result.id = id;
|
||||
result.value = "value";
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity
|
||||
static class Child extends ImmutableObject {
|
||||
@Parent
|
||||
Key<Root> parent = Key.create(Root.create(1, getCrossTldKey()));
|
||||
|
||||
@Id
|
||||
long id = 1;
|
||||
}
|
||||
}
|
100
javatests/google/registry/model/ofy/OfyFilterTest.java
Normal file
100
javatests/google/registry/model/ofy/OfyFilterTest.java
Normal file
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.initOfy;
|
||||
|
||||
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
|
||||
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
|
||||
import com.google.domain.registry.model.registrar.Registrar;
|
||||
import com.google.domain.registry.model.registrar.Registrar.Type;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.ObjectifyFactory;
|
||||
import com.googlecode.objectify.ObjectifyFilter;
|
||||
import com.googlecode.objectify.ObjectifyService;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Tests for our replacement Objectify filter. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class OfyFilterTest {
|
||||
|
||||
private LocalServiceTestHelper helper;
|
||||
private ObjectifyFactory factory;
|
||||
|
||||
// We can't use AppEngineRule, because it triggers the precise behavior that we are testing.
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()).setUp();
|
||||
// Clear out the factory so that it requires re-registration on each test method.
|
||||
// Otherwise, static registration of types in one method would persist across methods.
|
||||
initOfy();
|
||||
factory = ObjectifyService.factory();
|
||||
ObjectifyService.setFactory(new ObjectifyFactory(false));
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
ObjectifyFilter.complete();
|
||||
ObjectifyService.setFactory(factory);
|
||||
ObjectifyFilter.complete();
|
||||
helper.tearDown();
|
||||
}
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
/**
|
||||
* Key.create looks up kind metadata for the class of the object it is given. If this happens
|
||||
* before the first reference to ObjectifyService, which statically triggers type registrations,
|
||||
* then the create will fail. Note that this is only a problem if the type in question doesn't
|
||||
* call ObjectifyService.allocateId() inside its own builder or create method, since if it
|
||||
* does that would trigger the statics as well. In this example, Registrar has a string id, so
|
||||
* the bug occurs, were it not for OfyFilter.
|
||||
*/
|
||||
@Test
|
||||
public void testFilterRegistersTypes() throws Exception {
|
||||
Registrar registrar = new Registrar.Builder()
|
||||
.setType(Type.TEST)
|
||||
.setClientIdentifier("registrar")
|
||||
.build();
|
||||
try {
|
||||
Key.create(registrar);
|
||||
} catch (IllegalStateException e) {
|
||||
assertThat(e).hasMessage(
|
||||
"class com.google.domain.registry.model.registrar.Registrar has not been registered");
|
||||
}
|
||||
}
|
||||
|
||||
/** The filter should register all types for us. */
|
||||
@Test
|
||||
public void testKeyCreateAfterFilter() throws Exception {
|
||||
new OfyFilter().init(null);
|
||||
Registrar registrar = new Registrar.Builder()
|
||||
.setType(Type.TEST)
|
||||
.setClientIdentifier("registrar")
|
||||
.build();
|
||||
Key.create(registrar);
|
||||
}
|
||||
}
|
408
javatests/google/registry/model/ofy/OfyTest.java
Normal file
408
javatests/google/registry/model/ofy/OfyTest.java
Normal file
|
@ -0,0 +1,408 @@
|
|||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package com.google.domain.registry.model.ofy;
|
||||
|
||||
import static com.google.appengine.api.datastore.DatastoreServiceFactory.getDatastoreService;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.util.concurrent.Uninterruptibles.sleepUninterruptibly;
|
||||
import static com.google.domain.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static com.google.domain.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static com.google.domain.registry.model.ofy.Ofy.getBaseEntityClassFromEntityOrKey;
|
||||
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.persistActiveContact;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
import static com.google.domain.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import com.google.appengine.api.datastore.DatastoreFailureException;
|
||||
import com.google.appengine.api.datastore.DatastoreTimeoutException;
|
||||
import com.google.appengine.api.datastore.Entity;
|
||||
import com.google.appengine.api.taskqueue.TransientFailureException;
|
||||
import com.google.domain.registry.model.ImmutableObject;
|
||||
import com.google.domain.registry.model.contact.ContactResource;
|
||||
import com.google.domain.registry.model.domain.DomainBase;
|
||||
import com.google.domain.registry.model.domain.DomainResource;
|
||||
import com.google.domain.registry.model.eppcommon.Trid;
|
||||
import com.google.domain.registry.model.reporting.HistoryEntry;
|
||||
import com.google.domain.registry.testing.AppEngineRule;
|
||||
import com.google.domain.registry.testing.DatastoreHelper;
|
||||
import com.google.domain.registry.testing.ExceptionRule;
|
||||
import com.google.domain.registry.testing.FakeClock;
|
||||
import com.google.domain.registry.util.SystemClock;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.VoidWork;
|
||||
import com.googlecode.objectify.Work;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.OnLoad;
|
||||
import com.googlecode.objectify.annotation.OnSave;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
|
||||
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.ConcurrentModificationException;
|
||||
|
||||
/** Tests for our wrapper around Objectify. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class OfyTest {
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final ExceptionRule thrown = new ExceptionRule();
|
||||
|
||||
/** An entity to use in save and delete tests. */
|
||||
private HistoryEntry someObject;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
createTld("tld");
|
||||
someObject = new HistoryEntry.Builder()
|
||||
.setClientId("client id")
|
||||
.setModificationTime(START_OF_TIME)
|
||||
.setParent(persistActiveContact("parentContact"))
|
||||
.setTrid(Trid.create("client", "server"))
|
||||
.setXmlBytes("<xml></xml>".getBytes(UTF_8))
|
||||
.build();
|
||||
// This can't be initialized earlier because namespaces need the AppEngineRule to work.
|
||||
}
|
||||
|
||||
private void doBackupGroupRootTimestampInversionTest(VoidWork work) {
|
||||
DateTime groupTimestamp = someObject.getParent().get().getUpdateAutoTimestamp().getTimestamp();
|
||||
// Set the clock in Ofy to the same time as the backup group root's save time.
|
||||
Ofy ofy = new Ofy(new FakeClock(groupTimestamp));
|
||||
thrown.expect(
|
||||
TimestampInversionException.class,
|
||||
String.format(
|
||||
"Timestamp inversion between transaction time (%s) and entities rooted under:\n"
|
||||
+ "{Key<?>(ContactResource(\"2-ROID\"))=%s}",
|
||||
groupTimestamp,
|
||||
groupTimestamp));
|
||||
ofy.transact(work);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackupGroupRootTimestampsMustIncreaseOnSave() {
|
||||
doBackupGroupRootTimestampInversionTest(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBackupGroupRootTimestampsMustIncreaseOnDelete() {
|
||||
doBackupGroupRootTimestampInversionTest(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().entity(someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingKeyTwice() {
|
||||
thrown.expect(IllegalArgumentException.class, "Multiple entries with same key");
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(someObject);
|
||||
ofy().save().entity(someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletingKeyTwice() {
|
||||
thrown.expect(IllegalArgumentException.class, "Multiple entries with same key");
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().entity(someObject);
|
||||
ofy().delete().entity(someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSaveDeleteKey() {
|
||||
thrown.expect(IllegalArgumentException.class, "Multiple entries with same key");
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(someObject);
|
||||
ofy().delete().entity(someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteSaveKey() {
|
||||
thrown.expect(IllegalArgumentException.class, "Multiple entries with same key");
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().delete().entity(someObject);
|
||||
ofy().save().entity(someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSavingKeyTwiceInOneCall() {
|
||||
thrown.expect(IllegalArgumentException.class);
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entities(someObject, someObject);
|
||||
}});
|
||||
}
|
||||
|
||||
/** Simple entity class with lifecycle callbacks. */
|
||||
@com.googlecode.objectify.annotation.Entity
|
||||
public static class LifecycleObject extends ImmutableObject {
|
||||
|
||||
@Parent
|
||||
Key<?> parent = getCrossTldKey();
|
||||
|
||||
@Id
|
||||
long id = 1;
|
||||
|
||||
boolean onLoadCalled;
|
||||
boolean onSaveCalled;
|
||||
|
||||
@OnLoad
|
||||
public void load() {
|
||||
onLoadCalled = true;
|
||||
}
|
||||
|
||||
@OnSave
|
||||
public void save() {
|
||||
onSaveCalled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleCallbacks_loadFromEntity() {
|
||||
ofy().factory().register(LifecycleObject.class);
|
||||
LifecycleObject object = new LifecycleObject();
|
||||
Entity entity = ofy().save().toEntity(object);
|
||||
assertThat(object.onSaveCalled).isTrue();
|
||||
assertThat(ofy().load().<LifecycleObject>fromEntity(entity).onLoadCalled).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLifecycleCallbacks_loadFromDatastore() {
|
||||
ofy().factory().register(LifecycleObject.class);
|
||||
final LifecycleObject object = new LifecycleObject();
|
||||
ofy().transact(new VoidWork() {
|
||||
@Override
|
||||
public void vrun() {
|
||||
ofy().save().entity(object).now();
|
||||
}});
|
||||
assertThat(object.onSaveCalled).isTrue();
|
||||
ofy().clearSessionCache();
|
||||
assertThat(ofy().load().entity(object).now().onLoadCalled).isTrue();
|
||||
}
|
||||
|
||||
/** Avoid regressions of b/21309102 where transaction time did not change on each retry. */
|
||||
@Test
|
||||
public void testTransact_getsNewTimestampOnEachTry() {
|
||||
ofy().transact(new VoidWork() {
|
||||
|
||||
DateTime firstAttemptTime;
|
||||
|
||||
@Override
|
||||
public void vrun() {
|
||||
if (firstAttemptTime == null) {
|
||||
// Sleep a bit to ensure that the next attempt is at a new millisecond.
|
||||
firstAttemptTime = ofy().getTransactionTime();
|
||||
sleepUninterruptibly(10, MILLISECONDS);
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
assertThat(ofy().getTransactionTime()).isGreaterThan(firstAttemptTime);
|
||||
}});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_transientFailureException_retries() {
|
||||
assertThat(ofy().transact(new Work<Integer>() {
|
||||
|
||||
int count = 0;
|
||||
|
||||
@Override
|
||||
public Integer run() {
|
||||
count++;
|
||||
if (count == 3) {
|
||||
return count;
|
||||
}
|
||||
throw new TransientFailureException("");
|
||||
}})).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_datastoreTimeoutException_noManifest_retries() {
|
||||
assertThat(ofy().transact(new Work<Integer>() {
|
||||
|
||||
int count = 0;
|
||||
|
||||
@Override
|
||||
public Integer run() {
|
||||
// We don't write anything in this transaction, so there is no commit log manifest.
|
||||
// Therefore it's always safe to retry since nothing got written.
|
||||
count++;
|
||||
if (count == 3) {
|
||||
return count;
|
||||
}
|
||||
throw new DatastoreTimeoutException("");
|
||||
}})).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_datastoreTimeoutException_manifestNotWrittenToDatastore_retries() {
|
||||
assertThat(ofy().transact(new Work<Integer>() {
|
||||
|
||||
int count = 0;
|
||||
|
||||
@Override
|
||||
public Integer run() {
|
||||
// There will be something in the manifest now, but it won't be committed if we throw.
|
||||
ofy().save().entity(someObject);
|
||||
count++;
|
||||
if (count == 3) {
|
||||
return count;
|
||||
}
|
||||
throw new DatastoreTimeoutException("");
|
||||
}})).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransact_datastoreTimeoutException_manifestWrittenToDatastore_returnsSuccess() {
|
||||
// A work unit that throws if it is ever retried.
|
||||
VoidWork work = new VoidWork() {
|
||||
boolean firstCallToVrun = true;
|
||||
|
||||
@Override
|
||||
public void vrun() {
|
||||
if (firstCallToVrun) {
|
||||
firstCallToVrun = false;
|
||||
ofy().save().entity(someObject);
|
||||
return;
|
||||
}
|
||||
fail("Shouldn't have retried.");
|
||||
}};
|
||||
// A commit logged work that throws on the first attempt to get its result.
|
||||
CommitLoggedWork<Void> commitLoggedWork = new CommitLoggedWork<Void>(work, new SystemClock()) {
|
||||
boolean firstCallToGetResult = true;
|
||||
|
||||
@Override
|
||||
public Void getResult() {
|
||||
if (firstCallToGetResult) {
|
||||
firstCallToGetResult = false;
|
||||
throw new DatastoreTimeoutException("");
|
||||
}
|
||||
return null;
|
||||
}};
|
||||
// Despite the DatastoreTimeoutException in the first call to getResult(), this should succeed
|
||||
// without retrying. If a retry is triggered, the test should fail due to the call to fail().
|
||||
ofy().transactCommitLoggedWork(commitLoggedWork);
|
||||
}
|
||||
|
||||
void doReadOnlyRetryTest(final RuntimeException e) {
|
||||
assertThat(ofy().transactNewReadOnly(new Work<Integer>() {
|
||||
|
||||
int count = 0;
|
||||
|
||||
@Override
|
||||
public Integer run() {
|
||||
count++;
|
||||
if (count == 3) {
|
||||
return count;
|
||||
}
|
||||
throw e;
|
||||
}})).isEqualTo(3);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactNewReadOnly_transientFailureException_retries() {
|
||||
doReadOnlyRetryTest(new TransientFailureException(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactNewReadOnly_datastoreTimeoutException_retries() {
|
||||
doReadOnlyRetryTest(new DatastoreTimeoutException(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactNewReadOnly_datastoreFailureException_retries() {
|
||||
doReadOnlyRetryTest(new DatastoreFailureException(""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBaseEntityClassFromEntityOrKey_regularEntity() {
|
||||
ContactResource contact = newContactResource("testcontact");
|
||||
assertThat(getBaseEntityClassFromEntityOrKey(contact)).isEqualTo(ContactResource.class);
|
||||
assertThat(getBaseEntityClassFromEntityOrKey(Key.create(contact)))
|
||||
.isEqualTo(ContactResource.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBaseEntityClassFromEntityOrKey_subclassEntity() {
|
||||
DomainResource domain = DatastoreHelper.newDomainResource("test.tld");
|
||||
assertThat(getBaseEntityClassFromEntityOrKey(domain)).isEqualTo(DomainBase.class);
|
||||
assertThat(getBaseEntityClassFromEntityOrKey(Key.create(domain)))
|
||||
.isEqualTo(DomainBase.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBaseEntityClassFromEntityOrKey_unregisteredEntity() {
|
||||
thrown.expect(IllegalStateException.class, "SystemClock");
|
||||
getBaseEntityClassFromEntityOrKey(new SystemClock());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_getBaseEntityClassFromEntityOrKey_unregisteredEntityKey() {
|
||||
thrown.expect(IllegalArgumentException.class, "UnknownKind");
|
||||
getBaseEntityClassFromEntityOrKey(Key.create(
|
||||
com.google.appengine.api.datastore.KeyFactory.createKey("UnknownKind", 1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_doWithFreshSessionCache() {
|
||||
ofy().saveWithoutBackup().entity(someObject).now();
|
||||
final HistoryEntry modifiedObject =
|
||||
someObject.asBuilder().setModificationTime(END_OF_TIME).build();
|
||||
// Mutate the saved objected, bypassing the Objectify session cache.
|
||||
getDatastoreService().put(ofy().saveWithoutBackup().toEntity(modifiedObject));
|
||||
// Normal loading should come from the session cache and shouldn't reflect the mutation.
|
||||
assertThat(ofy().load().entity(someObject).now()).isEqualTo(someObject);
|
||||
// Loading inside doWithFreshSessionCache() should reflect the mutation.
|
||||
boolean ran = ofy().doWithFreshSessionCache(new Work<Boolean>() {
|
||||
@Override
|
||||
public Boolean run() {
|
||||
assertThat(ofy().load().entity(someObject).now()).isEqualTo(modifiedObject);
|
||||
return true;
|
||||
}});
|
||||
assertThat(ran).isTrue();
|
||||
// Test the normal loading again to verify that we've restored the original session unchanged.
|
||||
assertThat(ofy().load().entity(someObject).now()).isEqualTo(someObject);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue