Resurrect symmetric vkeys when possible. (#899)

* Resurrect symmetric vkeys when possible.

AbstractVKeyConverter had never been updated to generate symmetric VKeys for
simple (i.e. non-composite) VKey types.  Update it to default to generating a
VKey with a simple Ofy key.

With this change, composite VKeys must specify the "compositeKey = true" field
in the With*VKey annotations.  Doing so creates an asymmetric (SQL only) VKey
that can triggers higher-level logic to generate a corrected VKey containing
the composite Key.
This commit is contained in:
Michael Muller 2020-12-08 15:13:44 -05:00 committed by GitHub
parent c7e6192929
commit db19f9ea4f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 179 additions and 64 deletions

View file

@ -84,10 +84,10 @@ public class DomainBaseSqlTest {
saveRegistrar("registrar1");
saveRegistrar("registrar2");
saveRegistrar("registrar3");
contactKey = VKey.createSql(ContactResource.class, "contact_id1");
contact2Key = VKey.createSql(ContactResource.class, "contact_id2");
contactKey = createKey(ContactResource.class, "contact_id1");
contact2Key = createKey(ContactResource.class, "contact_id2");
host1VKey = VKey.createSql(HostResource.class, "host1");
host1VKey = createKey(HostResource.class, "host1");
domain =
new DomainBase.Builder()
@ -696,6 +696,10 @@ public class DomainBaseSqlTest {
assertThat(domain.getGracePeriods()).isEqualTo(gracePeriods);
}
private <T> VKey<T> createKey(Class<T> clazz, String name) {
return VKey.create(clazz, name, Key.create(clazz, name));
}
private <T> VKey<T> createLegacyVKey(Class<T> clazz, long id) {
return VKey.create(
clazz, id, Key.create(Key.create(EntityGroupRoot.class, "per-tld"), clazz, id));

View file

@ -14,7 +14,6 @@
package google.registry.model.history;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.ImmutableObjectSubject.assertAboutImmutableObjects;
import static google.registry.model.ImmutableObjectSubject.immutableObjectCorrespondence;
@ -92,10 +91,7 @@ public class DomainHistoryTest extends EntityTestCase {
assertDomainHistoriesEqual(fromDatabase, domainHistory);
assertThat(fromDatabase.getParentVKey()).isEqualTo(domainHistory.getParentVKey());
assertThat(fromDatabase.getNsHosts())
.containsExactlyElementsIn(
domainHistory.getNsHosts().stream()
.map(key -> VKey.createSql(HostResource.class, key.getSqlKey()))
.collect(toImmutableSet()));
.containsExactlyElementsIn(domainHistory.getNsHosts());
});
}

View file

@ -19,8 +19,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import google.registry.persistence.VKey;
import google.registry.persistence.WithLongVKey;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestExtension;
import google.registry.testing.AppEngineExtension;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.jupiter.api.Test;
@ -30,33 +29,56 @@ import org.junit.jupiter.api.extension.RegisterExtension;
public class LongVKeyConverterTest {
@RegisterExtension
public final JpaUnitTestExtension jpaExtension =
new JpaTestRules.Builder()
.withEntityClass(TestEntity.class, VKeyConverter_LongType.class)
.buildUnitTestRule();
public final AppEngineExtension appEngineExtension =
new AppEngineExtension.Builder()
.withDatastoreAndCloudSql()
.withoutCannedData()
.withJpaUnitTestEntities(
TestLongEntity.class,
VKeyConverter_LongType.class,
VKeyConverter_CompositeLongType.class)
.withOfyTestEntities(TestLongEntity.class, CompositeKeyTestLongEntity.class)
.build();
@Test
void testRoundTrip() {
TestEntity original = new TestEntity(VKey.createSql(TestEntity.class, 10L));
TestLongEntity original =
new TestLongEntity(
VKey.createSql(TestLongEntity.class, 10L),
VKey.createSql(CompositeKeyTestLongEntity.class, 20L));
jpaTm().transact(() -> jpaTm().getEntityManager().persist(original));
TestEntity retrieved =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
TestLongEntity retrieved =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestLongEntity.class, "id"));
assertThat(retrieved.number.getSqlKey()).isEqualTo(10L);
assertThat(retrieved.number.getOfyKey().getId()).isEqualTo(10L);
assertThat(retrieved.composite.getSqlKey()).isEqualTo(20L);
assertThat(retrieved.composite.maybeGetOfyKey().isPresent()).isFalse();
}
@Entity(name = "TestEntity")
@Entity(name = "TestLongEntity")
@com.googlecode.objectify.annotation.Entity
@WithLongVKey(classNameSuffix = "LongType")
static class TestEntity {
@Id String id = "id";
static class TestLongEntity {
@com.googlecode.objectify.annotation.Id @Id String id = "id";
VKey<TestEntity> number;
VKey<TestLongEntity> number;
VKey<CompositeKeyTestLongEntity> composite;
TestEntity(VKey<TestEntity> number) {
TestLongEntity(VKey<TestLongEntity> number, VKey<CompositeKeyTestLongEntity> composite) {
this.number = number;
this.composite = composite;
}
/** Default constructor, needed for hibernate. */
public TestEntity() {}
public TestLongEntity() {}
}
@Entity(name = "CompositeKeyTestLongEntity")
@com.googlecode.objectify.annotation.Entity
@WithLongVKey(classNameSuffix = "CompositeLongType", compositeKey = true)
static class CompositeKeyTestLongEntity {
@com.googlecode.objectify.annotation.Id @Id String id = "id";
}
}

View file

@ -19,8 +19,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import google.registry.persistence.VKey;
import google.registry.persistence.WithStringVKey;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestExtension;
import google.registry.testing.AppEngineExtension;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.jupiter.api.Test;
@ -30,36 +29,61 @@ import org.junit.jupiter.api.extension.RegisterExtension;
public class StringVKeyConverterTest {
@RegisterExtension
public final JpaUnitTestExtension jpaExtension =
new JpaTestRules.Builder()
.withEntityClass(TestEntity.class, VKeyConverter_StringType.class)
.buildUnitTestRule();
public final AppEngineExtension appEngineExtension =
new AppEngineExtension.Builder()
.withDatastoreAndCloudSql()
.withoutCannedData()
.withJpaUnitTestEntities(
TestStringEntity.class,
VKeyConverter_StringType.class,
VKeyConverter_CompositeStringType.class)
.withOfyTestEntities(TestStringEntity.class, CompositeKeyTestStringEntity.class)
.build();
@Test
void testRoundTrip() {
TestEntity original =
new TestEntity("TheRealSpartacus", VKey.createSql(TestEntity.class, "ImSpartacus!"));
TestStringEntity original =
new TestStringEntity(
"TheRealSpartacus",
VKey.createSql(TestStringEntity.class, "ImSpartacus!"),
VKey.createSql(CompositeKeyTestStringEntity.class, "NoImSpartacus!"));
jpaTm().transact(() -> jpaTm().getEntityManager().persist(original));
TestEntity retrieved =
TestStringEntity retrieved =
jpaTm()
.transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "TheRealSpartacus"));
.transact(
() -> jpaTm().getEntityManager().find(TestStringEntity.class, "TheRealSpartacus"));
assertThat(retrieved.other.getSqlKey()).isEqualTo("ImSpartacus!");
assertThat(retrieved.other.getOfyKey().getName()).isEqualTo("ImSpartacus!");
assertThat(retrieved.composite.getSqlKey()).isEqualTo("NoImSpartacus!");
assertThat(retrieved.composite.maybeGetOfyKey().isPresent()).isFalse();
}
@Entity(name = "TestEntity")
@Entity(name = "TestStringEntity")
@com.googlecode.objectify.annotation.Entity
@WithStringVKey(classNameSuffix = "StringType")
static class TestEntity {
@Id String id;
static class TestStringEntity {
@com.googlecode.objectify.annotation.Id @Id String id;
VKey<TestEntity> other;
VKey<TestStringEntity> other;
VKey<CompositeKeyTestStringEntity> composite;
TestEntity(String id, VKey<TestEntity> other) {
TestStringEntity(
String id, VKey<TestStringEntity> other, VKey<CompositeKeyTestStringEntity> composite) {
this.id = id;
this.other = other;
this.composite = composite;
}
/** Default constructor, needed for hibernate. */
public TestEntity() {}
public TestStringEntity() {}
}
@Entity(name = "CompositeKeyTestStringEntity")
@com.googlecode.objectify.annotation.Entity
@WithStringVKey(classNameSuffix = "CompositeStringType", compositeKey = true)
static class CompositeKeyTestStringEntity {
@com.googlecode.objectify.annotation.Id @Id String id = "id";
}
}