Stop writing ReservedList to Datastore (#1163)

This commit is contained in:
sarahcaseybot 2021-05-17 17:46:21 -04:00 committed by GitHub
parent 16641e05a1
commit c1f0c29134
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 53 additions and 692 deletions

View file

@ -255,7 +255,7 @@ public final class ReservedList
new CacheLoader<String, ReservedList>() {
@Override
public ReservedList load(String listName) {
return ReservedListDualDatabaseDao.getLatestRevision(listName).orElse(null);
return ReservedListDao.getLatestRevision(listName).orElse(null);
}
});

View file

@ -20,16 +20,12 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.flogger.FluentLogger;
import java.util.Optional;
/**
* A {@link ReservedList} DAO for Cloud SQL.
*
* <p>TODO(b/177567432): Rename this class to ReservedListDao after migrating to Cloud SQL.
*/
public class ReservedListSqlDao {
/** A {@link ReservedList} DAO for Cloud SQL. */
public class ReservedListDao {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private ReservedListSqlDao() {}
private ReservedListDao() {}
/** Persist a new reserved list to Cloud SQL. */
public static void save(ReservedList reservedList) {

View file

@ -1,50 +0,0 @@
// Copyright 2021 The Nomulus 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 google.registry.model.registry.label;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
import com.googlecode.objectify.Key;
import google.registry.persistence.VKey;
import java.util.Optional;
/** A {@link ReservedList} DAO for Datastore. */
public class ReservedListDatastoreDao {
private ReservedListDatastoreDao() {}
/** Persist a new reserved list to Datastore. */
public static void save(ReservedList reservedList) {
ofyTm().transact(() -> ofyTm().put(reservedList));
}
/** Delete a reserved list from Datastore. */
public static void delete(ReservedList reservedList) {
ofyTm().transact(() -> ofyTm().delete(reservedList));
}
/**
* Returns the most recent revision of the {@link ReservedList} with the specified name, if it
* exists.
*/
public static Optional<ReservedList> getLatestRevision(String reservedListName) {
return ofyTm()
.loadByKeyIfPresent(
VKey.createOfy(
ReservedList.class,
Key.create(getCrossTldKey(), ReservedList.class, reservedListName)));
}
}

View file

@ -1,126 +0,0 @@
// Copyright 2020 The Nomulus 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 google.registry.model.registry.label;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import com.google.common.collect.MapDifference;
import com.google.common.collect.MapDifference.ValueDifference;
import com.google.common.collect.Maps;
import google.registry.model.DatabaseMigrationUtils;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import java.util.Map;
import java.util.Optional;
/**
* A {@link ReservedList} DAO that does dual-write and dual-read against Datastore and Cloud SQL.
*
* <p>TODO(b/160993806): Delete this DAO and switch to use the SQL only DAO after migrating to Cloud
* SQL.
*/
public class ReservedListDualDatabaseDao {
private ReservedListDualDatabaseDao() {}
/** Persist a new reserved list to the database. */
public static void save(ReservedList reservedList) {
ReservedListSqlDao.save(reservedList);
DatabaseMigrationUtils.suppressExceptionUnlessInTest(
() -> ReservedListDatastoreDao.save(reservedList),
"Error saving the reserved list to Datastore.");
}
/** Delete a reserved list from both databases. */
public static void delete(ReservedList reservedList) {
ReservedListSqlDao.delete(reservedList);
DatabaseMigrationUtils.suppressExceptionUnlessInTest(
() -> ReservedListDatastoreDao.delete(reservedList),
"Error deleting the reserved list from Datastore.");
}
/**
* Returns the most recent revision of the {@link ReservedList} with the specified name, if it
* exists.
*/
public static Optional<ReservedList> getLatestRevision(String reservedListName) {
Optional<ReservedList> maybePrimaryList =
ReservedListSqlDao.getLatestRevision(reservedListName);
DatabaseMigrationUtils.suppressExceptionUnlessInTest(
() -> maybePrimaryList.ifPresent(primaryList -> loadAndCompare(primaryList)),
"Error comparing reserved lists.");
return maybePrimaryList;
}
private static void loadAndCompare(ReservedList primaryList) {
Optional<ReservedList> maybeSecondaryList =
ReservedListDatastoreDao.getLatestRevision(primaryList.getName());
if (!maybeSecondaryList.isPresent()) {
throw new IllegalStateException("Reserved list in Datastore is empty.");
}
Map<String, ReservedListEntry> labelsToReservations =
primaryList.reservedListMap.entrySet().parallelStream()
.collect(
toImmutableMap(
Map.Entry::getKey,
entry ->
ReservedListEntry.create(
entry.getKey(),
entry.getValue().reservationType,
entry.getValue().comment)));
ReservedList secondaryList = maybeSecondaryList.get();
MapDifference<String, ReservedListEntry> diff =
Maps.difference(labelsToReservations, secondaryList.reservedListMap);
if (!diff.areEqual()) {
if (diff.entriesDiffering().size() > 10) {
throw new IllegalStateException(
String.format(
"Unequal reserved lists detected, Datastore list with revision"
+ " id %d has %d different records than the current"
+ " Cloud SQL list.",
secondaryList.getRevisionId(), diff.entriesDiffering().size()));
}
StringBuilder diffMessage = new StringBuilder("Unequal reserved lists detected:\n");
diff.entriesDiffering().entrySet().stream()
.forEach(
entry -> {
String label = entry.getKey();
ValueDifference<ReservedListEntry> valueDiff = entry.getValue();
diffMessage.append(
String.format(
"Domain label %s has entry %s in Cloud SQL and entry"
+ " %s in the Datastore.\n",
label, valueDiff.leftValue(), valueDiff.rightValue()));
});
diff.entriesOnlyOnLeft().entrySet().stream()
.forEach(
entry -> {
String label = entry.getKey();
diffMessage.append(
String.format(
"Domain label %s has entry in Cloud SQL, but not in Datastore.\n", label));
});
diff.entriesOnlyOnRight().entrySet().stream()
.forEach(
entry -> {
String label = entry.getKey();
diffMessage.append(
String.format(
"Domain label %s has entry in Datastore, but not in Cloud SQL.\n", label));
});
throw new IllegalStateException(diffMessage.toString());
}
}
}

View file

@ -1,82 +0,0 @@
// Copyright 2021 The Nomulus 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 google.registry.tools;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.model.ofy.ObjectifyService.auditedOfy;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListDatastoreDao;
import google.registry.model.registry.label.ReservedListSqlDao;
/** Command to compare all ReservedLists in Datastore to all ReservedLists in Cloud SQL. */
@Parameters(
separators = " =",
commandDescription = "Compare all the ReservedLists in Datastore to those in Cloud SQL.")
final class CompareReservedListsCommand implements CommandWithRemoteApi {
@Override
public void run() {
ImmutableSet<String> datastoreLists =
auditedOfy().load().type(ReservedList.class).ancestor(getCrossTldKey()).list().stream()
.map(ReservedList::getName)
.collect(toImmutableSet());
ImmutableSet<String> cloudSqlLists =
jpaTm()
.transact(
() ->
jpaTm().loadAllOf(ReservedList.class).stream()
.map(ReservedList::getName)
.collect(toImmutableSet()));
int listsWithDiffs = 0;
for (String listName : Sets.difference(datastoreLists, cloudSqlLists)) {
listsWithDiffs++;
System.out.printf(
"ReservedList '%s' is present in Datastore, but not in Cloud SQL.%n", listName);
}
for (String listName : Sets.difference(cloudSqlLists, datastoreLists)) {
listsWithDiffs++;
System.out.printf(
"ReservedList '%s' is present in Cloud SQL, but not in Datastore.%n", listName);
}
for (String listName : Sets.intersection(datastoreLists, cloudSqlLists)) {
ImmutableMap<String, ReservedListEntry> namesInSql =
ReservedListSqlDao.getLatestRevision(listName).get().getReservedListEntries();
ImmutableMap<String, ReservedListEntry> namesInDatastore =
ReservedListDatastoreDao.getLatestRevision(listName).get().getReservedListEntries();
// This will only print out the name of the unequal list. GetReservedListCommand should be
// used to determine what the actual differences are.
if (!namesInDatastore.equals(namesInSql)) {
listsWithDiffs++;
System.out.printf("ReservedList '%s' has different entries in each database.%n", listName);
}
}
System.out.printf("Found %d unequal list(s).%n", listsWithDiffs);
}
}

View file

@ -17,7 +17,7 @@ package google.registry.tools;
import com.beust.jcommander.Parameter;
import com.google.common.flogger.FluentLogger;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListDao;
import google.registry.tools.params.PathParameter;
import java.nio.file.Path;
import javax.annotation.Nullable;
@ -61,7 +61,7 @@ public abstract class CreateOrUpdateReservedListCommand extends MutatingCommand
name, reservedList.getReservedListEntries().size());
try {
logger.atInfo().log("Saving reserved list for TLD %s", name);
ReservedListDualDatabaseDao.save(reservedList);
ReservedListDao.save(reservedList);
logger.atInfo().log(message);
} catch (Throwable e) {
message = "Unexpected error saving reserved list from nomulus tool command";

View file

@ -21,7 +21,7 @@ import com.beust.jcommander.Parameters;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListDao;
/**
* Command to delete a {@link ReservedList} from the database. This command will fail if the
@ -53,7 +53,7 @@ final class DeleteReservedListCommand extends ConfirmingCommand implements Comma
@Override
protected String execute() {
ReservedList existing = ReservedList.get(name).get();
ReservedListDualDatabaseDao.delete(existing);
ReservedListDao.delete(existing);
return String.format("Deleted reserved list: %s", name);
}
}

View file

@ -18,7 +18,7 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.appengine.repackaged.com.google.common.collect.Streams;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListDao;
import java.util.Comparator;
import java.util.stream.Collectors;
@ -34,11 +34,11 @@ public class GetReservedListCommand implements CommandWithRemoteApi {
@Override
public void run() throws Exception {
if (ReservedListDualDatabaseDao.getLatestRevision(reservedListName).isPresent()) {
if (ReservedListDao.getLatestRevision(reservedListName).isPresent()) {
System.out.printf(
"%s\n",
Streams.stream(
ReservedListDualDatabaseDao.getLatestRevision(reservedListName)
ReservedListDao.getLatestRevision(reservedListName)
.get()
.getReservedListEntries()
.values())

View file

@ -38,7 +38,6 @@ public final class RegistryTool {
.put("canonicalize_labels", CanonicalizeLabelsCommand.class)
.put("check_domain", CheckDomainCommand.class)
.put("check_domain_claims", CheckDomainClaimsCommand.class)
.put("compare_reserved_lists", CompareReservedListsCommand.class)
.put("convert_idn", ConvertIdnCommand.class)
.put("count_domains", CountDomainsCommand.class)
.put("create_anchor_tenant", CreateAnchorTenantCommand.class)

View file

@ -15,14 +15,13 @@
package google.registry.tools.server;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.POST;
import com.google.common.collect.ImmutableSet;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListDao;
import google.registry.request.Action;
import google.registry.request.auth.Auth;
import java.util.Comparator;
@ -48,13 +47,14 @@ public final class ListReservedListsAction extends ListObjectsAction<ReservedLis
@Override
public ImmutableSet<ReservedList> loadObjects() {
return transactIfJpaTm(
() ->
tm().loadAllOf(ReservedList.class).stream()
.map(ReservedList::getName)
.map(ReservedListDualDatabaseDao::getLatestRevision)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toImmutableSortedSet(Comparator.comparing(ReservedList::getName))));
return jpaTm()
.transact(
() ->
jpaTm().loadAllOf(ReservedList.class).stream()
.map(ReservedList::getName)
.map(ReservedListDao::getLatestRevision)
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toImmutableSortedSet(Comparator.comparing(ReservedList::getName))));
}
}

View file

@ -28,8 +28,8 @@ import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link ReservedListSqlDao}. */
public class ReservedListSqlDaoTest {
/** Unit tests for {@link ReservedListDao}. */
public class ReservedListDaoTest {
private final FakeClock fakeClock = new FakeClock();
@ -65,7 +65,7 @@ public class ReservedListSqlDaoTest {
@Test
void save_worksSuccessfully() {
ReservedListSqlDao.save(testReservedList);
ReservedListDao.save(testReservedList);
jpaTm()
.transact(
() -> {
@ -82,31 +82,31 @@ public class ReservedListSqlDaoTest {
@Test
void delete_worksSuccessfully() {
ReservedListSqlDao.save(testReservedList);
assertThat(ReservedListSqlDao.checkExists("testlist")).isTrue();
ReservedListSqlDao.delete(testReservedList);
assertThat(ReservedListSqlDao.checkExists("testlist")).isFalse();
ReservedListDao.save(testReservedList);
assertThat(ReservedListDao.checkExists("testlist")).isTrue();
ReservedListDao.delete(testReservedList);
assertThat(ReservedListDao.checkExists("testlist")).isFalse();
}
@Test
void delete_listNotInDatabase() {
assertThat(ReservedListSqlDao.checkExists("testlist")).isFalse();
ReservedListSqlDao.delete(testReservedList);
assertThat(ReservedListSqlDao.checkExists("testlist")).isFalse();
assertThat(ReservedListDao.checkExists("testlist")).isFalse();
ReservedListDao.delete(testReservedList);
assertThat(ReservedListDao.checkExists("testlist")).isFalse();
}
@Test
void checkExists_worksSuccessfully() {
assertThat(ReservedListSqlDao.checkExists("testlist")).isFalse();
ReservedListSqlDao.save(testReservedList);
assertThat(ReservedListSqlDao.checkExists("testlist")).isTrue();
assertThat(ReservedListDao.checkExists("testlist")).isFalse();
ReservedListDao.save(testReservedList);
assertThat(ReservedListDao.checkExists("testlist")).isTrue();
}
@Test
void getLatestRevision_worksSuccessfully() {
assertThat(ReservedListSqlDao.getLatestRevision("testlist").isPresent()).isFalse();
ReservedListSqlDao.save(testReservedList);
ReservedList persistedList = ReservedListSqlDao.getLatestRevision("testlist").get();
assertThat(ReservedListDao.getLatestRevision("testlist").isPresent()).isFalse();
ReservedListDao.save(testReservedList);
ReservedList persistedList = ReservedListDao.getLatestRevision("testlist").get();
assertThat(persistedList.getRevisionId()).isNotNull();
assertThat(persistedList.getLastUpdateTime()).isEqualTo(fakeClock.nowUtc());
assertThat(persistedList.getName()).isEqualTo("testlist");
@ -116,7 +116,7 @@ public class ReservedListSqlDaoTest {
@Test
void getLatestRevision_returnsLatestRevision() {
ReservedListSqlDao.save(
ReservedListDao.save(
new ReservedList.Builder()
.setName("testlist")
.setLastUpdateTime(fakeClock.nowUtc())
@ -127,8 +127,8 @@ public class ReservedListSqlDaoTest {
ReservedListEntry.create(
"old", ReservationType.RESERVED_FOR_SPECIFIC_USE, null)))
.build());
ReservedListSqlDao.save(testReservedList);
ReservedList persistedList = ReservedListSqlDao.getLatestRevision("testlist").get();
ReservedListDao.save(testReservedList);
ReservedList persistedList = ReservedListDao.getLatestRevision("testlist").get();
assertThat(persistedList.getRevisionId()).isNotNull();
assertThat(persistedList.getLastUpdateTime()).isEqualTo(fakeClock.nowUtc());
assertThat(persistedList.getName()).isEqualTo("testlist");

View file

@ -1,117 +0,0 @@
// Copyright 2021 The Nomulus 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 google.registry.model.registry.label;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.persistence.transaction.TransactionManagerFactory.ofyTm;
import com.google.common.collect.ImmutableMap;
import com.googlecode.objectify.Key;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.persistence.VKey;
import google.registry.testing.AppEngineExtension;
import google.registry.testing.FakeClock;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link ReservedListDatastoreDao}. */
public class ReservedListDatastoreDaoTest {
@RegisterExtension
final AppEngineExtension appEngine =
AppEngineExtension.builder().withDatastoreAndCloudSql().build();
private final FakeClock fakeClock = new FakeClock();
private ImmutableMap<String, ReservedListEntry> reservations;
private ReservedList reservedList;
@BeforeEach
void setUp() {
reservations =
ImmutableMap.of(
"food",
ReservedListEntry.create("food", ReservationType.RESERVED_FOR_SPECIFIC_USE, null),
"music",
ReservedListEntry.create("music", ReservationType.FULLY_BLOCKED, "fully blocked"));
reservedList =
new ReservedList.Builder()
.setName("testlist")
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(reservations)
.build();
}
@Test
void save_worksSuccessfully() {
ReservedListDatastoreDao.save(reservedList);
Optional<ReservedList> savedList =
ofyTm()
.loadByKeyIfPresent(
VKey.createOfy(
ReservedList.class,
Key.create(getCrossTldKey(), ReservedList.class, reservedList.name)));
assertThat(savedList.get()).isEqualTo(reservedList);
}
@Test
void delete_worksSuccessfully() {
ReservedListDatastoreDao.save(reservedList);
assertThat(ReservedListDatastoreDao.getLatestRevision("testlist").isPresent()).isTrue();
ReservedListDatastoreDao.delete(reservedList);
assertThat(ReservedListDatastoreDao.getLatestRevision("testlist").isPresent()).isFalse();
}
@Test
void delete_listNotInDatastore() {
assertThat(ReservedListDatastoreDao.getLatestRevision("testlist").isPresent()).isFalse();
ReservedListDatastoreDao.delete(reservedList);
assertThat(ReservedListDatastoreDao.getLatestRevision("testlist").isPresent()).isFalse();
}
@Test
void getLatestRevision_worksSuccessfully() {
assertThat(ReservedListDatastoreDao.getLatestRevision("testlist").isPresent()).isFalse();
ReservedListDatastoreDao.save(reservedList);
ReservedList persistedList = ReservedListDatastoreDao.getLatestRevision("testlist").get();
assertThat(persistedList).isEqualTo(reservedList);
}
@Test
void getLatestRevision_returnsLatestRevision() {
ReservedListDatastoreDao.save(
new ReservedList.Builder()
.setName("testlist")
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(
ImmutableMap.of(
"old",
ReservedListEntry.create(
"old", ReservationType.RESERVED_FOR_SPECIFIC_USE, null)))
.build());
assertThat(ReservedListDatastoreDao.getLatestRevision("testlist").get())
.isNotEqualTo(reservedList);
ReservedListDatastoreDao.save(reservedList);
ReservedList persistedList = ReservedListDatastoreDao.getLatestRevision("testlist").get();
assertThat(persistedList).isEqualTo(reservedList);
}
}

View file

@ -1,143 +0,0 @@
// Copyright 2021 The Nomulus 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 google.registry.model.registry.label;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableMap;
import google.registry.model.EntityTestCase;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class ReservedListDualDatabaseDaoTest extends EntityTestCase {
private ImmutableMap<String, ReservedListEntry> reservations;
private ReservedList reservedList;
@BeforeEach
void setUp() {
fakeClock.setAutoIncrementByOneMilli();
reservations =
ImmutableMap.of(
"food",
ReservedListEntry.create("food", ReservationType.RESERVED_FOR_SPECIFIC_USE, null),
"music",
ReservedListEntry.create("music", ReservationType.FULLY_BLOCKED, "fully blocked"));
reservedList =
new ReservedList.Builder()
.setName("testlist")
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(reservations)
.build();
}
@Test
void testSave_success() {
ReservedListDualDatabaseDao.save(reservedList);
Optional<ReservedList> savedList =
ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName());
assertThat(savedList.get()).isEqualTo(reservedList);
}
@Test
void testDelete_success() {
ReservedListDualDatabaseDao.save(reservedList);
assertThat(ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName()).isPresent())
.isTrue();
ReservedListDualDatabaseDao.delete(reservedList);
assertThat(ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName()).isPresent())
.isFalse();
}
@Test
void testSaveAndLoad_emptyList() {
ReservedList list =
new ReservedList.Builder()
.setName("empty")
.setLastUpdateTime(fakeClock.nowUtc())
.setReservedListMap(ImmutableMap.of())
.build();
ReservedListDualDatabaseDao.save(list);
Optional<ReservedList> savedList = ReservedListDualDatabaseDao.getLatestRevision("empty");
assertThat(savedList.get()).isEqualTo(list);
}
@Test
void testSave_multipleVersions() {
ReservedListDualDatabaseDao.save(reservedList);
assertThat(
ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName())
.get()
.getReservedListEntries())
.isEqualTo(reservations);
ImmutableMap<String, ReservedListEntry> newReservations =
ImmutableMap.of(
"food",
ReservedListEntry.create("food", ReservationType.RESERVED_FOR_SPECIFIC_USE, null));
ReservedList secondList =
new ReservedList.Builder()
.setName("testlist2")
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(newReservations)
.build();
ReservedListDualDatabaseDao.save(secondList);
assertThat(
ReservedListDualDatabaseDao.getLatestRevision(secondList.getName())
.get()
.getReservedListEntries())
.isEqualTo(newReservations);
}
@Test
void testLoad_unequalLists() {
ReservedListDualDatabaseDao.save(reservedList);
ReservedList secondList =
new ReservedList.Builder()
.setName(reservedList.name)
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(
ImmutableMap.of(
"food",
ReservedListEntry.create(
"food", ReservationType.RESERVED_FOR_SPECIFIC_USE, null)))
.build();
ReservedListSqlDao.save(secondList);
IllegalStateException thrown =
assertThrows(
IllegalStateException.class,
() -> ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName()));
assertThat(thrown)
.hasMessageThat()
.contains("Domain label music has entry in Datastore, but not in Cloud SQL.");
}
@Test
void testLoad_noListInDatastore() {
ReservedListSqlDao.save(reservedList);
IllegalStateException thrown =
assertThrows(
IllegalStateException.class,
() -> ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName()));
assertThat(thrown).hasMessageThat().contains("Reserved list in Datastore is empty.");
}
}

View file

@ -28,7 +28,7 @@ import google.registry.model.poll.PollMessageTest;
import google.registry.model.rde.RdeRevisionTest;
import google.registry.model.registry.RegistryLockDaoTest;
import google.registry.model.registry.RegistryTest;
import google.registry.model.registry.label.ReservedListSqlDaoTest;
import google.registry.model.registry.label.ReservedListDaoTest;
import google.registry.model.reporting.Spec11ThreatMatchTest;
import google.registry.model.server.KmsSecretRevisionSqlDaoTest;
import google.registry.model.server.LockTest;
@ -96,7 +96,7 @@ import org.junit.runner.RunWith;
RdeRevisionTest.class,
RegistrarDaoTest.class,
RegistryTest.class,
ReservedListSqlDaoTest.class,
ReservedListDaoTest.class,
RegistryLockDaoTest.class,
ServerSecretTest.class,
SignedMarkRevocationListDaoTest.class,

View file

@ -99,7 +99,7 @@ import google.registry.model.registry.Registry.TldType;
import google.registry.model.registry.label.PremiumList;
import google.registry.model.registry.label.PremiumList.PremiumListEntry;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListDao;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntryDao;
import google.registry.model.transfer.ContactTransferData;
@ -346,9 +346,8 @@ public class DatabaseHelper {
}
public static ReservedList persistReservedList(ReservedList reservedList) {
ReservedListDualDatabaseDao.save(reservedList);
ReservedListDao.save(reservedList);
maybeAdvanceClock();
tm().clearSessionCache();
return reservedList;
}

View file

@ -1,115 +0,0 @@
// Copyright 2021 The Nomulus 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 google.registry.tools;
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 google.registry.testing.DatabaseHelper.persistReservedList;
import com.google.common.collect.ImmutableMap;
import google.registry.model.registry.label.ReservationType;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListDatastoreDao;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListSqlDao;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link CompareReservedListsCommand}. */
public class CompareReservedListCommandTest extends CommandTestCase<CompareReservedListsCommand> {
@BeforeEach
void setUp() {
persistReservedList(
"testlist", "food, RESERVED_FOR_SPECIFIC_USE", "music, FULLY_BLOCKED # fully blocked");
persistReservedList("testlist2", "candy, ALLOWED_IN_SUNRISE");
}
@Test
void test_success() throws Exception {
runCommand();
assertThat(getStdoutAsString()).isEqualTo("Found 0 unequal list(s).\n");
}
@Test
void test_listMissingFromCloudSql() throws Exception {
jpaTm().transact(() -> jpaTm().delete(ReservedListSqlDao.getLatestRevision("testlist").get()));
runCommand();
assertThat(getStdoutAsString())
.isEqualTo(
"ReservedList 'testlist' is present in Datastore, but not in Cloud SQL.\n"
+ "Found 1 unequal list(s).\n");
}
@Test
void test_listMissingFromDatastore() throws Exception {
ofyTm()
.transact(
() -> ofyTm().delete(ReservedListDatastoreDao.getLatestRevision("testlist").get()));
runCommand();
assertThat(getStdoutAsString())
.isEqualTo(
"ReservedList 'testlist' is present in Cloud SQL, but not in Datastore.\n"
+ "Found 1 unequal list(s).\n");
}
@Test
void test_listsDiffer() throws Exception {
ImmutableMap<String, ReservedListEntry> newReservations =
ImmutableMap.of(
"food",
ReservedListEntry.create("food", ReservationType.RESERVED_FOR_SPECIFIC_USE, null));
ReservedList secondList =
new ReservedList.Builder()
.setName("testlist")
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(newReservations)
.build();
ReservedListDatastoreDao.save(secondList);
runCommand();
assertThat(getStdoutAsString())
.isEqualTo(
"ReservedList 'testlist' has different entries in each database.\n"
+ "Found 1 unequal list(s).\n");
}
@Test
void test_listsDifferAndMissing() throws Exception {
ofyTm()
.transact(
() -> ofyTm().delete(ReservedListDualDatabaseDao.getLatestRevision("testlist2").get()));
ImmutableMap<String, ReservedListEntry> newReservations =
ImmutableMap.of(
"food",
ReservedListEntry.create("food", ReservationType.RESERVED_FOR_SPECIFIC_USE, null));
ReservedList secondList =
new ReservedList.Builder()
.setName("testlist")
.setLastUpdateTime(fakeClock.nowUtc())
.setShouldPublish(false)
.setReservedListMap(newReservations)
.build();
ReservedListDatastoreDao.save(secondList);
runCommand();
assertThat(getStdoutAsString())
.isEqualTo(
"ReservedList 'testlist2' is present in Cloud SQL, but not in Datastore.\n"
+ "ReservedList 'testlist' has different entries in each database.\n"
+ "Found 2 unequal list(s).\n");
}
}

View file

@ -27,7 +27,7 @@ import com.google.common.io.Files;
import com.google.common.truth.Truth8;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListSqlDao;
import google.registry.model.registry.label.ReservedListDao;
import java.io.File;
import java.io.IOException;
import org.joda.time.DateTime;
@ -135,7 +135,7 @@ abstract class CreateOrUpdateReservedListCommandTestCase<
}
void verifyXnq9jyb4cInCloudSql() {
assertThat(ReservedListSqlDao.checkExists("xn--q9jyb4c_common-reserved")).isTrue();
assertThat(ReservedListDao.checkExists("xn--q9jyb4c_common-reserved")).isTrue();
ReservedList persistedList = getCloudSqlReservedList("xn--q9jyb4c_common-reserved");
assertThat(persistedList.getName()).isEqualTo("xn--q9jyb4c_common-reserved");
assertThat(persistedList.getShouldPublish()).isTrue();

View file

@ -23,7 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.model.registry.Registry;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedListDualDatabaseDao;
import google.registry.model.registry.label.ReservedListDao;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -41,7 +41,7 @@ class DeleteReservedListCommandTest extends CommandTestCase<DeleteReservedListCo
void testSuccess() throws Exception {
assertThat(reservedList.getReservedListEntries()).hasSize(1);
runCommandForced("--name=common");
assertThat(ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName())).isEmpty();
assertThat(ReservedListDao.getLatestRevision(reservedList.getName())).isEmpty();
}
@Test
@ -63,7 +63,7 @@ class DeleteReservedListCommandTest extends CommandTestCase<DeleteReservedListCo
assertThrows(
IllegalArgumentException.class,
() -> runCommandForced("--name=" + reservedList.getName()));
assertThat(ReservedListDualDatabaseDao.getLatestRevision(reservedList.getName())).isPresent();
assertThat(ReservedListDao.getLatestRevision(reservedList.getName())).isPresent();
assertThat(thrown)
.hasMessageThat()
.isEqualTo("Cannot delete reserved list because it is used on these tld(s): xn--q9jyb4c");

View file

@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.io.Files;
import google.registry.model.registry.label.ReservedList;
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
import google.registry.model.registry.label.ReservedListSqlDao;
import google.registry.model.registry.label.ReservedListDao;
import java.io.File;
import java.nio.file.Paths;
import org.junit.jupiter.api.BeforeEach;
@ -55,7 +55,7 @@ class UpdateReservedListCommandTest
}
private void populateInitialReservedListInCloudSql(boolean shouldPublish) {
ReservedListSqlDao.save(
ReservedListDao.save(
createCloudSqlReservedList(
"xn--q9jyb4c_common-reserved",
fakeClock.nowUtc(),
@ -128,7 +128,7 @@ class UpdateReservedListCommandTest
// Datastore when we update it.
runCommandForced("--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath);
verifyXnq9jyb4cInDatastore();
assertThat(ReservedListSqlDao.checkExists("xn--q9jyb4c_common-reserved")).isTrue();
assertThat(ReservedListDao.checkExists("xn--q9jyb4c_common-reserved")).isTrue();
}
@Test