diff --git a/core/src/main/java/google/registry/model/OteAccountBuilder.java b/core/src/main/java/google/registry/model/OteAccountBuilder.java index 56f236788..23ab6de5b 100644 --- a/core/src/main/java/google/registry/model/OteAccountBuilder.java +++ b/core/src/main/java/google/registry/model/OteAccountBuilder.java @@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static com.google.common.collect.ImmutableList.toImmutableList; -import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.model.registry.Registry.TldState.GENERAL_AVAILABILITY; import static google.registry.model.registry.Registry.TldState.START_DATE_SUNRISE; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; @@ -41,10 +40,10 @@ import google.registry.model.registry.Registry; import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.label.PremiumList; import google.registry.model.registry.label.PremiumListDualDao; +import google.registry.persistence.VKey; import google.registry.util.CidrAddressBlock; import java.util.Collection; import java.util.Optional; -import java.util.Set; import java.util.function.Function; import java.util.regex.Pattern; import org.joda.money.CurrencyUnit; @@ -225,15 +224,14 @@ public final class OteAccountBuilder { } /** - * Persists all the OT&E entities to datastore. + * Persists all the OT&E entities to the database. * * @return map from the new clientIds created to the new TLDs they have access to. Can be used to * go over all the newly created Registrars / Registries / RegistrarContacts if any * post-creation work is needed. */ public ImmutableMap buildAndPersist() { - // save all the entitiesl in a single transaction - tm().transact(this::saveAllEntities); + saveAllEntities(); return clientIdToTld; } @@ -246,30 +244,38 @@ public final class OteAccountBuilder { /** Saves all the OT&E entities we created. */ private void saveAllEntities() { - tm().assertInTransaction(); - // use ImmutableObject instead of Registry so that the Key generation doesn't break - ImmutableList registries = ImmutableList.of(sunriseTld, gaTld, eapTld); + ImmutableList registries = ImmutableList.of(sunriseTld, gaTld, eapTld); ImmutableList contacts = contactsBuilder.build(); - if (!replaceExisting) { - ImmutableList> keys = - Streams.concat(registries.stream(), registrars.stream(), contacts.stream()) - .map(Key::create) - .collect(toImmutableList()); - Set> existingKeys = ofy().load().keys(keys).keySet(); - checkState( - existingKeys.isEmpty(), - "Found existing object(s) conflicting with OT&E objects: %s", - existingKeys); - } - // Save the Registries (TLDs) first - ofy().save().entities(registries).now(); - // Now we can set the allowedTlds for the registrars - registrars = registrars.stream().map(this::addAllowedTld).collect(toImmutableList()); - // and we can save the registrars and contacts! - ofy().save().entities(registrars); - ofy().save().entities(contacts); + tm().transact( + () -> { + if (!replaceExisting) { + ImmutableList> keys = + Streams.concat( + registries.stream() + .map(registry -> Registry.createVKey(registry.getTldStr())), + registrars.stream().map(Registrar::createVKey), + contacts.stream().map(RegistrarContact::createVKey)) + .collect(toImmutableList()); + ImmutableMap, ImmutableObject> existingObjects = + tm().loadByKeysIfPresent(keys); + checkState( + existingObjects.isEmpty(), + "Found existing object(s) conflicting with OT&E objects: %s", + existingObjects.keySet()); + } + // Save the Registries (TLDs) first + tm().putAll(registries); + }); + // Now we can set the allowedTlds for the registrars in a new transaction + tm().transact( + () -> { + registrars = registrars.stream().map(this::addAllowedTld).collect(toImmutableList()); + // and we can save the registrars and contacts! + tm().putAll(registrars); + tm().putAll(contacts); + }); } private Registrar addAllowedTld(Registrar registrar) { diff --git a/core/src/main/java/google/registry/model/OteStats.java b/core/src/main/java/google/registry/model/OteStats.java index e7bb1bdb0..977ef797c 100644 --- a/core/src/main/java/google/registry/model/OteStats.java +++ b/core/src/main/java/google/registry/model/OteStats.java @@ -17,7 +17,6 @@ package google.registry.model; import static com.google.common.base.Predicates.equalTo; import static com.google.common.collect.ImmutableList.toImmutableList; import static google.registry.model.eppcommon.EppXmlTransformer.unmarshal; -import static google.registry.model.ofy.ObjectifyService.ofy; import static google.registry.util.CollectionUtils.isNullOrEmpty; import static google.registry.util.DomainNameUtils.ACE_PREFIX; @@ -28,7 +27,6 @@ import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; import com.google.common.collect.Multiset; import com.googlecode.objectify.Key; -import com.googlecode.objectify.cmd.Query; import google.registry.model.domain.DomainCommand; import google.registry.model.domain.fee.FeeCreateCommandExtension; import google.registry.model.domain.launch.LaunchCreateExtension; @@ -39,6 +37,7 @@ import google.registry.model.eppinput.EppInput.ResourceCommandWrapper; import google.registry.model.host.HostCommand; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.HistoryEntry.Type; +import google.registry.model.reporting.HistoryEntryDao; import google.registry.xml.XmlException; import java.util.Arrays; import java.util.EnumSet; @@ -196,16 +195,10 @@ public class OteStats { *

Stops when it notices that all tests have passed. */ private OteStats recordRegistrarHistory(String registrarName) { - ImmutableCollection clientIds = + ImmutableCollection registrarIds = OteAccountBuilder.createClientIdToTldMap(registrarName).keySet(); - Query query = - ofy() - .load() - .type(HistoryEntry.class) - .filter("clientId in", clientIds) - .order("modificationTime"); - for (HistoryEntry historyEntry : query) { + for (HistoryEntry historyEntry : HistoryEntryDao.loadHistoryObjectsByRegistrars(registrarIds)) { try { record(historyEntry); } catch (XmlException e) { diff --git a/core/src/main/java/google/registry/model/reporting/HistoryEntryDao.java b/core/src/main/java/google/registry/model/reporting/HistoryEntryDao.java index ada8130a9..c86b4b103 100644 --- a/core/src/main/java/google/registry/model/reporting/HistoryEntryDao.java +++ b/core/src/main/java/google/registry/model/reporting/HistoryEntryDao.java @@ -21,7 +21,9 @@ import static google.registry.persistence.transaction.TransactionManagerFactory. import static google.registry.util.DateTimeUtils.END_OF_TIME; import static google.registry.util.DateTimeUtils.START_OF_TIME; +import com.google.common.collect.ImmutableCollection; import com.google.common.collect.Iterables; +import com.google.common.collect.Streams; import google.registry.model.EppResource; import google.registry.model.contact.ContactHistory; import google.registry.model.contact.ContactResource; @@ -30,7 +32,11 @@ import google.registry.model.domain.DomainHistory; import google.registry.model.host.HostHistory; import google.registry.model.host.HostResource; import google.registry.persistence.VKey; +import google.registry.persistence.transaction.CriteriaQueryBuilder; import java.util.Comparator; +import java.util.stream.Stream; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; import org.joda.time.DateTime; /** @@ -85,21 +91,56 @@ public class HistoryEntryDao { } } + /** Loads all history objects from all time from the given registrars. */ + public static Iterable loadHistoryObjectsByRegistrars( + ImmutableCollection registrarIds) { + if (tm().isOfy()) { + return ofy() + .load() + .type(HistoryEntry.class) + .filter("clientId in", registrarIds) + .order("modificationTime"); + } else { + return jpaTm() + .transact( + () -> + Streams.concat( + loadHistoryObjectFromSqlByRegistrars(ContactHistory.class, registrarIds), + loadHistoryObjectFromSqlByRegistrars(DomainHistory.class, registrarIds), + loadHistoryObjectFromSqlByRegistrars(HostHistory.class, registrarIds)) + .sorted(Comparator.comparing(HistoryEntry::getModificationTime)) + .collect(toImmutableList())); + } + } + + private static Stream loadHistoryObjectFromSqlByRegistrars( + Class historyClass, ImmutableCollection registrarIds) { + return jpaTm() + .getEntityManager() + .createQuery( + CriteriaQueryBuilder.create(historyClass) + .whereFieldIsIn("clientId", registrarIds) + .build()) + .getResultStream(); + } + private static Iterable loadHistoryObjectsForResourceFromSql( VKey parentKey, DateTime afterTime, DateTime beforeTime) { + // The class we're searching from is based on which parent type (e.g. Domain) we have Class historyClass = getHistoryClassFromParent(parentKey.getKind()); + // The field representing repo ID unfortunately varies by history class String repoIdFieldName = getRepoIdFieldNameFromHistoryClass(historyClass); - String tableName = jpaTm().getEntityManager().getMetamodel().entity(historyClass).getName(); - String queryString = - String.format( - "SELECT entry FROM %s entry WHERE entry.modificationTime >= :afterTime AND " - + "entry.modificationTime <= :beforeTime AND entry.%s = :parentKey", - tableName, repoIdFieldName); + CriteriaBuilder criteriaBuilder = jpaTm().getEntityManager().getCriteriaBuilder(); + CriteriaQuery criteriaQuery = + CriteriaQueryBuilder.create(historyClass) + .where("modificationTime", criteriaBuilder::greaterThanOrEqualTo, afterTime) + .where("modificationTime", criteriaBuilder::lessThanOrEqualTo, beforeTime) + .where(repoIdFieldName, criteriaBuilder::equal, parentKey.getSqlKey().toString()) + .build(); + return jpaTm() - .query(queryString, historyClass) - .setParameter("afterTime", afterTime) - .setParameter("beforeTime", beforeTime) - .setParameter("parentKey", parentKey.getSqlKey().toString()) + .getEntityManager() + .createQuery(criteriaQuery) .getResultStream() .sorted(Comparator.comparing(HistoryEntry::getModificationTime)) .collect(toImmutableList()); @@ -127,15 +168,14 @@ public class HistoryEntryDao { private static Iterable loadAllHistoryObjectsFromSql( Class historyClass, DateTime afterTime, DateTime beforeTime) { + CriteriaBuilder criteriaBuilder = jpaTm().getEntityManager().getCriteriaBuilder(); return jpaTm() - .query( - String.format( - "SELECT entry FROM %s entry WHERE entry.modificationTime >= :afterTime AND " - + "entry.modificationTime <= :beforeTime", - jpaTm().getEntityManager().getMetamodel().entity(historyClass).getName()), - historyClass) - .setParameter("afterTime", afterTime) - .setParameter("beforeTime", beforeTime) + .getEntityManager() + .createQuery( + CriteriaQueryBuilder.create(historyClass) + .where("modificationTime", criteriaBuilder::greaterThanOrEqualTo, afterTime) + .where("modificationTime", criteriaBuilder::lessThanOrEqualTo, beforeTime) + .build()) .getResultList(); } } diff --git a/core/src/main/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java b/core/src/main/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java index 92ef3c964..0f005e4a5 100644 --- a/core/src/main/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java +++ b/core/src/main/java/google/registry/request/auth/AuthenticatedRegistrarAccessor.java @@ -19,6 +19,9 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.Streams.stream; import static google.registry.model.ofy.ObjectifyService.ofy; +import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm; +import static google.registry.persistence.transaction.TransactionManagerFactory.tm; +import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm; import com.google.appengine.api.users.User; import com.google.common.annotations.VisibleForTesting; @@ -316,30 +319,46 @@ public class AuthenticatedRegistrarAccessor { logger.atInfo().log("Checking registrar contacts for user ID %s", user.getUserId()); // Find all registrars that have a registrar contact with this user's ID. - ImmutableList> accessibleClientIds = - stream(ofy().load().type(RegistrarContact.class).filter("gaeUserId", user.getUserId())) - .map(RegistrarContact::getParent) - .collect(toImmutableList()); - // Filter out disabled registrars (note that pending registrars still allow console login). - ofy().load().keys(accessibleClientIds).values().stream() - .filter(registrar -> registrar.getState() != State.DISABLED) - .forEach(registrar -> builder.put(registrar.getClientId(), Role.OWNER)); + if (tm().isOfy()) { + ImmutableList> accessibleClientIds = + stream(ofy().load().type(RegistrarContact.class).filter("gaeUserId", user.getUserId())) + .map(RegistrarContact::getParent) + .collect(toImmutableList()); + // Filter out disabled registrars (note that pending registrars still allow console login). + ofy().load().keys(accessibleClientIds).values().stream() + .filter(registrar -> registrar.getState() != State.DISABLED) + .forEach(registrar -> builder.put(registrar.getClientId(), Role.OWNER)); + } else { + jpaTm() + .transact( + () -> + jpaTm() + .query( + "SELECT r FROM Registrar r INNER JOIN RegistrarPoc rp ON " + + "r.clientIdentifier = rp.registrarId WHERE rp.gaeUserId = " + + ":gaeUserId AND r.state != :state", + Registrar.class) + .setParameter("gaeUserId", user.getUserId()) + .setParameter("state", State.DISABLED) + .getResultStream() + .forEach(registrar -> builder.put(registrar.getClientId(), Role.OWNER))); + } // Admins have ADMIN access to all registrars, and also OWNER access to the registry registrar // and all non-REAL or non-live registrars. if (isAdmin) { - ofy() - .load() - .type(Registrar.class) - .forEach( - registrar -> { - if (registrar.getType() != Registrar.Type.REAL - || !registrar.isLive() - || registrar.getClientId().equals(registryAdminClientId)) { - builder.put(registrar.getClientId(), Role.OWNER); - } - builder.put(registrar.getClientId(), Role.ADMIN); - }); + transactIfJpaTm( + () -> + tm().loadAllOf(Registrar.class) + .forEach( + registrar -> { + if (registrar.getType() != Registrar.Type.REAL + || !registrar.isLive() + || registrar.getClientId().equals(registryAdminClientId)) { + builder.put(registrar.getClientId(), Role.OWNER); + } + builder.put(registrar.getClientId(), Role.ADMIN); + })); } return builder.build(); diff --git a/core/src/test/java/google/registry/model/OteStatsTest.java b/core/src/test/java/google/registry/model/OteStatsTest.java index 5e6ca0767..8a88d15ba 100644 --- a/core/src/test/java/google/registry/model/OteStatsTest.java +++ b/core/src/test/java/google/registry/model/OteStatsTest.java @@ -15,19 +15,28 @@ package google.registry.model; import static com.google.common.truth.Truth.assertThat; +import static google.registry.testing.DatabaseHelper.createTld; import google.registry.model.OteStats.StatType; import google.registry.testing.AppEngineExtension; -import org.junit.jupiter.api.Test; +import google.registry.testing.DualDatabaseTest; +import google.registry.testing.TestOfyAndSql; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.RegisterExtension; +@DualDatabaseTest public final class OteStatsTest { @RegisterExtension public final AppEngineExtension appEngine = AppEngineExtension.builder().withDatastoreAndCloudSql().build(); - @Test + @BeforeEach + void beforeEach() { + createTld("tld"); + } + + @TestOfyAndSql void testSuccess_allPass() throws Exception { OteStatsTestHelper.setupCompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); @@ -35,7 +44,7 @@ public final class OteStatsTest { assertThat(stats.getSize()).isEqualTo(30); } - @Test + @TestOfyAndSql void testSuccess_incomplete() throws Exception { OteStatsTestHelper.setupIncompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); @@ -46,7 +55,7 @@ public final class OteStatsTest { assertThat(stats.getSize()).isEqualTo(34); } - @Test + @TestOfyAndSql void testSuccess_toString() throws Exception { OteStatsTestHelper.setupCompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); @@ -87,7 +96,7 @@ public final class OteStatsTest { assertThat(stats.toString()).isEqualTo(expected); } - @Test + @TestOfyAndSql void testIncomplete_toString() throws Exception { OteStatsTestHelper.setupIncompleteOte("blobio"); OteStats stats = OteStats.getFromRegistrar("blobio"); diff --git a/core/src/test/java/google/registry/model/OteStatsTestHelper.java b/core/src/test/java/google/registry/model/OteStatsTestHelper.java index 66dcefa71..cf1202665 100644 --- a/core/src/test/java/google/registry/model/OteStatsTestHelper.java +++ b/core/src/test/java/google/registry/model/OteStatsTestHelper.java @@ -14,126 +14,168 @@ package google.registry.model; +import static google.registry.testing.DatabaseHelper.createTld; +import static google.registry.testing.DatabaseHelper.persistActiveDomain; +import static google.registry.testing.DatabaseHelper.persistActiveHost; +import static google.registry.testing.DatabaseHelper.persistDeletedDomain; +import static google.registry.testing.DatabaseHelper.persistDeletedHost; import static google.registry.testing.DatabaseHelper.persistPremiumList; import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.TestDataHelper.loadBytes; import static google.registry.util.DateTimeUtils.END_OF_TIME; +import google.registry.model.domain.DomainHistory; import google.registry.model.eppcommon.Trid; -import google.registry.model.reporting.HistoryEntry; +import google.registry.model.host.HostHistory; import google.registry.model.reporting.HistoryEntry.Type; import java.io.IOException; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; public final class OteStatsTestHelper { public static void setupCompleteOte(String baseClientId) throws IOException { setupIncompleteOte(baseClientId); String oteAccount1 = String.format("%s-1", baseClientId); + DateTime now = DateTime.now(DateTimeZone.UTC); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("xn--abc-873b2e7eb1k8a4lpjvv.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_CREATE) .setXmlBytes(getBytes("domain_create_idn.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_RESTORE) .setXmlBytes(getBytes("domain_restore.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new HostHistory.Builder() + .setHostRepoId(persistDeletedHost("ns1.example.tld", now).getRepoId()) .setClientId(oteAccount1) .setType(Type.HOST_DELETE) .setXmlBytes(getBytes("host_delete.xml")) + .setModificationTime(now) .build()); } /** * Sets up an incomplete OT&E registrar. It is missing the following entries: * - * - DOMAIN_CREATES_IDN - * - DOMAIN_RESTORES - * - HOST_DELETES + *

    + *
  • DOMAIN_CREATES_IDN + *
  • DOMAIN_RESTORES + *
  • HOST_DELETES + *
* - * TODO(b/122830156): Have this replicate the exact OT&E workflow with the correct client IDs + *

TODO(b/122830156): Have this replicate the exact OT&E workflow with the correct client IDs */ public static void setupIncompleteOte(String baseClientId) throws IOException { + createTld("tld"); persistPremiumList("default_sandbox_list", "sandbox,USD 1000"); OteAccountBuilder.forClientId(baseClientId).addContact("email@example.com").buildAndPersist(); String oteAccount1 = String.format("%s-1", baseClientId); + DateTime now = DateTime.now(DateTimeZone.UTC); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("exampleone.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_CREATE) .setXmlBytes(getBytes("domain_create_sunrise.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example-one.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_CREATE) .setXmlBytes(getBytes("domain_create_claim_notice.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_CREATE) .setXmlBytes(getBytes("domain_create_anchor_tenant_fee_standard.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_CREATE) .setXmlBytes(getBytes("domain_create_dsdata.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistDeletedDomain("example.tld", now).getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_DELETE) .setXmlBytes(getBytes("domain_delete.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_TRANSFER_APPROVE) .setXmlBytes(getBytes("domain_transfer_approve.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_TRANSFER_CANCEL) .setXmlBytes(getBytes("domain_transfer_cancel.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_TRANSFER_REJECT) .setXmlBytes(getBytes("domain_transfer_reject.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_TRANSFER_REQUEST) .setXmlBytes(getBytes("domain_transfer_request.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new DomainHistory.Builder() + .setDomainRepoId(persistActiveDomain("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.DOMAIN_UPDATE) .setXmlBytes(getBytes("domain_update_with_secdns.xml")) + .setModificationTime(now) .build()); persistResource( - new HistoryEntry.Builder() + new HostHistory.Builder() + .setHostRepoId(persistActiveHost("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.HOST_CREATE) .setXmlBytes(getBytes("host_create_complete.xml")) + .setModificationTime(now) .build()); // Persist 10 host updates for a total of 25 history entries. Since these also sort last by // modification time, when these cause all tests to pass, only the first will be recorded and // the rest will be skipped. for (int i = 0; i < 10; i++) { persistResource( - new HistoryEntry.Builder() + new HostHistory.Builder() + .setHostRepoId(persistActiveHost("example.tld").getRepoId()) .setClientId(oteAccount1) .setType(Type.HOST_UPDATE) .setXmlBytes(getBytes("host_update.xml")) diff --git a/core/src/test/java/google/registry/request/auth/AuthenticatedRegistrarAccessorTest.java b/core/src/test/java/google/registry/request/auth/AuthenticatedRegistrarAccessorTest.java index 6993a9ba1..772525eb6 100644 --- a/core/src/test/java/google/registry/request/auth/AuthenticatedRegistrarAccessorTest.java +++ b/core/src/test/java/google/registry/request/auth/AuthenticatedRegistrarAccessorTest.java @@ -38,14 +38,15 @@ import google.registry.model.registrar.Registrar; import google.registry.model.registrar.Registrar.State; import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException; import google.registry.testing.AppEngineExtension; +import google.registry.testing.DualDatabaseTest; import google.registry.testing.InjectExtension; +import google.registry.testing.TestOfyAndSql; import java.util.Optional; import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; import org.mockito.Mock; @@ -56,6 +57,7 @@ import org.mockito.quality.Strictness; /** Unit tests for {@link AuthenticatedRegistrarAccessor}. */ @ExtendWith(MockitoExtension.class) @MockitoSettings(strictness = Strictness.LENIENT) +@DualDatabaseTest class AuthenticatedRegistrarAccessorTest { @RegisterExtension @@ -132,7 +134,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Users are owners for registrars if and only if they are in the contacts for that registrar. */ - @Test + @TestOfyAndSql void getAllClientIdWithAccess_user() { AuthenticatedRegistrarAccessor registrarAccessor = new AuthenticatedRegistrarAccessor( @@ -144,7 +146,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Logged out users don't have access to anything. */ - @Test + @TestOfyAndSql void getAllClientIdWithAccess_loggedOutUser() { AuthenticatedRegistrarAccessor registrarAccessor = new AuthenticatedRegistrarAccessor( @@ -165,7 +167,7 @@ class AuthenticatedRegistrarAccessorTest { * *

(in other words - they don't have OWNER access only to REAL registrars owned by others) */ - @Test + @TestOfyAndSql void getAllClientIdWithAccess_gaeAdmin() { AuthenticatedRegistrarAccessor registrarAccessor = new AuthenticatedRegistrarAccessor( @@ -197,7 +199,7 @@ class AuthenticatedRegistrarAccessorTest { * *

(in other words - they don't have OWNER access only to REAL registrars owned by others) */ - @Test + @TestOfyAndSql void getAllClientIdWithAccess_userInSupportGroup() { when(groupsConnection.isMemberOfGroup("user@gmail.com", SUPPORT_GROUP.get())).thenReturn(true); AuthenticatedRegistrarAccessor registrarAccessor = @@ -220,7 +222,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Empty Support group email - skips check and doesn't generate the lazy. */ - @Test + @TestOfyAndSql void getAllClientIdWithAccess_emptySupportEmail_works() { AuthenticatedRegistrarAccessor registrarAccessor = new AuthenticatedRegistrarAccessor( @@ -233,7 +235,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Support group check throws - continue anyway. */ - @Test + @TestOfyAndSql void getAllClientIdWithAccess_throwingGroupCheck_stillWorks() { when(groupsConnection.isMemberOfGroup(any(), any())).thenThrow(new RuntimeException("blah")); AuthenticatedRegistrarAccessor registrarAccessor = @@ -247,7 +249,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Fail loading registrar if user doesn't have access to it. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_noAccess_isNotAdmin() { expectGetRegistrarFailure( REAL_CLIENT_ID_WITHOUT_CONTACT, @@ -256,7 +258,7 @@ class AuthenticatedRegistrarAccessorTest { verify(lazyGroupsConnection).get(); } - @Test + @TestOfyAndSql void testGetRegistrarForUser_registrarIsDisabled_isNotAdmin() { persistResource( Registrar.loadByClientId("TheRegistrar") @@ -272,7 +274,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Fail loading registrar if user doesn't have access to it, even if it's not REAL. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_noAccess_isNotAdmin_notReal() { expectGetRegistrarFailure( OTE_CLIENT_ID_WITHOUT_CONTACT, @@ -282,7 +284,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Fail loading registrar if there's no user associated with the request. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_noUser() { expectGetRegistrarFailure( CLIENT_ID_WITH_CONTACT, @@ -292,7 +294,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Succeed loading registrar if user has access to it. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_inContacts_isNotAdmin() throws Exception { expectGetRegistrarSuccess( CLIENT_ID_WITH_CONTACT, @@ -302,7 +304,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Succeed loading registrar if admin with access. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_inContacts_isAdmin() throws Exception { expectGetRegistrarSuccess( CLIENT_ID_WITH_CONTACT, @@ -312,7 +314,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Succeed loading registrar for admin even if they aren't on the approved contacts list. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_notInContacts_isAdmin() throws Exception { expectGetRegistrarSuccess( REAL_CLIENT_ID_WITHOUT_CONTACT, @@ -321,7 +323,7 @@ class AuthenticatedRegistrarAccessorTest { verifyNoInteractions(lazyGroupsConnection); } - @Test + @TestOfyAndSql void testGetRegistrarForUser_registrarIsDisabled_isAdmin() throws Exception { persistResource( Registrar.loadByClientId("NewRegistrar") @@ -337,7 +339,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Succeed loading non-REAL registrar for admin. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_notInContacts_isAdmin_notReal() throws Exception { expectGetRegistrarSuccess( OTE_CLIENT_ID_WITHOUT_CONTACT, @@ -347,7 +349,7 @@ class AuthenticatedRegistrarAccessorTest { } /** Fail loading registrar even if admin, if registrar doesn't exist. */ - @Test + @TestOfyAndSql void testGetRegistrarForUser_doesntExist_isAdmin() { expectGetRegistrarFailure( "BadClientId", @@ -382,7 +384,7 @@ class AuthenticatedRegistrarAccessorTest { } /** guessClientIdForUser returns the first clientId in getAllClientIdWithRoles. */ - @Test + @TestOfyAndSql void testGuessClientIdForUser_hasAccess_returnsFirst() throws Exception { AuthenticatedRegistrarAccessor registrarAccessor = AuthenticatedRegistrarAccessor.createForTesting( @@ -395,7 +397,7 @@ class AuthenticatedRegistrarAccessorTest { } /** If a user doesn't have access to any registrars, guess fails. */ - @Test + @TestOfyAndSql void testGuessClientIdForUser_noAccess_fails() { AuthenticatedRegistrarAccessor registrarAccessor = AuthenticatedRegistrarAccessor.createForTesting(ImmutableSetMultimap.of()); @@ -405,7 +407,7 @@ class AuthenticatedRegistrarAccessorTest { .isEqualTo("TestUserId isn't associated with any registrar"); } - @Test + @TestOfyAndSql void testNullness() { new NullPointerTester() .setDefault(HttpServletRequest.class, req) diff --git a/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_edit.png b/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_edit.png index 7d04602d9..00314a5cc 100644 Binary files a/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_edit.png and b/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_edit.png differ diff --git a/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_view.png b/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_view.png index e8202b4b3..41ae9cc5b 100644 Binary files a/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_view.png and b/core/src/test/resources/google/registry/webdriver/goldens/chrome-linux/RegistrarConsoleScreenshotTest_settingsAdmin_whenAdmin_view.png differ