Add Cloud SQL premium list caches and compare prices with Datastore (#376)

* Add Cloud SQL premium list caches and compare prices with Datastore

Nothing will fail if the prices can't be loaded from Cloud SQL, or if the prices
are different. All that happens is that the error is logged. Then, once this is
running in production for awhile, we'll look at the logs and see if there will
be any pricing implications from switching over to the Cloud SQL version of the
premium lists.

* Add setMaxResults(1) per code review

* Add tests and reorder public functions

* Don't statically import caches

* Improve test pass rate

* Merge branch 'master' into dual-read-premium

* Add PremiumEntry mapping

* Allow update

* Revert column order

* Alphabetize PremiumEntry columns

* Don't bother trying to enforce order

* Private constructor
This commit is contained in:
Ben McIlwain 2019-12-11 16:20:19 -05:00 committed by GitHub
parent 3aad8b6aa7
commit db7fcf6c38
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 438 additions and 17 deletions

View file

@ -15,13 +15,25 @@
package google.registry.schema.tld;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.newRegistry;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.JUnitBackports.assertThrows;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
import google.registry.model.registry.Registry;
import google.registry.model.transaction.JpaTransactionManagerRule;
import google.registry.testing.AppEngineRule;
import java.math.BigDecimal;
import org.joda.money.CurrencyUnit;
import java.util.List;
import java.util.Optional;
import org.joda.money.Money;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -35,6 +47,8 @@ public class PremiumListDaoTest {
public final JpaTransactionManagerRule jpaTmRule =
new JpaTransactionManagerRule.Builder().build();
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
private static final ImmutableMap<String, BigDecimal> TEST_PRICES =
ImmutableMap.of(
"silver",
@ -46,7 +60,7 @@ public class PremiumListDaoTest {
@Test
public void saveNew_worksSuccessfully() {
PremiumList premiumList = PremiumList.create("testname", CurrencyUnit.USD, TEST_PRICES);
PremiumList premiumList = PremiumList.create("testname", USD, TEST_PRICES);
PremiumListDao.saveNew(premiumList);
jpaTm()
.transact(
@ -64,22 +78,114 @@ public class PremiumListDaoTest {
});
}
@Test
public void update_worksSuccessfully() {
PremiumListDao.saveNew(
PremiumList.create(
"testname", USD, ImmutableMap.of("firstversion", BigDecimal.valueOf(123.45))));
PremiumListDao.update(PremiumList.create("testname", USD, TEST_PRICES));
jpaTm()
.transact(
() -> {
List<PremiumList> persistedLists =
jpaTm()
.getEntityManager()
.createQuery(
"SELECT pl FROM PremiumList pl WHERE pl.name = :name ORDER BY"
+ " pl.revisionId",
PremiumList.class)
.setParameter("name", "testname")
.getResultList();
assertThat(persistedLists).hasSize(2);
assertThat(persistedLists.get(1).getLabelsToPrices())
.containsExactlyEntriesIn(TEST_PRICES);
assertThat(persistedLists.get(1).getCreationTimestamp())
.isEqualTo(jpaTmRule.getTxnClock().nowUtc());
});
}
@Test
public void saveNew_throwsWhenPremiumListAlreadyExists() {
PremiumListDao.saveNew(PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES));
PremiumListDao.saveNew(PremiumList.create("testlist", USD, TEST_PRICES));
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() ->
PremiumListDao.saveNew(
PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES)));
assertThat(thrown).hasMessageThat().contains("A premium list of this name already exists");
() -> PremiumListDao.saveNew(PremiumList.create("testlist", USD, TEST_PRICES)));
assertThat(thrown).hasMessageThat().isEqualTo("Premium list 'testlist' already exists");
}
@Test
public void update_throwsWhenPremiumListDoesntExist() {
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> PremiumListDao.update(PremiumList.create("testlist", USD, TEST_PRICES)));
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Can't update non-existent premium list 'testlist'");
}
@Test
public void checkExists_worksSuccessfully() {
assertThat(PremiumListDao.checkExists("testlist")).isFalse();
PremiumListDao.saveNew(PremiumList.create("testlist", CurrencyUnit.USD, TEST_PRICES));
PremiumListDao.saveNew(PremiumList.create("testlist", USD, TEST_PRICES));
assertThat(PremiumListDao.checkExists("testlist")).isTrue();
}
@Test
public void getLatestRevision_returnsEmptyForNonexistentList() {
assertThat(PremiumListDao.getLatestRevision("nonexistentlist")).isEmpty();
}
@Test
public void getLatestRevision_worksSuccessfully() {
PremiumListDao.saveNew(
PremiumList.create("list1", JPY, ImmutableMap.of("wrong", BigDecimal.valueOf(1000.50))));
PremiumListDao.update(PremiumList.create("list1", JPY, TEST_PRICES));
jpaTm()
.transact(
() -> {
Optional<PremiumList> persistedList = PremiumListDao.getLatestRevision("list1");
assertThat(persistedList).isPresent();
assertThat(persistedList.get().getName()).isEqualTo("list1");
assertThat(persistedList.get().getCurrency()).isEqualTo(JPY);
assertThat(persistedList.get().getLabelsToPrices())
.containsExactlyEntriesIn(TEST_PRICES);
});
}
@Test
public void getPremiumPrice_returnsNoneWhenNoPremiumListConfigured() {
persistResource(newRegistry("foobar", "FOOBAR").asBuilder().setPremiumList(null).build());
assertThat(PremiumListDao.getPremiumPrice("rich", Registry.get("foobar"))).isEmpty();
}
@Test
public void getPremiumPrice_worksSuccessfully() {
persistResource(
newRegistry("foobar", "FOOBAR")
.asBuilder()
.setPremiumListKey(
Key.create(
getCrossTldKey(),
google.registry.model.registry.label.PremiumList.class,
"premlist"))
.build());
PremiumListDao.saveNew(PremiumList.create("premlist", USD, TEST_PRICES));
assertThat(PremiumListDao.getPremiumPrice("silver", Registry.get("foobar")))
.hasValue(Money.of(USD, 10.23));
assertThat(PremiumListDao.getPremiumPrice("gold", Registry.get("foobar")))
.hasValue(Money.of(USD, 1305.47));
assertThat(PremiumListDao.getPremiumPrice("zirconium", Registry.get("foobar"))).isEmpty();
}
@Test
public void testGetPremiumPrice_throwsWhenPremiumListCantBeLoaded() {
createTld("tld");
IllegalStateException thrown =
assertThrows(
IllegalStateException.class,
() -> PremiumListDao.getPremiumPrice("foobar", Registry.get("tld")));
assertThat(thrown).hasMessageThat().isEqualTo("Could not load premium list 'tld'");
}
}