mirror of
https://github.com/google/nomulus.git
synced 2025-06-11 15:04:46 +02:00
Integrate transaction persistence into JpaTM (#717)
* Integrate transaction persistence into JpaTM Store the serialized transaction whenever we commit from the JPA transaction manager. This change also adds: - The Transaction table. - The TransactionEntity which is stored in it. - Changes to the test infrastructure to register the TransactionEntity for tests where we don't load the nomulus schema. - A new configuration variable to allow us to turn the transaction persistence functionality on and off (default is "off"). * Changes for review. * Incremented sequence number of flyway file
This commit is contained in:
parent
a56713e4be
commit
a802be2a9b
13 changed files with 250 additions and 16 deletions
|
@ -42,7 +42,13 @@ public class JpaEntityCoverageExtension implements BeforeEachCallback, AfterEach
|
|||
// TODO(weiminyu): update this set when entities written to Cloud SQL and tests are added.
|
||||
private static final ImmutableSet<String> IGNORE_ENTITIES =
|
||||
ImmutableSet.of(
|
||||
"DelegationSignerData", "DesignatedContact", "GracePeriod", "RegistrarContact");
|
||||
"DelegationSignerData",
|
||||
"DesignatedContact",
|
||||
"GracePeriod",
|
||||
"RegistrarContact",
|
||||
|
||||
// TransactionEntity is trivial, its persistence is tested in TransactionTest.
|
||||
"TransactionEntity");
|
||||
|
||||
private static final ImmutableSet<Class> ALL_JPA_ENTITIES =
|
||||
PersistenceXmlUtility.getManagedClasses().stream()
|
||||
|
|
|
@ -165,10 +165,10 @@ abstract class JpaTransactionManagerExtension implements BeforeEachCallback, Aft
|
|||
}
|
||||
executeSql(readSqlInClassPath(DB_CLEANUP_SQL_PATH));
|
||||
initScriptPath.ifPresent(path -> executeSql(readSqlInClassPath(path)));
|
||||
if (!extraEntityClasses.isEmpty()) {
|
||||
if (!includeNomulusSchema) {
|
||||
File tempSqlFile = File.createTempFile("tempSqlFile", ".sql");
|
||||
tempSqlFile.deleteOnExit();
|
||||
exporter.export(extraEntityClasses, tempSqlFile);
|
||||
exporter.export(getTestEntities(), tempSqlFile);
|
||||
executeSql(new String(Files.readAllBytes(tempSqlFile.toPath()), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
|
@ -187,11 +187,7 @@ abstract class JpaTransactionManagerExtension implements BeforeEachCallback, Aft
|
|||
assertReasonableNumDbConnections();
|
||||
emf =
|
||||
createEntityManagerFactory(
|
||||
getJdbcUrl(),
|
||||
database.getUsername(),
|
||||
database.getPassword(),
|
||||
properties,
|
||||
extraEntityClasses);
|
||||
getJdbcUrl(), database.getUsername(), database.getPassword(), properties);
|
||||
emfEntityHash = entityHash;
|
||||
}
|
||||
|
||||
|
@ -309,11 +305,7 @@ abstract class JpaTransactionManagerExtension implements BeforeEachCallback, Aft
|
|||
|
||||
/** Constructs the {@link EntityManagerFactory} instance. */
|
||||
private EntityManagerFactory createEntityManagerFactory(
|
||||
String jdbcUrl,
|
||||
String username,
|
||||
String password,
|
||||
ImmutableMap<String, String> configs,
|
||||
ImmutableList<Class> extraEntityClasses) {
|
||||
String jdbcUrl, String username, String password, ImmutableMap<String, String> configs) {
|
||||
HashMap<String, String> properties = Maps.newHashMap(configs);
|
||||
properties.put(Environment.URL, jdbcUrl);
|
||||
properties.put(Environment.USER, username);
|
||||
|
@ -342,7 +334,14 @@ abstract class JpaTransactionManagerExtension implements BeforeEachCallback, Aft
|
|||
descriptor.getManagedClassNames().addAll(nonEntityClasses);
|
||||
}
|
||||
|
||||
extraEntityClasses.stream().map(Class::getName).forEach(descriptor::addClasses);
|
||||
getTestEntities().stream().map(Class::getName).forEach(descriptor::addClasses);
|
||||
return Bootstrap.getEntityManagerFactoryBuilder(descriptor, properties).build();
|
||||
}
|
||||
|
||||
private ImmutableList<Class> getTestEntities() {
|
||||
// We have to add the TransactionEntity to extra entities, as this is required by the
|
||||
// transaction replication mechanism.
|
||||
return Stream.concat(extraEntityClasses.stream(), Stream.of(TransactionEntity.class))
|
||||
.collect(toImmutableList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,16 +15,19 @@
|
|||
package google.registry.persistence.transaction;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.VKey;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.StreamCorruptedException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -99,6 +102,51 @@ public class TransactionTest {
|
|||
StreamCorruptedException.class, () -> Transaction.deserialize(new byte[] {1, 2, 3, 4}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionSerialization() throws IOException {
|
||||
RegistryConfig.overrideCloudSqlReplicateTransactions(true);
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
jpaTm().saveNew(fooEntity);
|
||||
jpaTm().saveNew(barEntity);
|
||||
});
|
||||
TransactionEntity txnEnt =
|
||||
jpaTm().transact(() -> jpaTm().load(VKey.createSql(TransactionEntity.class, 1L)));
|
||||
Transaction txn = Transaction.deserialize(txnEnt.contents);
|
||||
txn.writeToDatastore();
|
||||
ofyTm()
|
||||
.transact(
|
||||
() -> {
|
||||
assertThat(ofyTm().load(fooEntity.key())).isEqualTo(fooEntity);
|
||||
assertThat(ofyTm().load(barEntity.key())).isEqualTo(barEntity);
|
||||
});
|
||||
|
||||
// Verify that no transaction was persisted for the load transaction.
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(() -> jpaTm().checkExists(VKey.createSql(TransactionEntity.class, 2L))))
|
||||
.isFalse();
|
||||
} finally {
|
||||
RegistryConfig.overrideCloudSqlReplicateTransactions(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionSerializationDisabledByDefault() {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
jpaTm().saveNew(fooEntity);
|
||||
jpaTm().saveNew(barEntity);
|
||||
});
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(() -> jpaTm().checkExists(VKey.createSql(TransactionEntity.class, 1L))))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Entity(name = "TxnTestEntity")
|
||||
@javax.persistence.Entity(name = "TestEntity")
|
||||
private static class TestEntity extends ImmutableObject {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue