mirror of
https://github.com/google/nomulus
synced 2026-07-06 00:04:50 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1e650bd0a1 | |||
| 2649a9362a | |||
| 3c65ad0f8a | |||
| 2bfd02f977 | |||
| 3af0f8c148 | |||
| 553b24e005 | |||
| 3bf697c43c |
+44
-1
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import java.lang.reflect.Constructor
|
||||
import com.google.common.base.CaseFormat
|
||||
import java.util.Optional
|
||||
|
||||
plugins {
|
||||
@@ -791,6 +791,49 @@ createUberJar(
|
||||
'beam_pipeline_common',
|
||||
'')
|
||||
|
||||
// Create beam staging task if environment is alpha or crash.
|
||||
// All other environments use formally released pipelines through CloudBuild.
|
||||
//
|
||||
// User should install gcloud and login to GCP before invoking this tasks.
|
||||
if (environment in ['alpha', 'crash']) {
|
||||
def pipelines = [
|
||||
[
|
||||
mainClass: 'google.registry.beam.initsql.InitSqlPipeline',
|
||||
metaData: 'google/registry/beam/init_sql_pipeline_metadata.json'
|
||||
],
|
||||
[
|
||||
mainClass: 'google.registry.beam.datastore.BulkDeleteDatastorePipeline',
|
||||
metaData: 'google/registry/beam/bulk_delete_datastore_pipeline_metadata.json'
|
||||
],
|
||||
]
|
||||
project.tasks.create("stage_beam_pipelines") {
|
||||
doLast {
|
||||
pipelines.each {
|
||||
def mainClass = it['mainClass']
|
||||
def metaData = it['metaData']
|
||||
def pipelineName = CaseFormat.UPPER_CAMEL.to(
|
||||
CaseFormat.LOWER_UNDERSCORE,
|
||||
mainClass.substring(mainClass.lastIndexOf('.') + 1))
|
||||
def imageName = "gcr.io/${gcpProject}/beam/${pipelineName}"
|
||||
def metaDataBaseName = metaData.substring(metaData.lastIndexOf('/') + 1)
|
||||
def uberJarName = tasks.beam_pipeline_common.outputs.files.asPath
|
||||
|
||||
def command = "\
|
||||
gcloud dataflow flex-template build \
|
||||
gs://${gcpProject}-deploy/live/beam/${metaDataBaseName} \
|
||||
--image-gcr-path ${imageName}:live \
|
||||
--sdk-language JAVA \
|
||||
--flex-template-base-image JAVA11 \
|
||||
--metadata-file ${projectDir}/src/main/resources/${metaData} \
|
||||
--jar ${uberJarName} \
|
||||
--env FLEX_TEMPLATE_JAVA_MAIN_CLASS=${mainClass} \
|
||||
--project ${gcpProject}".toString()
|
||||
rootProject.ext.execInBash(command, '/tmp')
|
||||
}
|
||||
}
|
||||
}.dependsOn(tasks.beam_pipeline_common)
|
||||
}
|
||||
|
||||
// A jar with classes and resources from main sourceSet, excluding internal
|
||||
// data. See comments on configurations.nomulus_test above for details.
|
||||
// TODO(weiminyu): release process should build this using the public repo to eliminate the need
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
// 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.batch;
|
||||
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.persistence.PersistenceModule.SchemaManagerConnection;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.util.Retrier;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Statement;
|
||||
import java.util.function.Supplier;
|
||||
import javax.inject.Inject;
|
||||
import org.flywaydb.core.api.FlywayException;
|
||||
|
||||
/**
|
||||
* Wipes out all Cloud SQL data in a Nomulus GCP environment.
|
||||
*
|
||||
* <p>This class is created for the QA environment, where migration testing with production data
|
||||
* will happen. A regularly scheduled wipeout is a prerequisite to using production data there.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = "/_dr/task/wipeOutCloudSql",
|
||||
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
|
||||
public class WipeOutCloudSqlAction implements Runnable {
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
// As a short-lived class, hardcode allowed projects here instead of using config files.
|
||||
private static final ImmutableSet<String> ALLOWED_PROJECTS =
|
||||
ImmutableSet.of("domain-registry-qa");
|
||||
|
||||
private final String projectId;
|
||||
private final Supplier<Connection> connectionSupplier;
|
||||
private final Response response;
|
||||
private final Retrier retrier;
|
||||
|
||||
@Inject
|
||||
WipeOutCloudSqlAction(
|
||||
@Config("projectId") String projectId,
|
||||
@SchemaManagerConnection Supplier<Connection> connectionSupplier,
|
||||
Response response,
|
||||
Retrier retrier) {
|
||||
this.projectId = projectId;
|
||||
this.connectionSupplier = connectionSupplier;
|
||||
this.response = response;
|
||||
this.retrier = retrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
response.setContentType(PLAIN_TEXT_UTF_8);
|
||||
|
||||
if (!ALLOWED_PROJECTS.contains(projectId)) {
|
||||
response.setStatus(SC_FORBIDDEN);
|
||||
response.setPayload("Wipeout is not allowed in " + projectId);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
retrier.callWithRetry(
|
||||
() -> {
|
||||
try (Connection conn = connectionSupplier.get();
|
||||
Statement statement = conn.createStatement()) {
|
||||
statement.execute("drop owned by schema_deployer;");
|
||||
}
|
||||
return null;
|
||||
},
|
||||
e -> !(e instanceof FlywayException));
|
||||
response.setStatus(SC_OK);
|
||||
response.setPayload("Wiped out Cloud SQL in " + projectId);
|
||||
} catch (RuntimeException e) {
|
||||
logger.atSevere().withCause(e).log("Failed to wipe out Cloud SQL data.");
|
||||
response.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
response.setPayload("Failed to wipe out Cloud SQL in " + projectId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,6 +379,12 @@
|
||||
<url-pattern>/_dr/task/relockDomain</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Action to wipeout Cloud SQL data -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>backend-servlet</servlet-name>
|
||||
<url-pattern>/_dr/task/wipeOutCloudSql</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Security config -->
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
|
||||
@@ -82,4 +82,13 @@
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
<cron>
|
||||
<url><![CDATA[/_dr/task/wipeOutCloudSql]]></url>
|
||||
<description>
|
||||
This job runs an action that deletes all data in Cloud SQL.
|
||||
</description>
|
||||
<schedule>every saturday 03:07</schedule>
|
||||
<target>backend</target>
|
||||
</cron>
|
||||
|
||||
</cronentries>
|
||||
|
||||
+11
-1
@@ -21,12 +21,13 @@ import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.model.EntityClasses;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.NotBackedUp;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.annotations.VirtualEntity;
|
||||
|
||||
/** Constants related to export code. */
|
||||
public final class ExportConstants {
|
||||
public final class AnnotatedEntities {
|
||||
|
||||
/** Returns the names of kinds to include in Datastore backups. */
|
||||
public static ImmutableSet<String> getBackupKinds() {
|
||||
@@ -49,4 +50,13 @@ public final class ExportConstants {
|
||||
.map(Key::getKind)
|
||||
.collect(toImmutableSortedSet(Ordering.natural()));
|
||||
}
|
||||
|
||||
/** Returns the names of kinds that are in the cross-TLD entity group. */
|
||||
public static ImmutableSet<String> getCrossTldKinds() {
|
||||
return EntityClasses.ALL_CLASSES.stream()
|
||||
.filter(hasAnnotation(InCrossTld.class))
|
||||
.filter(hasAnnotation(VirtualEntity.class).negate())
|
||||
.map(Key::getKind)
|
||||
.collect(toImmutableSortedSet(Ordering.natural()));
|
||||
}
|
||||
}
|
||||
@@ -66,12 +66,13 @@ public class BackupDatastoreAction implements Runnable {
|
||||
try {
|
||||
Operation backup =
|
||||
datastoreAdmin
|
||||
.export(RegistryConfig.getDatastoreBackupsBucket(), ExportConstants.getBackupKinds())
|
||||
.export(
|
||||
RegistryConfig.getDatastoreBackupsBucket(), AnnotatedEntities.getBackupKinds())
|
||||
.execute();
|
||||
|
||||
String backupName = backup.getName();
|
||||
// Enqueue a poll task to monitor the backup and load REPORTING-related kinds into bigquery.
|
||||
enqueuePollTask(backupName, ExportConstants.getReportingKinds());
|
||||
enqueuePollTask(backupName, AnnotatedEntities.getReportingKinds());
|
||||
String message =
|
||||
String.format(
|
||||
"Datastore backup started with name: %s\nSaving to %s",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// 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.annotations;
|
||||
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation for an Objectify {@link Entity} to indicate that it is in the cross-TLD entity group.
|
||||
*
|
||||
* <p>This means that the entity's <code>@Parent</code> field has to have the value of {@link
|
||||
* EntityGroupRoot#getCrossTldKey}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.TYPE})
|
||||
@Inherited
|
||||
public @interface InCrossTld {}
|
||||
@@ -20,11 +20,13 @@ import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
/** A singleton entity in Datastore. */
|
||||
@MappedSuperclass
|
||||
@InCrossTld
|
||||
public abstract class CrossTldSingleton extends ImmutableObject {
|
||||
|
||||
public static final long SINGLETON_ID = 1; // There is always exactly one of these.
|
||||
|
||||
@@ -29,6 +29,7 @@ import com.googlecode.objectify.annotation.OnLoad;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.common.Cursor.CursorId;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.persistence.VKey;
|
||||
@@ -51,6 +52,7 @@ import org.joda.time.DateTime;
|
||||
@Entity
|
||||
@javax.persistence.Entity
|
||||
@IdClass(CursorId.class)
|
||||
@InCrossTld
|
||||
public class Cursor extends ImmutableObject implements DatastoreAndSqlEntity {
|
||||
|
||||
/** The scope of a global cursor. A global cursor is a cursor that is not specific to one tld. */
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.googlecode.objectify.annotation.Mapify;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.common.TimedTransitionProperty.TimeMapper;
|
||||
import google.registry.model.common.TimedTransitionProperty.TimedTransition;
|
||||
import google.registry.model.registry.label.PremiumList;
|
||||
@@ -46,6 +47,7 @@ import org.joda.time.DateTime;
|
||||
|
||||
@Entity
|
||||
@Immutable
|
||||
@InCrossTld
|
||||
public class DatabaseTransitionSchedule extends ImmutableObject implements DatastoreOnlyEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.model.ofy;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
@@ -29,6 +30,8 @@ import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Streams;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.Result;
|
||||
import com.googlecode.objectify.cmd.Query;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.contact.ContactHistory;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.host.HostHistory;
|
||||
@@ -251,7 +254,13 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
|
||||
@Override
|
||||
public <T> ImmutableList<T> loadAllOf(Class<T> clazz) {
|
||||
return ImmutableList.copyOf(getOfy().load().type(clazz));
|
||||
Query<T> query = getOfy().load().type(clazz);
|
||||
// If the entity is in the cross-TLD entity group, then we can take advantage of an ancestor
|
||||
// query to give us strong transactional consistency.
|
||||
if (clazz.isAnnotationPresent(InCrossTld.class)) {
|
||||
query = query.ancestor(getCrossTldKey());
|
||||
}
|
||||
return ImmutableList.copyOf(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -298,6 +307,11 @@ public class DatastoreTransactionManager implements TransactionManager {
|
||||
getOfy().clearSessionCache();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOfy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the given {@link Result} instance synchronously if not in a transaction.
|
||||
*
|
||||
|
||||
@@ -72,6 +72,7 @@ import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.JsonMapBuilder;
|
||||
import google.registry.model.Jsonifiable;
|
||||
import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.model.registrar.Registrar.BillingAccountEntry.CurrencyMapper;
|
||||
@@ -112,6 +113,7 @@ import org.joda.time.DateTime;
|
||||
columnList = "ianaIdentifier",
|
||||
name = "registrar_iana_identifier_idx"),
|
||||
})
|
||||
@InCrossTld
|
||||
public class Registrar extends ImmutableObject
|
||||
implements Buildable, DatastoreAndSqlEntity, Jsonifiable {
|
||||
|
||||
@@ -985,9 +987,7 @@ public class Registrar extends ImmutableObject
|
||||
|
||||
/** Loads all registrar entities directly from Datastore. */
|
||||
public static Iterable<Registrar> loadAll() {
|
||||
return tm().isOfy()
|
||||
? ImmutableList.copyOf(ofy().load().type(Registrar.class).ancestor(getCrossTldKey()))
|
||||
: tm().transact(() -> tm().loadAllOf(Registrar.class));
|
||||
return transactIfJpaTm(() -> tm().loadAllOf(Registrar.class));
|
||||
}
|
||||
|
||||
/** Loads all registrar entities using an in-memory cache. */
|
||||
|
||||
@@ -44,6 +44,7 @@ import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.JsonMapBuilder;
|
||||
import google.registry.model.Jsonifiable;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.registrar.RegistrarContact.RegistrarPocId;
|
||||
import google.registry.persistence.VKey;
|
||||
@@ -77,6 +78,7 @@ import javax.persistence.Transient;
|
||||
@javax.persistence.Index(columnList = "gaeUserId", name = "registrarpoc_gae_user_id_idx")
|
||||
})
|
||||
@IdClass(RegistrarPocId.class)
|
||||
@InCrossTld
|
||||
public class RegistrarContact extends ImmutableObject
|
||||
implements DatastoreAndSqlEntity, Jsonifiable {
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.model.common.TimedTransitionProperty;
|
||||
@@ -86,6 +87,7 @@ import org.joda.time.Duration;
|
||||
@ReportedOn
|
||||
@Entity
|
||||
@javax.persistence.Entity(name = "Tld")
|
||||
@InCrossTld
|
||||
public class Registry extends ImmutableObject implements Buildable, DatastoreAndSqlEntity {
|
||||
|
||||
@Parent @Transient Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.label.ReservedList.ReservedListEntry;
|
||||
@@ -59,6 +60,7 @@ import org.joda.time.DateTime;
|
||||
* must subclass {@link DomainLabelEntry}.
|
||||
*/
|
||||
@MappedSuperclass
|
||||
@InCrossTld
|
||||
public abstract class BaseDomainLabelList<T extends Comparable<?>, R extends DomainLabelEntry<T, ?>>
|
||||
extends ImmutableObject implements Buildable {
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.schema.replay.DatastoreOnlyEntity;
|
||||
@@ -96,6 +97,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||
/** Virtual parent entity for premium list entry entities associated with a single revision. */
|
||||
@ReportedOn
|
||||
@Entity
|
||||
@InCrossTld
|
||||
public static class PremiumListRevision extends ImmutableObject implements DatastoreOnlyEntity {
|
||||
|
||||
@Parent Key<PremiumList> parent;
|
||||
@@ -195,6 +197,7 @@ public final class PremiumList extends BaseDomainLabelList<Money, PremiumList.Pr
|
||||
*/
|
||||
@ReportedOn
|
||||
@Entity
|
||||
@InCrossTld
|
||||
public static class PremiumListEntry extends DomainLabelEntry<Money, PremiumListEntry>
|
||||
implements Buildable, DatastoreOnlyEntity {
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Mapify;
|
||||
import com.googlecode.objectify.mapper.Mapper;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.label.DomainLabelMetrics.MetricsReservedListMatch;
|
||||
import google.registry.schema.replay.NonReplicatedEntity;
|
||||
@@ -62,6 +63,7 @@ import org.joda.time.DateTime;
|
||||
* revisionId. This is fine though, because we only use the list with the highest revisionId.
|
||||
*/
|
||||
@Entity
|
||||
@ReportedOn
|
||||
@javax.persistence.Entity
|
||||
@Table(indexes = {@Index(columnList = "name", name = "reservedlist_name_idx")})
|
||||
public final class ReservedList
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.schema.replay.DatastoreOnlyEntity;
|
||||
@@ -28,6 +29,7 @@ import google.registry.schema.replay.DatastoreOnlyEntity;
|
||||
/** Pointer to the latest {@link KmsSecretRevision}. */
|
||||
@Entity
|
||||
@ReportedOn
|
||||
@InCrossTld
|
||||
public class KmsSecret extends ImmutableObject implements DatastoreOnlyEntity {
|
||||
|
||||
/** The unique name of this {@link KmsSecret}. */
|
||||
|
||||
@@ -26,6 +26,7 @@ import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import google.registry.schema.replay.NonReplicatedEntity;
|
||||
import javax.persistence.Column;
|
||||
@@ -58,6 +59,7 @@ import javax.persistence.Transient;
|
||||
@ReportedOn
|
||||
@javax.persistence.Entity(name = "KmsSecret")
|
||||
@Table(indexes = {@Index(columnList = "secretName")})
|
||||
@InCrossTld
|
||||
public class KmsSecretRevision extends ImmutableObject implements NonReplicatedEntity {
|
||||
|
||||
/**
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.OnSave;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.NotBackedUp;
|
||||
import google.registry.model.annotations.NotBackedUp.Reason;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
@@ -67,6 +68,7 @@ import org.joda.time.DateTime;
|
||||
@Entity
|
||||
@javax.persistence.Entity
|
||||
@NotBackedUp(reason = Reason.EXTERNALLY_SOURCED)
|
||||
@InCrossTld
|
||||
public class SignedMarkRevocationList extends ImmutableObject implements NonReplicatedEntity {
|
||||
|
||||
@VisibleForTesting static final int SHARD_SIZE = 10000;
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.googlecode.objectify.annotation.OnSave;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.CreateAutoTimestamp;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.annotations.NotBackedUp;
|
||||
import google.registry.model.annotations.NotBackedUp.Reason;
|
||||
import google.registry.model.annotations.VirtualEntity;
|
||||
@@ -89,6 +90,7 @@ import org.joda.time.DateTime;
|
||||
@NotBackedUp(reason = Reason.EXTERNALLY_SOURCED)
|
||||
@javax.persistence.Entity(name = "ClaimsList")
|
||||
@Table
|
||||
@InCrossTld
|
||||
public class ClaimsListShard extends ImmutableObject implements NonReplicatedEntity {
|
||||
|
||||
/** The number of claims list entries to store per shard. */
|
||||
|
||||
@@ -36,6 +36,8 @@ import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.module.backend.BackendRequestComponent.BackendRequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||
import google.registry.rde.JSchModule;
|
||||
import google.registry.request.Modules.DatastoreServiceModule;
|
||||
import google.registry.request.Modules.Jackson2Module;
|
||||
@@ -71,6 +73,8 @@ import javax.inject.Singleton;
|
||||
KeyringModule.class,
|
||||
KmsModule.class,
|
||||
NetHttpTransportModule.class,
|
||||
PersistenceModule.class,
|
||||
SecretManagerModule.class,
|
||||
ServerTridProviderModule.class,
|
||||
SheetsServiceModule.class,
|
||||
StackdriverModule.class,
|
||||
|
||||
@@ -30,6 +30,7 @@ import google.registry.batch.RefreshDnsOnHostRenameAction;
|
||||
import google.registry.batch.RelockDomainAction;
|
||||
import google.registry.batch.ResaveAllEppResourcesAction;
|
||||
import google.registry.batch.ResaveEntityAction;
|
||||
import google.registry.batch.WipeOutCloudSqlAction;
|
||||
import google.registry.cron.CommitLogFanoutAction;
|
||||
import google.registry.cron.CronModule;
|
||||
import google.registry.cron.TldFanoutAction;
|
||||
@@ -205,6 +206,8 @@ interface BackendRequestComponent {
|
||||
|
||||
PublishInvoicesAction uploadInvoicesAction();
|
||||
|
||||
WipeOutCloudSqlAction wipeOutCloudSqlAction();
|
||||
|
||||
@Subcomponent.Builder
|
||||
abstract class Builder implements RequestComponentBuilder<BackendRequestComponent> {
|
||||
|
||||
|
||||
@@ -44,10 +44,14 @@ import google.registry.tools.AuthModule.CloudSqlClientCredential;
|
||||
import google.registry.util.Clock;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Qualifier;
|
||||
@@ -163,6 +167,37 @@ public abstract class PersistenceModule {
|
||||
return ImmutableMap.copyOf(overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a {@link Supplier} of single-use JDBC {@link Connection connections} that can manage
|
||||
* the database DDL schema.
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
@SchemaManagerConnection
|
||||
static Supplier<Connection> provideSchemaManagerConnectionSupplier(
|
||||
SqlCredentialStore credentialStore,
|
||||
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs) {
|
||||
SqlCredential credential =
|
||||
credentialStore.getCredential(new RobotUser(RobotId.SCHEMA_DEPLOYER));
|
||||
String user = credential.login();
|
||||
String password = credential.password();
|
||||
return () -> createJdbcConnection(user, password, cloudSqlConfigs);
|
||||
}
|
||||
|
||||
private static Connection createJdbcConnection(
|
||||
String user, String password, ImmutableMap<String, String> cloudSqlConfigs) {
|
||||
Properties properties = new Properties();
|
||||
properties.put("user", user);
|
||||
properties.put("password", password);
|
||||
properties.put("cloudSqlInstance", cloudSqlConfigs.get(HIKARI_DS_CLOUD_SQL_INSTANCE));
|
||||
properties.put("socketFactory", cloudSqlConfigs.get(HIKARI_DS_SOCKET_FACTORY));
|
||||
try {
|
||||
return DriverManager.getConnection(cloudSqlConfigs.get(Environment.URL), properties);
|
||||
} catch (SQLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@AppEngineJpaTm
|
||||
@@ -378,6 +413,11 @@ public abstract class PersistenceModule {
|
||||
}
|
||||
}
|
||||
|
||||
/** Dagger qualifier for JDBC {@link Connection} with schema management privilege. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
public @interface SchemaManagerConnection {}
|
||||
|
||||
/** Dagger qualifier for {@link JpaTransactionManager} used for App Engine application. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
|
||||
+5
@@ -531,6 +531,11 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
// This is an intended no-op method as there is no session cache in Postgresql.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOfy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void assertDelete(VKey<T> key) {
|
||||
if (internalDelete(key) != 1) {
|
||||
|
||||
+13
-13
@@ -17,7 +17,7 @@ package google.registry.persistence.transaction;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.ofy.DatastoreTransactionManager;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
@@ -130,7 +130,7 @@ public interface TransactionManager {
|
||||
void putAll(ImmutableCollection<?> entities);
|
||||
|
||||
/**
|
||||
* Persists a new entity or update the existing entity in the database without writing any backup
|
||||
* Persists a new entity or update the existing entity in the database without writing commit logs
|
||||
* if the underlying database is Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
@@ -142,8 +142,8 @@ public interface TransactionManager {
|
||||
void putWithoutBackup(Object entity);
|
||||
|
||||
/**
|
||||
* Persists all new entities or update the existing entities in the database without writing any
|
||||
* backup if the underlying database is Datastore.
|
||||
* Persists all new entities or update the existing entities in the database without writing
|
||||
* commit logs if the underlying database is Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
* the application code. When the method is invoked with Datastore, it won't write the commit log
|
||||
@@ -160,7 +160,7 @@ public interface TransactionManager {
|
||||
void updateAll(ImmutableCollection<?> entities);
|
||||
|
||||
/**
|
||||
* Updates an entity in the database without writing any backup if the underlying database is
|
||||
* Updates an entity in the database without writing commit logs if the underlying database is
|
||||
* Datastore.
|
||||
*
|
||||
* <p>This method is for the sake of keeping a single code path when replacing ofy() with tm() in
|
||||
@@ -240,7 +240,9 @@ public interface TransactionManager {
|
||||
/**
|
||||
* Returns a stream of all entities of the given type that exist in the database.
|
||||
*
|
||||
* <p>The resulting stream is empty if there are no entities of this type.
|
||||
* <p>The resulting stream is empty if there are no entities of this type. In Datastore mode, if
|
||||
* the class is a member of the cross-TLD entity group (i.e. if it has the {@link InCrossTld}
|
||||
* annotation, then the correct ancestor query will automatically be applied.
|
||||
*/
|
||||
<T> ImmutableList<T> loadAllOf(Class<T> clazz);
|
||||
|
||||
@@ -254,19 +256,19 @@ public interface TransactionManager {
|
||||
void delete(Object entity);
|
||||
|
||||
/**
|
||||
* Deletes the entity by its id without writing any backup if the underlying database is
|
||||
* Deletes the entity by its id without writing commit logs if the underlying database is
|
||||
* Datastore.
|
||||
*/
|
||||
void deleteWithoutBackup(VKey<?> key);
|
||||
|
||||
/**
|
||||
* Deletes the set of entities by their key id without writing any backup if the underlying
|
||||
* Deletes the set of entities by their key id without writing commit logs if the underlying
|
||||
* database is Datastore.
|
||||
*/
|
||||
void deleteWithoutBackup(Iterable<? extends VKey<?>> keys);
|
||||
|
||||
/**
|
||||
* Deletes the given entity from the database without writing any backup if the underlying
|
||||
* Deletes the given entity from the database without writing commit logs if the underlying
|
||||
* database is Datastore.
|
||||
*/
|
||||
void deleteWithoutBackup(Object entity);
|
||||
@@ -274,8 +276,6 @@ public interface TransactionManager {
|
||||
/** Clears the session cache if the underlying database is Datastore, otherwise it is a no-op. */
|
||||
void clearSessionCache();
|
||||
|
||||
/** Returns true if the transaction manager is DatastoreTransactionManager. */
|
||||
default boolean isOfy() {
|
||||
return this instanceof DatastoreTransactionManager;
|
||||
}
|
||||
/** Returns true if the transaction manager is DatastoreTransactionManager, false otherwise. */
|
||||
boolean isOfy();
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.tools;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
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 com.beust.jcommander.Parameter;
|
||||
@@ -61,13 +62,7 @@ final class DeleteTldCommand extends ConfirmingCommand implements CommandWithRem
|
||||
"Cannot delete TLD because registrar %s lists it as an allowed TLD",
|
||||
registrar.getClientId());
|
||||
}
|
||||
|
||||
int count = ofy().load()
|
||||
.type(DomainBase.class)
|
||||
.filter("tld", tld)
|
||||
.limit(1)
|
||||
.count();
|
||||
checkState(count == 0, "Cannot delete TLD because a domain is defined on it");
|
||||
checkState(!tldContainsDomains(tld), "Cannot delete TLD because a domain is defined on it");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,8 +72,25 @@ final class DeleteTldCommand extends ConfirmingCommand implements CommandWithRem
|
||||
|
||||
@Override
|
||||
protected String execute() {
|
||||
tm().transactNew(() -> ofy().delete().entity(registry).now());
|
||||
tm().transactNew(() -> tm().delete(registry));
|
||||
registry.invalidateInCache();
|
||||
return String.format("Deleted TLD '%s'.\n", tld);
|
||||
}
|
||||
|
||||
private boolean tldContainsDomains(String tld) {
|
||||
if (tm().isOfy()) {
|
||||
return ofy().load().type(DomainBase.class).filter("tld", tld).limit(1).count() > 0;
|
||||
} else {
|
||||
return jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.query("FROM Domain WHERE tld = :tld", DomainBase.class)
|
||||
.setParameter("tld", tld)
|
||||
.setMaxResults(1)
|
||||
.getResultStream()
|
||||
.findFirst()
|
||||
.isPresent());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,17 +15,19 @@
|
||||
package google.registry.tools;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
|
||||
import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.base.Strings;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.common.Cursor;
|
||||
import google.registry.model.common.Cursor.CursorType;
|
||||
import google.registry.model.registry.Registries;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.TldType;
|
||||
import google.registry.persistence.VKey;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -50,20 +52,18 @@ final class ListCursorsCommand implements CommandWithRemoteApi {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Map<Registry, Key<Cursor>> registries =
|
||||
Registries.getTlds()
|
||||
.stream()
|
||||
Map<Registry, VKey<Cursor>> registries =
|
||||
Registries.getTlds().stream()
|
||||
.map(Registry::get)
|
||||
.filter(r -> r.getTldType() == filterTldType)
|
||||
.filter(r -> !filterEscrowEnabled || r.getEscrowEnabled())
|
||||
.collect(toImmutableMap(r -> r, r -> Cursor.createKey(cursorType, r)));
|
||||
Map<Key<Cursor>, Cursor> cursors = ofy().load().keys(registries.values());
|
||||
.collect(toImmutableMap(r -> r, r -> Cursor.createVKey(cursorType, r.getTldStr())));
|
||||
ImmutableMap<VKey<? extends Cursor>, Cursor> cursors =
|
||||
transactIfJpaTm(() -> tm().loadByKeysIfPresent(registries.values()));
|
||||
if (!registries.isEmpty()) {
|
||||
String header = String.format(OUTPUT_FMT, "TLD", "Cursor Time", "Last Update Time");
|
||||
System.out.printf("%s\n%s\n", header, Strings.repeat("-", header.length()));
|
||||
registries
|
||||
.entrySet()
|
||||
.stream()
|
||||
registries.entrySet().stream()
|
||||
.map(
|
||||
e ->
|
||||
renderLine(
|
||||
|
||||
@@ -25,7 +25,7 @@ import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import google.registry.bigquery.BigqueryUtils.SourceFormat;
|
||||
import google.registry.export.ExportConstants;
|
||||
import google.registry.export.AnnotatedEntities;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -48,7 +48,7 @@ final class LoadSnapshotCommand extends BigqueryCommand {
|
||||
@Parameter(
|
||||
names = "--kinds",
|
||||
description = "List of Datastore kinds for which to import snapshot data.")
|
||||
private List<String> kindNames = new ArrayList<>(ExportConstants.getReportingKinds());
|
||||
private List<String> kindNames = new ArrayList<>(AnnotatedEntities.getReportingKinds());
|
||||
|
||||
/** Runs the main snapshot import logic. */
|
||||
@Override
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
package google.registry.tools.server;
|
||||
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static java.util.Comparator.comparing;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Streams;
|
||||
import google.registry.model.EppResourceUtils;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.request.Action;
|
||||
@@ -51,7 +51,7 @@ public final class ListHostsAction extends ListObjectsAction<HostResource> {
|
||||
@Override
|
||||
public ImmutableSet<HostResource> loadObjects() {
|
||||
final DateTime now = clock.nowUtc();
|
||||
return Streams.stream(ofy().load().type(HostResource.class))
|
||||
return transactIfJpaTm(() -> tm().loadAllOf(HostResource.class)).stream()
|
||||
.filter(host -> EppResourceUtils.isActive(host, now))
|
||||
.collect(toImmutableSortedSet(comparing(HostResource::getHostName)));
|
||||
}
|
||||
|
||||
@@ -14,16 +14,21 @@
|
||||
|
||||
package google.registry.tools.server;
|
||||
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
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.request.Action.Method.GET;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.registry.label.PremiumList;
|
||||
import google.registry.model.registry.label.PremiumListDualDao;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
/**
|
||||
* An action that lists premium lists, for use by the {@code nomulus list_premium_lists} command.
|
||||
@@ -46,7 +51,14 @@ public final class ListPremiumListsAction extends ListObjectsAction<PremiumList>
|
||||
|
||||
@Override
|
||||
public ImmutableSet<PremiumList> loadObjects() {
|
||||
return ImmutableSet.copyOf(
|
||||
ofy().load().type(PremiumList.class).ancestor(getCrossTldKey()).list());
|
||||
return transactIfJpaTm(
|
||||
() ->
|
||||
tm().loadAllOf(PremiumList.class).stream()
|
||||
.map(PremiumList::getName)
|
||||
.map(PremiumListDualDao::getLatestRevision)
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.peek(list -> Hibernate.initialize(list.getLabelsToPrices()))
|
||||
.collect(toImmutableSortedSet(Comparator.comparing(PremiumList::getName))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,15 +14,19 @@
|
||||
|
||||
package google.registry.tools.server;
|
||||
|
||||
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
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.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.request.Action;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** A that lists reserved lists, for use by the {@code nomulus list_reserved_lists} command. */
|
||||
@@ -44,7 +48,13 @@ public final class ListReservedListsAction extends ListObjectsAction<ReservedLis
|
||||
|
||||
@Override
|
||||
public ImmutableSet<ReservedList> loadObjects() {
|
||||
return ImmutableSet.copyOf(
|
||||
ofy().load().type(ReservedList.class).ancestor(getCrossTldKey()).list());
|
||||
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))));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
// 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.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.FakeSleeper;
|
||||
import google.registry.util.Retrier;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Statement;
|
||||
import org.flywaydb.core.api.FlywayException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
/** Unit tests for {@link WipeOutCloudSqlAction}. */
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
public class WipeOutCloudSqlActionTest {
|
||||
|
||||
@Mock private Statement stmt;
|
||||
@Mock private Connection conn;
|
||||
|
||||
private FakeResponse response = new FakeResponse();
|
||||
private Retrier retrier = new Retrier(new FakeSleeper(new FakeClock()), 2);
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() throws Exception {
|
||||
lenient().when(conn.createStatement()).thenReturn(stmt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_projectAllowed() throws Exception {
|
||||
WipeOutCloudSqlAction action =
|
||||
new WipeOutCloudSqlAction("domain-registry-qa", () -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
verify(stmt, times(1)).execute(anyString());
|
||||
verify(stmt, times(1)).close();
|
||||
verifyNoMoreInteractions(stmt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_projectNotAllowed() {
|
||||
WipeOutCloudSqlAction action =
|
||||
new WipeOutCloudSqlAction("domain-registry", () -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
verifyNoInteractions(stmt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_nonRetrieableFailure() throws Exception {
|
||||
doThrow(new FlywayException()).when(stmt).execute(anyString());
|
||||
WipeOutCloudSqlAction action =
|
||||
new WipeOutCloudSqlAction("domain-registry-qa", () -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_INTERNAL_SERVER_ERROR);
|
||||
verify(stmt, times(1)).execute(anyString());
|
||||
verify(stmt, times(1)).close();
|
||||
verifyNoMoreInteractions(stmt);
|
||||
}
|
||||
|
||||
@Test
|
||||
void run_retrieableFailure() throws Exception {
|
||||
when(stmt.execute(anyString())).thenThrow(new RuntimeException()).thenReturn(true);
|
||||
WipeOutCloudSqlAction action =
|
||||
new WipeOutCloudSqlAction("domain-registry-qa", () -> conn, response, retrier);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
verify(stmt, times(2)).execute(anyString());
|
||||
verify(stmt, times(2)).close();
|
||||
verifyNoMoreInteractions(stmt);
|
||||
}
|
||||
}
|
||||
+16
-8
@@ -19,8 +19,9 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static com.google.common.io.Resources.getResource;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
import static google.registry.export.ExportConstants.getBackupKinds;
|
||||
import static google.registry.export.ExportConstants.getReportingKinds;
|
||||
import static google.registry.export.AnnotatedEntities.getBackupKinds;
|
||||
import static google.registry.export.AnnotatedEntities.getCrossTldKinds;
|
||||
import static google.registry.export.AnnotatedEntities.getReportingKinds;
|
||||
import static google.registry.util.ResourceUtils.readResourceUtf8;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
@@ -31,13 +32,15 @@ import com.google.common.collect.Streams;
|
||||
import com.google.re2j.Pattern;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ExportConstants}. */
|
||||
class ExportConstantsTest {
|
||||
/** Unit tests for {@link AnnotatedEntities}. */
|
||||
class AnnotatedEntitiesTest {
|
||||
|
||||
private static final String GOLDEN_BACKUP_KINDS_FILENAME = "backup_kinds.txt";
|
||||
|
||||
private static final String GOLDEN_REPORTING_KINDS_FILENAME = "reporting_kinds.txt";
|
||||
|
||||
private static final String GOLDEN_CROSSTLD_KINDS_FILENAME = "crosstld_kinds.txt";
|
||||
|
||||
private static final String UPDATE_INSTRUCTIONS_TEMPLATE = Joiner.on('\n').join(
|
||||
"",
|
||||
repeat("-", 80),
|
||||
@@ -50,15 +53,20 @@ class ExportConstantsTest {
|
||||
"");
|
||||
|
||||
@Test
|
||||
void testBackupKinds_matchGoldenBackupKindsFile() {
|
||||
void testBackupKinds_matchGoldenFile() {
|
||||
checkKindsMatchGoldenFile("backed-up", GOLDEN_BACKUP_KINDS_FILENAME, getBackupKinds());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReportingKinds_matchGoldenReportingKindsFile() {
|
||||
void testReportingKinds_matchGoldenFile() {
|
||||
checkKindsMatchGoldenFile("reporting", GOLDEN_REPORTING_KINDS_FILENAME, getReportingKinds());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCrossTldKinds_matchGoldenFile() {
|
||||
checkKindsMatchGoldenFile("crosstld", GOLDEN_CROSSTLD_KINDS_FILENAME, getCrossTldKinds());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReportingKinds_areSubsetOfBackupKinds() {
|
||||
assertThat(getBackupKinds()).containsAtLeastElementsIn(getReportingKinds());
|
||||
@@ -70,7 +78,7 @@ class ExportConstantsTest {
|
||||
String.format(
|
||||
UPDATE_INSTRUCTIONS_TEMPLATE,
|
||||
kindsName,
|
||||
getResource(ExportConstantsTest.class, goldenFilename).toString(),
|
||||
getResource(AnnotatedEntitiesTest.class, goldenFilename).toString(),
|
||||
Joiner.on('\n').join(actualKinds));
|
||||
assertWithMessage(updateInstructions)
|
||||
.that(actualKinds)
|
||||
@@ -85,7 +93,7 @@ class ExportConstantsTest {
|
||||
* @return ImmutableList<String>
|
||||
*/
|
||||
private static ImmutableList<String> extractListFromFile(String filename) {
|
||||
String fileContents = readResourceUtf8(ExportConstantsTest.class, filename);
|
||||
String fileContents = readResourceUtf8(AnnotatedEntitiesTest.class, filename);
|
||||
final Pattern stripComments = Pattern.compile("\\s*#.*$");
|
||||
return Streams.stream(Splitter.on('\n').split(fileContents.trim()))
|
||||
.map(line -> stripComments.matcher(line).replaceFirst(""))
|
||||
@@ -54,7 +54,7 @@ public class BackupDatastoreActionTest {
|
||||
action.response = response;
|
||||
|
||||
when(datastoreAdmin.export(
|
||||
"gs://registry-project-id-datastore-backups", ExportConstants.getBackupKinds()))
|
||||
"gs://registry-project-id-datastore-backups", AnnotatedEntities.getBackupKinds()))
|
||||
.thenReturn(exportRequest);
|
||||
when(exportRequest.execute()).thenReturn(backupOperation);
|
||||
when(backupOperation.getName())
|
||||
@@ -73,7 +73,7 @@ public class BackupDatastoreActionTest {
|
||||
.param(CHECK_BACKUP_NAME_PARAM, "projects/registry-project-id/operations/ASA1ODYwNjc")
|
||||
.param(
|
||||
CHECK_BACKUP_KINDS_TO_LOAD_PARAM,
|
||||
Joiner.on(",").join(ExportConstants.getReportingKinds()))
|
||||
Joiner.on(",").join(AnnotatedEntities.getReportingKinds()))
|
||||
.method("POST"));
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(
|
||||
|
||||
+2
-6
@@ -20,13 +20,12 @@ import static com.google.common.collect.Iterables.getOnlyElement;
|
||||
import static com.google.common.collect.MoreCollectors.onlyElement;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.config.RegistryConfig.getContactAutomaticTransferLength;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.ContactResourceSubject.assertAboutContacts;
|
||||
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatabaseHelper.assertPollMessagesEqual;
|
||||
import static google.registry.testing.DatabaseHelper.deleteResource;
|
||||
import static google.registry.testing.DatabaseHelper.getPollMessages;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKeys;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.testing.EppExceptionSubject.assertAboutEppExceptions;
|
||||
@@ -136,10 +135,7 @@ class ContactTransferRequestFlowTest
|
||||
// poll messages, the approval notice ones for gaining and losing registrars.
|
||||
assertPollMessagesEqual(
|
||||
Iterables.filter(
|
||||
transactIfJpaTm(
|
||||
() -> tm().loadByKeys(contact.getTransferData().getServerApproveEntities()))
|
||||
.values(),
|
||||
PollMessage.class),
|
||||
loadByKeys(contact.getTransferData().getServerApproveEntities()), PollMessage.class),
|
||||
ImmutableList.of(gainingApproveMessage, losingApproveMessage));
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatabaseHelper.getOnlyPollMessage;
|
||||
import static google.registry.testing.DatabaseHelper.getPollMessages;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKey;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKeys;
|
||||
import static google.registry.testing.DatabaseHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveContact;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
@@ -300,15 +302,13 @@ class DomainTransferRequestFlowTest
|
||||
// Assert that the domain's TransferData server-approve billing events match the above.
|
||||
if (expectTransferBillingEvent) {
|
||||
assertBillingEventsEqual(
|
||||
transactIfJpaTm(
|
||||
() -> tm().loadByKey(domain.getTransferData().getServerApproveBillingEvent())),
|
||||
loadByKey(domain.getTransferData().getServerApproveBillingEvent()),
|
||||
optionalTransferBillingEvent.get());
|
||||
} else {
|
||||
assertThat(domain.getTransferData().getServerApproveBillingEvent()).isNull();
|
||||
}
|
||||
assertBillingEventsEqual(
|
||||
transactIfJpaTm(
|
||||
() -> tm().loadByKey(domain.getTransferData().getServerApproveAutorenewEvent())),
|
||||
loadByKey(domain.getTransferData().getServerApproveAutorenewEvent()),
|
||||
gainingClientAutorenew);
|
||||
// Assert that the full set of server-approve billing events is exactly the extra ones plus
|
||||
// the transfer billing event (if present) and the gaining client autorenew.
|
||||
@@ -318,14 +318,10 @@ class DomainTransferRequestFlowTest
|
||||
.collect(toImmutableSet());
|
||||
assertBillingEventsEqual(
|
||||
Iterables.filter(
|
||||
transactIfJpaTm(
|
||||
() ->
|
||||
tm().loadByKeys(domain.getTransferData().getServerApproveEntities()).values()),
|
||||
BillingEvent.class),
|
||||
loadByKeys(domain.getTransferData().getServerApproveEntities()), BillingEvent.class),
|
||||
Sets.union(expectedServeApproveBillingEvents, extraBillingEvents));
|
||||
// The domain's autorenew billing event should still point to the losing client's event.
|
||||
BillingEvent.Recurring domainAutorenewEvent =
|
||||
transactIfJpaTm(() -> tm().loadByKey(domain.getAutorenewBillingEvent()));
|
||||
BillingEvent.Recurring domainAutorenewEvent = loadByKey(domain.getAutorenewBillingEvent());
|
||||
assertThat(domainAutorenewEvent.getClientId()).isEqualTo("TheRegistrar");
|
||||
assertThat(domainAutorenewEvent.getRecurrenceEndTime()).isEqualTo(implicitTransferTime);
|
||||
// The original grace periods should remain untouched.
|
||||
@@ -421,17 +417,13 @@ class DomainTransferRequestFlowTest
|
||||
|
||||
// Assert that the poll messages show up in the TransferData server approve entities.
|
||||
assertPollMessagesEqual(
|
||||
transactIfJpaTm(
|
||||
() -> tm().loadByKey(domain.getTransferData().getServerApproveAutorenewPollMessage())),
|
||||
loadByKey(domain.getTransferData().getServerApproveAutorenewPollMessage()),
|
||||
autorenewPollMessage);
|
||||
// Assert that the full set of server-approve poll messages is exactly the server approve
|
||||
// OneTime messages to gaining and losing registrars plus the gaining client autorenew.
|
||||
assertPollMessagesEqual(
|
||||
Iterables.filter(
|
||||
transactIfJpaTm(
|
||||
() ->
|
||||
tm().loadByKeys(domain.getTransferData().getServerApproveEntities()).values()),
|
||||
PollMessage.class),
|
||||
loadByKeys(domain.getTransferData().getServerApproveEntities()), PollMessage.class),
|
||||
ImmutableList.of(
|
||||
transferApprovedPollMessage, losingTransferApprovedPollMessage, autorenewPollMessage));
|
||||
}
|
||||
@@ -449,11 +441,7 @@ class DomainTransferRequestFlowTest
|
||||
.hasLastEppUpdateTime(implicitTransferTime)
|
||||
.and()
|
||||
.hasLastEppUpdateClientId("NewRegistrar");
|
||||
assertThat(
|
||||
transactIfJpaTm(
|
||||
() ->
|
||||
tm().loadByKey(domainAfterAutomaticTransfer.getAutorenewBillingEvent())
|
||||
.getEventTime()))
|
||||
assertThat(loadByKey(domainAfterAutomaticTransfer.getAutorenewBillingEvent()).getEventTime())
|
||||
.isEqualTo(expectedExpirationTime);
|
||||
// And after the expected grace time, the grace period should be gone.
|
||||
DomainBase afterGracePeriod =
|
||||
|
||||
@@ -19,10 +19,10 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.assertNoBillingEvents;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.newDomainBase;
|
||||
import static google.registry.testing.DatabaseHelper.newHostResource;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
@@ -302,8 +302,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResour
|
||||
.hasPersistedCurrentSponsorClientId("TheRegistrar")
|
||||
.and()
|
||||
.hasLastTransferTime(oneDayAgo);
|
||||
DomainBase reloadedDomain =
|
||||
transactIfJpaTm(() -> tm().loadByEntity(domain)).cloneProjectedAtTime(now);
|
||||
DomainBase reloadedDomain = loadByEntity(domain).cloneProjectedAtTime(now);
|
||||
assertThat(reloadedDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns1.example.tld", "ns2.example.tld");
|
||||
}
|
||||
@@ -337,15 +336,8 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResour
|
||||
.hasPersistedCurrentSponsorClientId("TheRegistrar")
|
||||
.and()
|
||||
.hasLastTransferTime(null);
|
||||
assertThat(
|
||||
transactIfJpaTm(() -> tm().loadByEntity(foo))
|
||||
.cloneProjectedAtTime(now)
|
||||
.getSubordinateHosts())
|
||||
.isEmpty();
|
||||
assertThat(
|
||||
transactIfJpaTm(() -> tm().loadByEntity(example))
|
||||
.cloneProjectedAtTime(now)
|
||||
.getSubordinateHosts())
|
||||
assertThat(loadByEntity(foo).cloneProjectedAtTime(now).getSubordinateHosts()).isEmpty();
|
||||
assertThat(loadByEntity(example).cloneProjectedAtTime(now).getSubordinateHosts())
|
||||
.containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns2.foo.tld", "ns2.example.tld");
|
||||
}
|
||||
@@ -380,11 +372,9 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResour
|
||||
.hasPersistedCurrentSponsorClientId("TheRegistrar")
|
||||
.and()
|
||||
.hasLastTransferTime(null);
|
||||
DomainBase reloadedFooDomain =
|
||||
transactIfJpaTm(() -> tm().loadByEntity(fooDomain)).cloneProjectedAtTime(now);
|
||||
DomainBase reloadedFooDomain = loadByEntity(fooDomain).cloneProjectedAtTime(now);
|
||||
assertThat(reloadedFooDomain.getSubordinateHosts()).isEmpty();
|
||||
DomainBase reloadedTldDomain =
|
||||
transactIfJpaTm(() -> tm().loadByEntity(tldDomain)).cloneProjectedAtTime(now);
|
||||
DomainBase reloadedTldDomain = loadByEntity(tldDomain).cloneProjectedAtTime(now);
|
||||
assertThat(reloadedTldDomain.getSubordinateHosts()).containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns1.example.foo", "ns2.example.tld");
|
||||
}
|
||||
@@ -427,8 +417,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResour
|
||||
.and()
|
||||
.hasLastSuperordinateChange(clock.nowUtc());
|
||||
assertThat(renamedHost.getLastTransferTime()).isEqualTo(oneDayAgo);
|
||||
DomainBase reloadedDomain =
|
||||
transactIfJpaTm(() -> tm().loadByEntity(domain)).cloneProjectedAtTime(clock.nowUtc());
|
||||
DomainBase reloadedDomain = loadByEntity(domain).cloneProjectedAtTime(clock.nowUtc());
|
||||
assertThat(reloadedDomain.getSubordinateHosts()).isEmpty();
|
||||
assertDnsTasksEnqueued("ns1.example.foo");
|
||||
}
|
||||
@@ -464,10 +453,7 @@ class HostUpdateFlowTest extends ResourceFlowTestCase<HostUpdateFlow, HostResour
|
||||
.hasPersistedCurrentSponsorClientId("TheRegistrar")
|
||||
.and()
|
||||
.hasLastTransferTime(null);
|
||||
assertThat(
|
||||
transactIfJpaTm(() -> tm().loadByEntity(domain))
|
||||
.cloneProjectedAtTime(now)
|
||||
.getSubordinateHosts())
|
||||
assertThat(loadByEntity(domain).cloneProjectedAtTime(now).getSubordinateHosts())
|
||||
.containsExactly("ns2.example.tld");
|
||||
assertDnsTasksEnqueued("ns2.example.tld");
|
||||
}
|
||||
|
||||
@@ -19,8 +19,9 @@ import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIM
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.ofyTmOrDoNothing;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.loadByKey;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||
@@ -184,14 +185,11 @@ public class BillingEventTest extends EntityTestCase {
|
||||
|
||||
@TestOfyAndSql
|
||||
void testPersistence() {
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(oneTime))).isEqualTo(oneTime);
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(oneTimeSynthetic)))
|
||||
.isEqualTo(oneTimeSynthetic);
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(recurring))).isEqualTo(recurring);
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(cancellationOneTime)))
|
||||
.isEqualTo(cancellationOneTime);
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(cancellationRecurring)))
|
||||
.isEqualTo(cancellationRecurring);
|
||||
assertThat(loadByEntity(oneTime)).isEqualTo(oneTime);
|
||||
assertThat(loadByEntity(oneTimeSynthetic)).isEqualTo(oneTimeSynthetic);
|
||||
assertThat(loadByEntity(recurring)).isEqualTo(recurring);
|
||||
assertThat(loadByEntity(cancellationOneTime)).isEqualTo(cancellationOneTime);
|
||||
assertThat(loadByEntity(cancellationRecurring)).isEqualTo(cancellationRecurring);
|
||||
|
||||
ofyTmOrDoNothing(() -> assertThat(tm().loadByEntity(modification)).isEqualTo(modification));
|
||||
}
|
||||
@@ -220,10 +218,8 @@ public class BillingEventTest extends EntityTestCase {
|
||||
|
||||
@TestOfyAndSql
|
||||
void testCancellationMatching() {
|
||||
VKey<?> recurringKey =
|
||||
transactIfJpaTm(
|
||||
() -> tm().loadByEntity(oneTimeSynthetic).getCancellationMatchingBillingEvent());
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByKey(recurringKey))).isEqualTo(recurring);
|
||||
VKey<?> recurringKey = loadByEntity(oneTimeSynthetic).getCancellationMatchingBillingEvent();
|
||||
assertThat(loadByKey(recurringKey)).isEqualTo(recurring);
|
||||
}
|
||||
|
||||
@TestOfyOnly
|
||||
|
||||
@@ -22,9 +22,8 @@ import static google.registry.model.domain.token.AllocationToken.TokenStatus.NOT
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenStatus.VALID;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadByEntity;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
@@ -78,8 +77,7 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
.put(DateTime.now(UTC).plusWeeks(8), TokenStatus.ENDED)
|
||||
.build())
|
||||
.build());
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(unlimitedUseToken)))
|
||||
.isEqualTo(unlimitedUseToken);
|
||||
assertThat(loadByEntity(unlimitedUseToken)).isEqualTo(unlimitedUseToken);
|
||||
|
||||
DomainBase domain = persistActiveDomain("example.foo");
|
||||
Key<HistoryEntry> historyEntryKey = Key.create(Key.create(domain), HistoryEntry.class, 1);
|
||||
@@ -92,7 +90,7 @@ public class AllocationTokenTest extends EntityTestCase {
|
||||
.setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z"))
|
||||
.setTokenType(SINGLE_USE)
|
||||
.build());
|
||||
assertThat(transactIfJpaTm(() -> tm().loadByEntity(singleUseToken))).isEqualTo(singleUseToken);
|
||||
assertThat(loadByEntity(singleUseToken)).isEqualTo(singleUseToken);
|
||||
}
|
||||
|
||||
@TestOfyOnly
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// 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.ofy;
|
||||
|
||||
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 static google.registry.testing.DatabaseHelper.persistResources;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.Key;
|
||||
import com.googlecode.objectify.annotation.Entity;
|
||||
import com.googlecode.objectify.annotation.Id;
|
||||
import com.googlecode.objectify.annotation.Parent;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.annotations.InCrossTld;
|
||||
import google.registry.model.common.EntityGroupRoot;
|
||||
import google.registry.schema.replay.EntityTest.EntityForTesting;
|
||||
import google.registry.testing.AppEngineExtension;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link DatastoreTransactionManager}. */
|
||||
public class DatastoreTransactionManagerTest {
|
||||
|
||||
@RegisterExtension
|
||||
public final AppEngineExtension appEngine =
|
||||
AppEngineExtension.builder()
|
||||
.withDatastore()
|
||||
.withOfyTestEntities(InCrossTldTestEntity.class)
|
||||
.build();
|
||||
|
||||
@Test
|
||||
void test_loadAllOf_usesAncestorQuery() {
|
||||
InCrossTldTestEntity foo = new InCrossTldTestEntity("foo");
|
||||
InCrossTldTestEntity bar = new InCrossTldTestEntity("bar");
|
||||
InCrossTldTestEntity baz = new InCrossTldTestEntity("baz");
|
||||
baz.parent = null;
|
||||
persistResources(ImmutableList.of(foo, bar, baz));
|
||||
// baz is excluded by the cross-TLD ancestor query
|
||||
assertThat(ofyTm().loadAllOf(InCrossTldTestEntity.class)).containsExactly(foo, bar);
|
||||
}
|
||||
|
||||
@Entity
|
||||
@EntityForTesting
|
||||
@InCrossTld
|
||||
private static class InCrossTldTestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name;
|
||||
@Parent Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
|
||||
private InCrossTldTestEntity(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// Needs to exist to make Objectify happy.
|
||||
@SuppressWarnings("unused")
|
||||
private InCrossTldTestEntity() {}
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||
import com.google.common.base.Ascii;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableCollection;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -1244,5 +1245,45 @@ public class DatabaseHelper {
|
||||
clientId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads (i.e. reloads) the specified entity from the DB.
|
||||
*
|
||||
* <p>If the transaction manager is Cloud SQL, then this creates an inner wrapping transaction for
|
||||
* convenience, so you don't need to wrap it in a transaction at the callsite.
|
||||
*/
|
||||
public static <T> T loadByEntity(T entity) {
|
||||
return transactIfJpaTm(() -> tm().loadByEntity(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified entity by its key from the DB.
|
||||
*
|
||||
* <p>If the transaction manager is Cloud SQL, then this creates an inner wrapping transaction for
|
||||
* convenience, so you don't need to wrap it in a transaction at the callsite.
|
||||
*/
|
||||
public static <T> T loadByKey(VKey<T> key) {
|
||||
return transactIfJpaTm(() -> tm().loadByKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the specified entities by their keys from the DB.
|
||||
*
|
||||
* <p>If the transaction manager is Cloud SQL, then this creates an inner wrapping transaction for
|
||||
* convenience, so you don't need to wrap it in a transaction at the callsite.
|
||||
*/
|
||||
public static <T> ImmutableCollection<T> loadByKeys(Iterable<? extends VKey<? extends T>> keys) {
|
||||
return transactIfJpaTm(() -> tm().loadByKeys(keys).values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all of the entities of the specified type from the DB.
|
||||
*
|
||||
* <p>If the transaction manager is Cloud SQL, then this creates an inner wrapping transaction for
|
||||
* convenience, so you don't need to wrap it in a transaction at the callsite.
|
||||
*/
|
||||
public static <T> ImmutableList<T> loadAllOf(Class<T> clazz) {
|
||||
return transactIfJpaTm(() -> tm().loadAllOf(clazz));
|
||||
}
|
||||
|
||||
private DatabaseHelper() {}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static google.registry.model.domain.token.AllocationToken.TokenType.SINGL
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.createTlds;
|
||||
import static google.registry.testing.DatabaseHelper.loadAllOf;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveDomain;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
@@ -134,10 +135,9 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
|
||||
for (int i = 0; i < 50; i++) {
|
||||
persistToken(String.format("batch%2d", i), null, i % 2 == 0);
|
||||
}
|
||||
assertThat(transactIfJpaTm(() -> tm().loadAllOf(AllocationToken.class).size())).isEqualTo(56);
|
||||
assertThat(loadAllOf(AllocationToken.class).size()).isEqualTo(56);
|
||||
runCommandForced("--prefix", "batch");
|
||||
assertThat(transactIfJpaTm(() -> tm().loadAllOf(AllocationToken.class).size()))
|
||||
.isEqualTo(56 - 25);
|
||||
assertThat(loadAllOf(AllocationToken.class).size()).isEqualTo(56 - 25);
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
|
||||
@@ -27,11 +27,13 @@ import com.google.common.collect.ImmutableSortedMap;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.Registry.RegistryNotFoundException;
|
||||
import google.registry.model.registry.Registry.TldType;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link DeleteTldCommand}. */
|
||||
@DualDatabaseTest
|
||||
class DeleteTldCommandTest extends CommandTestCase<DeleteTldCommand> {
|
||||
|
||||
private static final String TLD_REAL = "tldreal";
|
||||
@@ -53,7 +55,7 @@ class DeleteTldCommandTest extends CommandTestCase<DeleteTldCommand> {
|
||||
TldType.TEST));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testSuccess_otherTldUnaffected() throws Exception {
|
||||
runCommandForced("--tld=" + TLD_TEST);
|
||||
|
||||
@@ -61,24 +63,24 @@ class DeleteTldCommandTest extends CommandTestCase<DeleteTldCommand> {
|
||||
assertThrows(RegistryNotFoundException.class, () -> Registry.get(TLD_TEST));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_whenTldDoesNotExist() {
|
||||
assertThrows(RegistryNotFoundException.class, () -> runCommandForced("--tld=nonexistenttld"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_whenTldIsReal() {
|
||||
assertThrows(IllegalStateException.class, () -> runCommandForced("--tld=" + TLD_REAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_whenDomainsArePresent() {
|
||||
persistDeletedDomain("domain." + TLD_TEST, DateTime.parse("2000-01-01TZ"));
|
||||
|
||||
assertThrows(IllegalStateException.class, () -> runCommandForced("--tld=" + TLD_TEST));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testFailure_whenRegistrarLinksToTld() {
|
||||
allowRegistrarAccess("TheRegistrar", TLD_TEST);
|
||||
|
||||
|
||||
@@ -17,10 +17,9 @@ package google.registry.tools;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.SINGLE_USE;
|
||||
import static google.registry.model.domain.token.AllocationToken.TokenType.UNLIMITED_USE;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
|
||||
import static google.registry.testing.DatabaseHelper.assertAllocationTokens;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.loadAllOf;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
@@ -134,7 +133,7 @@ class GenerateAllocationTokensCommandTest extends CommandTestCase<GenerateAlloca
|
||||
runCommand("--prefix", "ooo", "--number", "100", "--length", "16");
|
||||
// The deterministic string generator makes it too much hassle to assert about each token, so
|
||||
// just assert total number.
|
||||
assertThat(transactIfJpaTm(() -> tm().loadAllOf(AllocationToken.class).size())).isEqualTo(100);
|
||||
assertThat(loadAllOf(AllocationToken.class).size()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
@@ -199,7 +198,7 @@ class GenerateAllocationTokensCommandTest extends CommandTestCase<GenerateAlloca
|
||||
Collection<String> sampleTokens = command.stringGenerator.createStrings(13, 100);
|
||||
runCommand("--tokens", Joiner.on(",").join(sampleTokens));
|
||||
assertInStdout(Iterables.toArray(sampleTokens, String.class));
|
||||
assertThat(transactIfJpaTm(() -> tm().loadAllOf(AllocationToken.class).size())).isEqualTo(100);
|
||||
assertThat(loadAllOf(AllocationToken.class).size()).isEqualTo(100);
|
||||
}
|
||||
|
||||
@TestOfyAndSql
|
||||
|
||||
@@ -24,14 +24,15 @@ import google.registry.model.common.Cursor;
|
||||
import google.registry.model.common.Cursor.CursorType;
|
||||
import google.registry.model.ofy.Ofy;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.InjectExtension;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
|
||||
/** Unit tests for {@link ListCursorsCommand}. */
|
||||
@DualDatabaseTest
|
||||
public class ListCursorsCommandTest extends CommandTestCase<ListCursorsCommand> {
|
||||
|
||||
private static final String HEADER_ONE =
|
||||
@@ -44,17 +45,17 @@ public class ListCursorsCommandTest extends CommandTestCase<ListCursorsCommand>
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
inject.setStaticField(
|
||||
Ofy.class, "clock", new FakeClock(DateTime.parse("1984-12-21T06:07:08.789Z")));
|
||||
fakeClock.setTo(DateTime.parse("1984-12-21T06:07:08.789Z"));
|
||||
inject.setStaticField(Ofy.class, "clock", fakeClock);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testListCursors_noTlds_printsNothing() throws Exception {
|
||||
runCommand("--type=BRDA");
|
||||
assertThat(getStdoutAsString()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testListCursors_twoTldsOneAbsent_printsAbsentAndTimestampSorted() throws Exception {
|
||||
createTlds("foo", "bar");
|
||||
persistResource(
|
||||
@@ -69,19 +70,19 @@ public class ListCursorsCommandTest extends CommandTestCase<ListCursorsCommand>
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testListCursors_badCursor_throwsIae() {
|
||||
ParameterException thrown =
|
||||
assertThrows(ParameterException.class, () -> runCommand("--type=love"));
|
||||
assertThat(thrown).hasMessageThat().contains("Invalid value for --type parameter.");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testListCursors_lowercaseCursor_isAllowed() throws Exception {
|
||||
runCommand("--type=brda");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testListCursors_filterEscrowEnabled_doesWhatItSays() throws Exception {
|
||||
createTlds("foo", "bar");
|
||||
persistResource(Registry.get("bar").asBuilder().setEscrowEnabled(true).build());
|
||||
|
||||
@@ -17,13 +17,15 @@ package google.registry.tools.server;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistActiveHost;
|
||||
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ListHostsAction}. */
|
||||
@DualDatabaseTest
|
||||
class ListHostsActionTest extends ListActionTestCase {
|
||||
|
||||
private ListHostsAction action;
|
||||
@@ -35,7 +37,7 @@ class ListHostsActionTest extends ListActionTestCase {
|
||||
action.clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_noParameters() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -44,7 +46,7 @@ class ListHostsActionTest extends ListActionTestCase {
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_twoLinesWithRepoId() {
|
||||
persistActiveHost("example2.foo");
|
||||
persistActiveHost("example1.foo");
|
||||
@@ -59,7 +61,7 @@ class ListHostsActionTest extends ListActionTestCase {
|
||||
"^example2.foo\\s+2-ROID\\s*$");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_twoLinesWithWildcard() {
|
||||
persistActiveHost("example2.foo");
|
||||
persistActiveHost("example1.foo");
|
||||
@@ -74,7 +76,7 @@ class ListHostsActionTest extends ListActionTestCase {
|
||||
"^example2.foo\\s+.*1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_twoLinesWithWildcardAndAnotherField() {
|
||||
persistActiveHost("example2.foo");
|
||||
persistActiveHost("example1.foo");
|
||||
@@ -89,7 +91,7 @@ class ListHostsActionTest extends ListActionTestCase {
|
||||
"^example2.foo\\s+.*1");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_withBadField_returnsError() {
|
||||
persistActiveHost("example2.foo");
|
||||
persistActiveHost("example1.foo");
|
||||
|
||||
@@ -16,11 +16,15 @@ package google.registry.tools.server;
|
||||
|
||||
import static google.registry.testing.DatabaseHelper.persistPremiumList;
|
||||
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import google.registry.testing.TestOfyOnly;
|
||||
import google.registry.testing.TestSqlOnly;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ListPremiumListsAction}. */
|
||||
@DualDatabaseTest
|
||||
class ListPremiumListsActionTest extends ListActionTestCase {
|
||||
|
||||
private ListPremiumListsAction action;
|
||||
@@ -32,7 +36,7 @@ class ListPremiumListsActionTest extends ListActionTestCase {
|
||||
action = new ListPremiumListsAction();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_noParameters() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -43,7 +47,7 @@ class ListPremiumListsActionTest extends ListActionTestCase {
|
||||
"^xn--q9jyb4c$");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyOnly // only ofy has revisionKey
|
||||
void testRun_withParameters() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -56,7 +60,20 @@ class ListPremiumListsActionTest extends ListActionTestCase {
|
||||
"^xn--q9jyb4c\\s+.*PremiumList.*$");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestSqlOnly
|
||||
void testRun_withLabelsToPrices() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
Optional.of("labelsToPrices"),
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
"^name\\s+labelsToPrices\\s*$",
|
||||
"^-+\\s+-+\\s*$",
|
||||
"^how\\s+\\{richer=5000\\.00\\}$",
|
||||
"^xn--q9jyb4c\\s+\\{rich=100\\.00\\}\\s+$");
|
||||
}
|
||||
|
||||
@TestOfyOnly
|
||||
void testRun_withWildcard() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -69,7 +86,7 @@ class ListPremiumListsActionTest extends ListActionTestCase {
|
||||
"^xn--q9jyb4c\\s+.*PremiumList");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_withBadField_returnsError() {
|
||||
testRunError(
|
||||
action,
|
||||
|
||||
@@ -20,11 +20,13 @@ import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.label.ReservedList;
|
||||
import google.registry.testing.DualDatabaseTest;
|
||||
import google.registry.testing.TestOfyAndSql;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ListReservedListsAction}. */
|
||||
@DualDatabaseTest
|
||||
class ListReservedListsActionTest extends ListActionTestCase {
|
||||
|
||||
private ListReservedListsAction action;
|
||||
@@ -38,7 +40,7 @@ class ListReservedListsActionTest extends ListActionTestCase {
|
||||
action = new ListReservedListsAction();
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_noParameters() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -49,7 +51,7 @@ class ListReservedListsActionTest extends ListActionTestCase {
|
||||
"^xn--q9jyb4c-published\\s*$");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_withParameters() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -62,7 +64,7 @@ class ListReservedListsActionTest extends ListActionTestCase {
|
||||
"^xn--q9jyb4c-published\\s+true\\s*$");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_withWildcard() {
|
||||
testRunSuccess(
|
||||
action,
|
||||
@@ -75,7 +77,7 @@ class ListReservedListsActionTest extends ListActionTestCase {
|
||||
"^xn--q9jyb4c-published\\s+.*true");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestOfyAndSql
|
||||
void testRun_withBadField_returnsError() {
|
||||
testRunError(
|
||||
action,
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
ClaimsListShard
|
||||
ClaimsListSingleton
|
||||
Cursor
|
||||
DatabaseTransitionSchedule
|
||||
KmsSecret
|
||||
KmsSecretRevision
|
||||
PremiumList
|
||||
PremiumListEntry
|
||||
PremiumListRevision
|
||||
Registrar
|
||||
RegistrarContact
|
||||
Registry
|
||||
ReservedList
|
||||
ServerSecret
|
||||
SignedMarkRevocationList
|
||||
TmchCrl
|
||||
@@ -20,3 +20,4 @@ Recurring
|
||||
Registrar
|
||||
RegistrarContact
|
||||
Registry
|
||||
ReservedList
|
||||
|
||||
@@ -43,3 +43,4 @@ PATH CLASS METHOD
|
||||
/_dr/task/updateRegistrarRdapBaseUrls UpdateRegistrarRdapBaseUrlsAction GET y INTERNAL,API APP ADMIN
|
||||
/_dr/task/updateSnapshotView UpdateSnapshotViewAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/uploadDatastoreBackup UploadDatastoreBackupAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/wipeOutCloudSql WipeOutCloudSqlAction GET n INTERNAL,API APP ADMIN
|
||||
|
||||
@@ -133,3 +133,16 @@ for more information.
|
||||
|
||||
[app-engine-sdk]: https://cloud.google.com/appengine/docs/java/download
|
||||
[java-jdk11]: https://www.oracle.com/java/technologies/javase-downloads.html
|
||||
|
||||
## Deploy the BEAM Pipelines
|
||||
|
||||
Nomulus is in the middle of migrating all pipelines to use flex-template. For
|
||||
pipelines already based on flex-template, deployment in the testing environments
|
||||
(alpha and crash) can be done using the following command:
|
||||
|
||||
```shell
|
||||
./nom_build :core:stage_beam_pipelines --environment=alpha
|
||||
```
|
||||
|
||||
Pipeline deployment in other environments are through CloudBuild. Please refer
|
||||
to the [release folder](http://github.com/google/nomulus/release) for details.
|
||||
|
||||
Reference in New Issue
Block a user