Remove Ofy support from Cursor (#1672)

Cursor was originally envisioned to support arbitary ImmutableObject
scopes. However, in practice only the Registry scope is used. The SQL
representation of Cursor assumes that and the schema uses a composite ID
with a string column for the primary key of the scope object. Without a
schema migration to persist the VKey of the scope, we cannot support any
ImmutableObject other than those with a primitive string primary key.

Given the complexity involved and the limited use case, the scope is now
explictly limited to Registry only.

Also removed mapreduces that depends on Ofy keys of Cursors, and made
some code quality improvement based on IntelliJ suggestions on modified
files.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/1672)
<!-- Reviewable:end -->
This commit is contained in:
Lai Jiang 2022-06-28 14:59:21 -04:00 committed by GitHub
parent eb1b283ba3
commit 76d63b24a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 235 additions and 341 deletions

View file

@ -279,7 +279,7 @@ public class RdeIO {
transactIfJpaTm(
() ->
tm().loadByKeyIfPresent(
Cursor.createVKey(key.cursor(), registry.getTldStr())));
Cursor.createScopedVKey(key.cursor(), registry)));
DateTime position = getCursorTimeOrStartOfTime(cursor);
checkState(key.interval() != null, "Interval must be present");
DateTime newPosition = key.watermark().plus(key.interval());
@ -292,7 +292,7 @@ public class RdeIO {
"Partial ordering of RDE deposits broken: %s %s",
position,
key);
tm().put(Cursor.create(key.cursor(), newPosition, registry));
tm().put(Cursor.createScoped(key.cursor(), newPosition, registry));
logger.atInfo().log(
"Rolled forward %s on %s cursor to %s.", key.cursor(), key.tld(), newPosition);
RdeRevision.saveRevision(key.tld(), key.watermark(), key.mode(), input.getValue());

View file

@ -27,7 +27,6 @@ import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
@ -42,7 +41,9 @@ import java.net.URL;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import javax.inject.Named;
@ -1266,7 +1267,7 @@ public final class RegistryConfig {
e.getKey().equals("START_OF_TIME")
? START_OF_TIME
: DateTime.parse(e.getKey()),
e -> e.getValue()));
Entry::getValue));
}
@Provides

View file

@ -17,7 +17,6 @@ package google.registry.model;
import com.google.common.collect.ImmutableSet;
import google.registry.model.annotations.DeleteAfterMigration;
import google.registry.model.billing.BillingEvent;
import google.registry.model.common.Cursor;
import google.registry.model.common.EntityGroupRoot;
import google.registry.model.common.GaeUserIdConverter;
import google.registry.model.contact.ContactHistory;
@ -54,7 +53,6 @@ public final class EntityClasses {
BillingEvent.Recurring.class,
ContactHistory.class,
ContactResource.class,
Cursor.class,
DomainBase.class,
DomainHistory.class,
EntityGroupRoot.class,

View file

@ -57,6 +57,8 @@ import org.joda.time.DateTime;
@Access(AccessType.FIELD) // otherwise it'll use the default if the repoId (property)
public abstract class EppResource extends BackupGroupRoot implements Buildable {
private static final long serialVersionUID = -252782773382339534L;
/**
* Unique identifier in the registry for this resource.
*
@ -102,13 +104,13 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
* The time when this resource was created.
*
* <p>Map the method to XML, not the field, because if we map the field (with an adaptor class) it
* will never be omitted from the xml even if the timestamp inside creationTime is null and we
* will never be omitted from the xml even if the timestamp inside creationTime is null, and we
* return null from the adaptor (instead it gets written as an empty tag).
*
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
* resource fields.
*/
@AttributeOverrides({@AttributeOverride(name = "creationTime", column = @Column())})
@AttributeOverrides(@AttributeOverride(name = "creationTime", column = @Column))
@Index
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
@ -199,6 +201,7 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
public abstract String getForeignKey();
/** Create the VKey for the specified EPP resource. */
@Override
public abstract VKey<? extends EppResource> createVKey();
/** Override of {@link Buildable#asBuilder} so that the extra methods are visible. */

View file

@ -16,60 +16,52 @@ package google.registry.model.common;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import com.google.common.base.Splitter;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.OnLoad;
import com.googlecode.objectify.annotation.Parent;
import google.registry.model.ImmutableObject;
import google.registry.model.UnsafeSerializable;
import google.registry.model.UpdateAutoTimestamp;
import google.registry.model.annotations.InCrossTld;
import google.registry.model.common.Cursor.CursorId;
import google.registry.model.tld.Registry;
import google.registry.persistence.VKey;
import java.util.List;
import java.util.Optional;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.PostLoad;
import javax.persistence.Transient;
import org.joda.time.DateTime;
/**
* Shared entity for date cursors. This type supports both "scoped" cursors (i.e. per resource of a
* given type, such as a TLD) and global (i.e. one per environment) cursors, defined internally as
* scoped on {@link EntityGroupRoot}.
* Shared entity for date cursors.
*
* <p>This type supports both "scoped" cursors (i.e. one per TLD) and global (i.e. one per
* environment) cursors.
*/
@Entity
@javax.persistence.Entity
@IdClass(CursorId.class)
@InCrossTld
public class Cursor extends ImmutableObject implements UnsafeSerializable {
private static final long serialVersionUID = 5777891565780594961L;
/** The scope of a global cursor. A global cursor is a cursor that is not specific to one tld. */
public static final String GLOBAL = "GLOBAL";
/** The types of cursors, used as the string id field for each cursor in Datastore. */
public enum CursorType {
/** Cursor for ensuring rolling transactional isolation of BRDA staging operation. */
BRDA(Registry.class),
BRDA(true),
/** Cursor for ensuring rolling transactional isolation of RDE report operation. */
RDE_REPORT(Registry.class),
RDE_REPORT(true),
/** Cursor for ensuring rolling transactional isolation of RDE staging operation. */
RDE_STAGING(Registry.class),
RDE_STAGING(true),
/** Cursor for ensuring rolling transactional isolation of RDE upload operation. */
RDE_UPLOAD(Registry.class),
RDE_UPLOAD(true),
/**
* Cursor that tracks the last time we talked to the escrow provider's SFTP server for a given
@ -84,67 +76,47 @@ public class Cursor extends ImmutableObject implements UnsafeSerializable {
* action will fail with a status code above 300 and App Engine will keep retrying the action
* until it's ready.
*/
RDE_UPLOAD_SFTP(Registry.class),
RDE_UPLOAD_SFTP(true),
/**
* Cursor for ensuring rolling transactional isolation of recurring billing expansion. The
* value of this cursor represents the exclusive upper bound on the range of billing times
* for which Recurring billing events have been expanded (i.e. the inclusive first billing time
* for the next expansion job).
* Cursor for ensuring rolling transactional isolation of recurring billing expansion. The value
* of this cursor represents the exclusive upper bound on the range of billing times for which
* Recurring billing events have been expanded (i.e. the inclusive first billing time for the
* next expansion job).
*/
RECURRING_BILLING(EntityGroupRoot.class),
RECURRING_BILLING(false),
/**
* Cursor for {@link google.registry.export.sheet.SyncRegistrarsSheetAction}. The DateTime
* stored is the last time that registrar changes were successfully synced to the sheet. If
* there were no changes since the last time the action run, the cursor is not updated.
*/
SYNC_REGISTRAR_SHEET(EntityGroupRoot.class),
SYNC_REGISTRAR_SHEET(false),
/** Cursor for tracking monthly uploads of ICANN transaction reports. */
ICANN_UPLOAD_TX(Registry.class),
ICANN_UPLOAD_TX(true),
/** Cursor for tracking monthly uploads of ICANN activity reports. */
ICANN_UPLOAD_ACTIVITY(Registry.class),
ICANN_UPLOAD_ACTIVITY(true);
// TODO(sarahbot) Delete this cursor once all data in the database that refers to it is removed.
/** Cursor for tracking monthly uploads of MANIFEST.txt to ICANN. No longer used. */
@Deprecated
ICANN_UPLOAD_MANIFEST(EntityGroupRoot.class);
private final boolean scoped;
/** See the definition of scope on {@link #getScopeClass}. */
private final Class<? extends ImmutableObject> scope;
CursorType(Class<? extends ImmutableObject> scope) {
this.scope = scope;
CursorType(boolean scoped) {
this.scoped = scoped;
}
/**
* If there are multiple cursors for a given cursor type, a cursor must also have a scope
* defined (distinct from a parent, which is always the EntityGroupRoot key). For instance, for
* a cursor that is defined at the registry level, the scope type will be Registry.class. For a
* cursor (theoretically) defined for each EPP resource, the scope type will be
* EppResource.class. For a global cursor, i.e. one that applies per environment, this will be
* {@link EntityGroupRoot}.
*/
public Class<?> getScopeClass() {
return scope;
public boolean isScoped() {
return scoped;
}
}
@Transient @Parent Key<EntityGroupRoot> parent = getCrossTldKey();
@Transient @Id String id;
@Ignore
@Enumerated(EnumType.STRING)
@Column(nullable = false)
@javax.persistence.Id
@Id
CursorType type;
@Ignore
@Column(nullable = false)
@javax.persistence.Id
@Id
String scope;
@Column(nullable = false)
@ -154,27 +126,7 @@ public class Cursor extends ImmutableObject implements UnsafeSerializable {
@Column(nullable = false)
UpdateAutoTimestamp lastUpdateTime = UpdateAutoTimestamp.create(null);
@OnLoad
void onLoad() {
scope = getScopeFromId(id);
type = getTypeFromId(id);
}
@PostLoad
void postLoad() {
// "Generate" the ID based on the scope and type
Key<? extends ImmutableObject> scopeKey =
scope.equals(GLOBAL)
? getCrossTldKey()
: Key.create(getCrossTldKey(), Registry.class, scope);
id = generateId(type, scopeKey);
}
public static VKey<Cursor> createVKey(Key<Cursor> key) {
String id = key.getName();
return VKey.create(Cursor.class, new CursorId(getTypeFromId(id), getScopeFromId(id)), key);
}
@Override
public VKey<Cursor> createVKey() {
return createVKey(type, scope);
}
@ -183,10 +135,13 @@ public class Cursor extends ImmutableObject implements UnsafeSerializable {
return createVKey(type, GLOBAL);
}
public static VKey<Cursor> createVKey(CursorType type, String scope) {
Key<Cursor> key =
scope.equals(GLOBAL) ? createGlobalKey(type) : createKey(type, Registry.get(scope));
return VKey.create(Cursor.class, new CursorId(type, scope), key);
public static VKey<Cursor> createScopedVKey(CursorType type, Registry tld) {
return createVKey(type, tld.getTldStr());
}
private static VKey<Cursor> createVKey(CursorType type, String scope) {
checkValidCursorTypeForScope(type, scope);
return VKey.createSql(Cursor.class, new CursorId(type, scope));
}
public DateTime getLastUpdateTime() {
@ -201,76 +156,42 @@ public class Cursor extends ImmutableObject implements UnsafeSerializable {
return type;
}
/**
* Checks that the type of the scoped object (or null) matches the required type for the specified
* cursor (or null, if the cursor is a global cursor).
*/
private static void checkValidCursorTypeForScope(
CursorType cursorType, Key<? extends ImmutableObject> scope) {
/** Checks that the specified scope matches the required type for the specified cursor. */
private static void checkValidCursorTypeForScope(CursorType cursorType, String scope) {
checkNotNull(cursorType, "Cursor type cannot be null");
checkNotNull(scope, "Cursor scope cannot be null");
checkArgument(
cursorType.getScopeClass().getSimpleName().equals(scope.getKind()),
"Class required for cursor does not match scope class");
}
/** Generates a unique ID for a given scope key and cursor type. */
private static String generateId(CursorType cursorType, Key<? extends ImmutableObject> scope) {
return String.format("%s_%s", scope.getString(), cursorType.name());
}
private static String getScopeFromId(String id) {
List<String> idSplit = Splitter.on('_').splitToList(id);
// The key is always either the cross-tld-key or the key of a TLD (whose parent is the
// cross-tld-key).
Key<?> scopeKey = Key.valueOf(idSplit.get(0));
return scopeKey.getParent() == null ? GLOBAL : scopeKey.getName();
}
private static CursorType getTypeFromId(String id) {
List<String> idSplit = Splitter.on('_').splitToList(id);
// The cursor type is the second part of the ID string
return CursorType.valueOf(String.join("_", idSplit.subList(1, idSplit.size())));
}
/** Creates a unique key for a given scope and cursor type. */
public static Key<Cursor> createKey(CursorType cursorType, ImmutableObject scope) {
Key<? extends ImmutableObject> scopeKey = Key.create(scope);
checkValidCursorTypeForScope(cursorType, scopeKey);
return Key.create(getCrossTldKey(), Cursor.class, generateId(cursorType, scopeKey));
}
/** Creates a unique key for a given global cursor type. */
public static Key<Cursor> createGlobalKey(CursorType cursorType) {
checkArgument(
cursorType.getScopeClass().equals(EntityGroupRoot.class),
"Cursor type is not a global cursor.");
return Key.create(getCrossTldKey(), Cursor.class, generateId(cursorType, getCrossTldKey()));
cursorType.isScoped() != scope.equals(GLOBAL),
"Scope %s does not match cursor type %s",
scope,
cursorType);
}
/** Creates a new global cursor instance. */
public static Cursor createGlobal(CursorType cursorType, DateTime cursorTime) {
return create(cursorType, cursorTime, getCrossTldKey());
return create(cursorType, cursorTime, GLOBAL);
}
/** Creates a new cursor instance with a given {@link Key} scope. */
private static Cursor create(
CursorType cursorType, DateTime cursorTime, Key<? extends ImmutableObject> scope) {
/** Creates a new cursor instance with a given {@link Registry} scope. */
public static Cursor createScoped(CursorType cursorType, DateTime cursorTime, Registry scope) {
checkNotNull(scope, "Cursor scope cannot be null");
return create(cursorType, cursorTime, scope.getTldStr());
}
/**
* Creates a new cursor instance with a given TLD scope, or global if the scope is {@link
* #GLOBAL}.
*/
private static Cursor create(CursorType cursorType, DateTime cursorTime, String scope) {
checkNotNull(cursorTime, "Cursor time cannot be null");
checkValidCursorTypeForScope(cursorType, scope);
Cursor instance = new Cursor();
instance.cursorTime = checkNotNull(cursorTime, "Cursor time cannot be null");
checkNotNull(scope, "Cursor scope cannot be null");
checkNotNull(cursorType, "Cursor type cannot be null");
checkValidCursorTypeForScope(cursorType, scope);
instance.id = generateId(cursorType, scope);
instance.type = cursorType;
instance.scope = scope.equals(getCrossTldKey()) ? GLOBAL : scope.getName();
instance.scope = scope;
return instance;
}
/** Creates a new cursor instance with a given {@link ImmutableObject} scope. */
public static Cursor create(CursorType cursorType, DateTime cursorTime, ImmutableObject scope) {
checkNotNull(scope, "Cursor scope cannot be null");
return create(cursorType, cursorTime, Key.create(scope));
}
/**
* Returns the current time for a given cursor, or {@code START_OF_TIME} if the cursor is null.
*/
@ -284,9 +205,13 @@ public class Cursor extends ImmutableObject implements UnsafeSerializable {
public static class CursorId extends ImmutableObject implements UnsafeSerializable {
private static final long serialVersionUID = -6749584762913095437L;
public CursorType type;
public String scope;
// Hibernate requires a no-arg constructor.
@SuppressWarnings("unused")
private CursorId() {}
public CursorId(CursorType type, String scope) {

View file

@ -101,6 +101,7 @@ public class ContactHistory extends HistoryEntry implements UnsafeSerializable {
/** Creates a {@link VKey} instance for this entity. */
@SuppressWarnings("unchecked")
@Override
public VKey<ContactHistory> createVKey() {
return (VKey<ContactHistory>) createVKey(Key.create(this));
}

View file

@ -252,6 +252,7 @@ public class DomainHistory extends HistoryEntry {
/** Creates a {@link VKey} instance for this entity. */
@SuppressWarnings("unchecked")
@Override
public VKey<DomainHistory> createVKey() {
return (VKey<DomainHistory>) createVKey(Key.create(this));
}

View file

@ -248,6 +248,7 @@ public class AllocationToken extends BackupGroupRoot implements Buildable {
return renewalPriceBehavior;
}
@Override
public VKey<AllocationToken> createVKey() {
return VKey.create(AllocationToken.class, getToken(), Key.create(this));
}

View file

@ -102,6 +102,7 @@ public class HostHistory extends HistoryEntry implements UnsafeSerializable {
/** Creates a {@link VKey} instance for this entity. */
@SuppressWarnings("unchecked")
@Override
public VKey<HostHistory> createVKey() {
return (VKey<HostHistory>) createVKey(Key.create(this));
}

View file

@ -730,6 +730,7 @@ public class Registrar extends ImmutableObject
}
/** Creates a {@link VKey} for this instance. */
@Override
public VKey<Registrar> createVKey() {
return createVKey(Key.create(this));
}

View file

@ -317,6 +317,7 @@ public class RegistrarPoc extends ImmutableObject implements Jsonifiable, Unsafe
.build();
}
@Override
public VKey<RegistrarPoc> createVKey() {
return VKey.createSql(RegistrarPoc.class, new RegistrarPocId(emailAddress, registrarId));
}

View file

@ -96,6 +96,7 @@ public abstract class EppHistoryVKey<K, E extends EppResource> extends Immutable
}
/** Creates a {@link VKey} from this instance. */
@Override
public VKey<K> createVKey() {
Class<K> vKeyType = new TypeInstantiator<K>(getClass()) {}.getExactType();
return VKey.create(vKeyType, createSqlKey(), createOfyKey());

View file

@ -18,7 +18,6 @@ import static google.registry.model.common.Cursor.CursorType.BRDA;
import static google.registry.model.common.Cursor.getCursorTimeOrStartOfTime;
import static google.registry.model.rde.RdeMode.THIN;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
@ -31,6 +30,7 @@ import google.registry.keyring.api.KeyModule.Key;
import google.registry.model.common.Cursor;
import google.registry.model.rde.RdeNamingUtils;
import google.registry.model.rde.RdeRevision;
import google.registry.model.tld.Registry;
import google.registry.request.Action;
import google.registry.request.HttpException.NoContentException;
import google.registry.request.Parameter;
@ -97,7 +97,8 @@ public final class BrdaCopyAction implements Runnable {
// TODO(b/217772483): consider guarding this action with a lock and check if there is work.
// Not urgent since file writes on GCS are atomic.
Optional<Cursor> cursor =
transactIfJpaTm(() -> tm().loadByKeyIfPresent(Cursor.createVKey(BRDA, tld)));
tm().transact(
() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(BRDA, Registry.get(tld))));
DateTime brdaCursorTime = getCursorTimeOrStartOfTime(cursor);
if (isBeforeOrAt(brdaCursorTime, watermark)) {
throw new NoContentException(

View file

@ -92,9 +92,7 @@ class EscrowTaskRunner {
DateTime startOfToday = clock.nowUtc().withTimeAtStartOfDay();
DateTime nextRequiredRun =
transactIfJpaTm(
() ->
tm().loadByKeyIfPresent(
Cursor.createVKey(cursorType, registry.getTldStr())))
() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(cursorType, registry)))
.map(Cursor::getCursorTime)
.orElse(startOfToday);
if (nextRequiredRun.isAfter(startOfToday)) {
@ -104,7 +102,7 @@ class EscrowTaskRunner {
task.runWithLock(nextRequiredRun);
DateTime nextRun = nextRequiredRun.plus(interval);
logger.atInfo().log("Rolling cursor forward to %s.", nextRun);
tm().transact(() -> tm().put(Cursor.create(cursorType, nextRun, registry)));
tm().transact(() -> tm().put(Cursor.createScoped(cursorType, nextRun, registry)));
return null;
};
String lockName = String.format("EscrowTaskRunner %s", task.getClass().getSimpleName());

View file

@ -92,7 +92,7 @@ public final class PendingDepositChecker {
// Avoid creating a transaction unless absolutely necessary.
Optional<Cursor> maybeCursor =
transactIfJpaTm(
() -> tm().loadByKeyIfPresent(Cursor.createVKey(cursorType, registry.getTldStr())));
() -> tm().loadByKeyIfPresent(Cursor.createScopedVKey(cursorType, registry)));
DateTime cursorValue = maybeCursor.map(Cursor::getCursorTime).orElse(startingPoint);
if (isBeforeOrAt(cursorValue, now)) {
DateTime watermark =
@ -112,11 +112,11 @@ public final class PendingDepositChecker {
return tm().transact(
() -> {
Optional<Cursor> maybeCursor =
tm().loadByKeyIfPresent(Cursor.createVKey(cursorType, registry.getTldStr()));
tm().loadByKeyIfPresent(Cursor.createScopedVKey(cursorType, registry));
if (maybeCursor.isPresent()) {
return maybeCursor.get().getCursorTime();
}
tm().put(Cursor.create(cursorType, initialValue, registry));
tm().put(Cursor.createScoped(cursorType, initialValue, registry));
return initialValue;
});
}

View file

@ -19,7 +19,6 @@ import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
import static google.registry.model.common.Cursor.getCursorTimeOrStartOfTime;
import static google.registry.model.rde.RdeMode.FULL;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.isBeforeOrAt;
@ -83,8 +82,10 @@ public final class RdeReportAction implements Runnable, EscrowTask {
@Override
public void runWithLock(DateTime watermark) throws Exception {
Optional<Cursor> cursor =
transactIfJpaTm(
() -> tm().loadByKeyIfPresent(Cursor.createVKey(CursorType.RDE_UPLOAD, tld)));
tm().transact(
() ->
tm().loadByKeyIfPresent(
Cursor.createScopedVKey(CursorType.RDE_UPLOAD, Registry.get(tld))));
DateTime cursorTime = getCursorTimeOrStartOfTime(cursor);
if (isBeforeOrAt(cursorTime, watermark)) {
throw new NoContentException(

View file

@ -22,7 +22,6 @@ import static google.registry.model.common.Cursor.CursorType.RDE_UPLOAD_SFTP;
import static google.registry.model.common.Cursor.getCursorTimeOrStartOfTime;
import static google.registry.model.rde.RdeMode.FULL;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.persistence.transaction.TransactionManagerUtil.transactIfJpaTm;
import static google.registry.rde.RdeModule.RDE_REPORT_QUEUE;
import static google.registry.request.Action.Method.POST;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
@ -163,7 +162,10 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
}
logger.atInfo().log("Verifying readiness to upload the RDE deposit.");
Optional<Cursor> cursor =
transactIfJpaTm(() -> tm().loadByKeyIfPresent(Cursor.createVKey(RDE_STAGING, tld)));
tm().transact(
() ->
tm().loadByKeyIfPresent(
Cursor.createScopedVKey(RDE_STAGING, Registry.get(tld))));
DateTime stagingCursorTime = getCursorTimeOrStartOfTime(cursor);
if (isBeforeOrAt(stagingCursorTime, watermark)) {
throw new NoContentException(
@ -173,7 +175,10 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
tld, watermark, stagingCursorTime));
}
DateTime sftpCursorTime =
transactIfJpaTm(() -> tm().loadByKeyIfPresent(Cursor.createVKey(RDE_UPLOAD_SFTP, tld)))
tm().transact(
() ->
tm().loadByKeyIfPresent(
Cursor.createScopedVKey(RDE_UPLOAD_SFTP, Registry.get(tld))))
.map(Cursor::getCursorTime)
.orElse(START_OF_TIME);
Duration timeSinceLastSftp = new Duration(sftpCursorTime, clock.nowUtc());
@ -211,7 +216,7 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
tm().transact(
() ->
tm().put(
Cursor.create(
Cursor.createScoped(
RDE_UPLOAD_SFTP, tm().getTransactionTime(), Registry.get(tld))));
response.setContentType(PLAIN_TEXT_UTF_8);
response.setPayload(String.format("OK %s %s\n", tld, watermark));

View file

@ -166,7 +166,7 @@ public final class IcannReportingUploadAction implements Runnable {
// Set cursor to first day of next month if the upload succeeded
if (success) {
Cursor newCursor =
Cursor.create(
Cursor.createScoped(
cursorType,
cursorTime.withTimeAtStartOfDay().withDayOfMonth(1).plusMonths(1),
Registry.get(tldStr));
@ -227,7 +227,7 @@ public final class IcannReportingUploadAction implements Runnable {
private ImmutableMap<VKey<? extends Cursor>, Registry> loadKeyMap(
ImmutableSet<Registry> registries, CursorType type) {
return Maps.uniqueIndex(registries, r -> Cursor.createVKey(type, r.getTldStr()));
return Maps.uniqueIndex(registries, r -> Cursor.createScopedVKey(type, r));
}
/**
@ -247,7 +247,7 @@ public final class IcannReportingUploadAction implements Runnable {
Cursor cursor =
cursorMap.getOrDefault(
key,
Cursor.create(
Cursor.createScoped(
type,
clock.nowUtc().withDayOfMonth(1).withTimeAtStartOfDay().plusMonths(1),
registry));

View file

@ -57,7 +57,7 @@ final class ListCursorsCommand implements CommandWithRemoteApi {
.map(Registry::get)
.filter(r -> r.getTldType() == filterTldType)
.filter(r -> !filterEscrowEnabled || r.getEscrowEnabled())
.collect(toImmutableMap(r -> r, r -> Cursor.createVKey(cursorType, r.getTldStr())));
.collect(toImmutableMap(r -> r, r -> Cursor.createScopedVKey(cursorType, r)));
ImmutableMap<VKey<? extends Cursor>, Cursor> cursors =
transactIfJpaTm(() -> tm().loadByKeysIfPresent(registries.values()));
if (!registries.isEmpty()) {

View file

@ -54,7 +54,7 @@ final class UpdateCursorsCommand extends ConfirmingCommand implements CommandWit
} else {
for (String tld : tlds) {
Registry registry = Registry.get(tld);
result.add(Cursor.create(cursorType, newTimestamp, registry));
result.add(Cursor.createScoped(cursorType, newTimestamp, registry));
}
}
cursorsToUpdate = result.build();

View file

@ -30,9 +30,9 @@ import org.testcontainers.containers.PostgreSQLContainer;
/**
* Generates a schema for JPA annotated classes using Hibernate.
*
* <p>Note that this isn't complete yet, as all of the persistent classes have not yet been
* converted. After converting a class, a call to "addAnnotatedClass()" for the new class must be
* added to the code below.
* <p>Note that this isn't complete yet, as all the persistent classes have not yet been converted.
* After converting a class, a call to "addAnnotatedClass()" for the new class must be added to the
* code below.
*/
@Parameters(separators = " =", commandDescription = "Generate PostgreSQL schema.")
public class GenerateSqlSchemaCommand implements Command {
@ -49,7 +49,7 @@ public class GenerateSqlSchemaCommand implements Command {
@VisibleForTesting
public static final int POSTGRESQL_PORT = 5432;
private PostgreSQLContainer postgresContainer = null;
private PostgreSQLContainer<?> postgresContainer = null;
@Parameter(
names = {"-o", "--out_file"},
@ -85,12 +85,12 @@ public class GenerateSqlSchemaCommand implements Command {
// Start the container and store the address information.
postgresContainer =
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag())
new PostgreSQLContainer<>(NomulusPostgreSql.getDockerTag())
.withDatabaseName(DB_NAME)
.withUsername(DB_USERNAME)
.withPassword(DB_PASSWORD);
postgresContainer.start();
databaseHost = postgresContainer.getContainerIpAddress();
databaseHost = postgresContainer.getHost();
databasePort = postgresContainer.getMappedPort(POSTGRESQL_PORT);
} else if (databaseHost == null) {
System.err.println(

View file

@ -34,7 +34,7 @@ public abstract class PostgresqlCommand implements Command {
@VisibleForTesting public static final int POSTGRESQL_PORT = 5432;
protected PostgreSQLContainer postgresContainer = null;
protected PostgreSQLContainer<?> postgresContainer = null;
@Parameter(
names = {"-s", "--start_postgresql"},
@ -68,7 +68,7 @@ public abstract class PostgresqlCommand implements Command {
// Start the container and store the address information.
postgresContainer =
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag())
new PostgreSQLContainer<>(NomulusPostgreSql.getDockerTag())
.withDatabaseName(DB_NAME)
.withUsername(DB_USERNAME)
.withPassword(DB_PASSWORD);
@ -79,7 +79,7 @@ public abstract class PostgresqlCommand implements Command {
return false;
}
postgresContainer.start();
databaseHost = postgresContainer.getContainerIpAddress();
databaseHost = postgresContainer.getHost();
databasePort = postgresContainer.getMappedPort(POSTGRESQL_PORT);
} else if (databaseHost == null) {
System.err.println(

View file

@ -257,8 +257,8 @@ public class RdePipelineTest {
tm().transact(
() -> {
tm().put(Cursor.create(CursorType.BRDA, now, Registry.get("soy")));
tm().put(Cursor.create(RDE_STAGING, now, Registry.get("soy")));
tm().put(Cursor.createScoped(CursorType.BRDA, now, Registry.get("soy")));
tm().put(Cursor.createScoped(RDE_STAGING, now, Registry.get("soy")));
RdeRevision.saveRevision("soy", now, THIN, 0);
RdeRevision.saveRevision("soy", now, FULL, 0);
});
@ -567,7 +567,9 @@ public class RdePipelineTest {
}
private static DateTime loadCursorTime(CursorType type) {
return tm().transact(() -> tm().loadByKey(Cursor.createVKey(type, "soy")).getCursorTime());
return tm().transact(
() ->
tm().loadByKey(Cursor.createScopedVKey(type, Registry.get("soy"))).getCursorTime());
}
private static Function<DepositFragment, String> getXmlElement(String pattern) {

View file

@ -61,7 +61,6 @@ public class ClassPathManagerTest {
assertThat(ClassPathManager.getClass("Modification")).isEqualTo(Modification.class);
assertThat(ClassPathManager.getClass("AllocationToken")).isEqualTo(AllocationToken.class);
assertThat(ClassPathManager.getClass("OneTime")).isEqualTo(OneTime.class);
assertThat(ClassPathManager.getClass("Cursor")).isEqualTo(Cursor.class);
assertThat(ClassPathManager.getClass("RdeRevision")).isEqualTo(RdeRevision.class);
assertThat(ClassPathManager.getClass("HostResource")).isEqualTo(HostResource.class);
assertThat(ClassPathManager.getClass("Recurring")).isEqualTo(Recurring.class);
@ -120,7 +119,6 @@ public class ClassPathManagerTest {
assertThat(ClassPathManager.getClassName(Modification.class)).isEqualTo("Modification");
assertThat(ClassPathManager.getClassName(AllocationToken.class)).isEqualTo("AllocationToken");
assertThat(ClassPathManager.getClassName(OneTime.class)).isEqualTo("OneTime");
assertThat(ClassPathManager.getClassName(Cursor.class)).isEqualTo("Cursor");
assertThat(ClassPathManager.getClassName(RdeRevision.class)).isEqualTo("RdeRevision");
assertThat(ClassPathManager.getClassName(HostResource.class)).isEqualTo("HostResource");
assertThat(ClassPathManager.getClassName(Recurring.class)).isEqualTo("Recurring");

View file

@ -19,24 +19,18 @@ import static google.registry.model.common.Cursor.CursorType.BRDA;
import static google.registry.model.common.Cursor.CursorType.RDE_UPLOAD;
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
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.persistActiveDomain;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
import static org.junit.jupiter.api.Assertions.assertThrows;
import google.registry.model.EntityTestCase;
import google.registry.model.domain.DomainBase;
import google.registry.model.tld.Registry;
import google.registry.testing.DualDatabaseTest;
import google.registry.testing.TestOfyAndSql;
import google.registry.testing.TestSqlOnly;
import google.registry.util.SerializeUtils;
import org.joda.time.DateTime;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link Cursor}. */
@DualDatabaseTest
public class CursorTest extends EntityTestCase {
public CursorTest() {
@ -48,7 +42,7 @@ public class CursorTest extends EntityTestCase {
fakeClock.setTo(DateTime.parse("2010-10-17TZ"));
}
@TestSqlOnly
@Test
void testSerializable() {
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
tm().transact(() -> tm().put(Cursor.createGlobal(RECURRING_BILLING, time)));
@ -57,22 +51,23 @@ public class CursorTest extends EntityTestCase {
assertThat(SerializeUtils.serializeDeserialize(persisted)).isEqualTo(persisted);
}
@TestOfyAndSql
@Test
void testSuccess_persistScopedCursor() {
createTld("tld");
Registry tld = createTld("tld");
this.fakeClock.advanceOneMilli();
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
Cursor cursor = Cursor.create(RDE_UPLOAD, time, Registry.get("tld"));
Cursor cursor = Cursor.createScoped(RDE_UPLOAD, time, tld);
tm().transact(() -> tm().put(cursor));
transactIfJpaTm(
() -> {
assertThat(tm().loadByKeyIfPresent(Cursor.createVKey(BRDA, "tld")).isPresent()).isFalse();
assertThat(tm().loadByKey(Cursor.createVKey(RDE_UPLOAD, "tld")).getCursorTime())
.isEqualTo(time);
});
tm().transact(
() -> {
assertThat(tm().loadByKeyIfPresent(Cursor.createScopedVKey(BRDA, tld)).isPresent())
.isFalse();
assertThat(tm().loadByKey(Cursor.createScopedVKey(RDE_UPLOAD, tld)).getCursorTime())
.isEqualTo(time);
});
}
@TestOfyAndSql
@Test
void testSuccess_persistGlobalCursor() {
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
Cursor cursor = Cursor.createGlobal(RECURRING_BILLING, time);
@ -81,86 +76,47 @@ public class CursorTest extends EntityTestCase {
.isEqualTo(time);
}
@TestOfyAndSql
void testIndexing() throws Exception {
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
tm().transact(() -> tm().put(Cursor.createGlobal(RECURRING_BILLING, time)));
Cursor cursor = tm().transact(() -> tm().loadByKey(Cursor.createGlobalVKey(RECURRING_BILLING)));
verifyDatastoreIndexing(cursor);
@Test
void testFailure_VKeyWrongScope() {
Registry tld = createTld("tld");
assertThrows(
IllegalArgumentException.class,
() -> Cursor.createGlobalVKey(RDE_UPLOAD),
"Scope GLOBAL does not match cursor type RDE_UPLOAD");
assertThrows(
IllegalArgumentException.class,
() -> Cursor.createScopedVKey(RECURRING_BILLING, tld),
"Scope tld does not match cursor type RECURRING_BILLING");
assertThrows(
NullPointerException.class, () -> Cursor.createScopedVKey(RECURRING_BILLING, null));
}
@TestOfyAndSql
void testFailure_invalidScopeOnCreate() {
createTld("tld");
this.fakeClock.advanceOneMilli();
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
final DomainBase domain = persistActiveDomain("notaregistry.tld");
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> Cursor.create(RDE_UPLOAD, time, domain),
domain.getTld());
assertThat(thrown)
.hasMessageThat()
.contains("Class required for cursor does not match scope class");
}
@TestOfyAndSql
void testFailure_invalidScopeOnKeyCreate() {
createTld("tld");
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> Cursor.createKey(RDE_UPLOAD, persistActiveDomain("notaregistry.tld")));
assertThat(thrown)
.hasMessageThat()
.contains("Class required for cursor does not match scope class");
}
@TestOfyAndSql
void testFailure_createGlobalKeyForScopedCursorType() {
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> Cursor.createGlobalKey(RDE_UPLOAD));
assertThat(thrown).hasMessageThat().contains("Cursor type is not a global cursor");
}
@TestOfyAndSql
void testFailure_invalidScopeOnGlobalKeyCreate() {
createTld("tld");
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> Cursor.createKey(RECURRING_BILLING, persistActiveDomain("notaregistry.tld")));
assertThat(thrown)
.hasMessageThat()
.contains("Class required for cursor does not match scope class");
}
@TestOfyAndSql
@Test
void testFailure_nullScope() {
NullPointerException thrown =
assertThrows(
NullPointerException.class,
() -> Cursor.create(RECURRING_BILLING, START_OF_TIME, null));
() -> Cursor.createScoped(RECURRING_BILLING, START_OF_TIME, null));
assertThat(thrown).hasMessageThat().contains("Cursor scope cannot be null");
}
@TestOfyAndSql
@Test
void testFailure_nullCursorType() {
createTld("tld");
NullPointerException thrown =
assertThrows(
NullPointerException.class,
() -> Cursor.create(null, START_OF_TIME, Registry.get("tld")));
() -> Cursor.createScoped(null, START_OF_TIME, Registry.get("tld")));
assertThat(thrown).hasMessageThat().contains("Cursor type cannot be null");
}
@TestOfyAndSql
@Test
void testFailure_nullTime() {
createTld("tld");
NullPointerException thrown =
assertThrows(
NullPointerException.class, () -> Cursor.create(RDE_UPLOAD, null, Registry.get("tld")));
NullPointerException.class,
() -> Cursor.createScoped(RDE_UPLOAD, null, Registry.get("tld")));
assertThat(thrown).hasMessageThat().contains("Cursor time cannot be null");
}
}

View file

@ -106,6 +106,7 @@ class BillingVKeyTest {
return billingRecurrenceVKey.createVKey();
}
@Override
public VKey<BillingVKeyTestEntity> createVKey() {
return VKey.createSql(BillingVKeyTestEntity.class, id);
}

View file

@ -96,6 +96,7 @@ class DomainHistoryVKeyTest {
this.domainHistoryVKey = domainHistoryVKey;
}
@Override
public VKey<TestEntity> createVKey() {
return VKey.createSql(TestEntity.class, id);
}

View file

@ -125,13 +125,13 @@ public class BrdaCopyActionTest {
() -> {
RdeRevision.saveRevision("lol", DateTime.parse("2010-10-17TZ"), RdeMode.THIN, 0);
});
persistResource(Cursor.create(BRDA, action.watermark.plusDays(1), Registry.get("lol")));
persistResource(Cursor.createScoped(BRDA, action.watermark.plusDays(1), Registry.get("lol")));
}
@ParameterizedTest
@ValueSource(strings = {"", "job-name/"})
void testRun_stagingNotFinished_throws204(String prefix) throws Exception {
persistResource(Cursor.create(BRDA, action.watermark, Registry.get("lol")));
persistResource(Cursor.createScoped(BRDA, action.watermark, Registry.get("lol")));
NoContentException thrown = assertThrows(NoContentException.class, () -> runAction(prefix));
assertThat(thrown)
.hasMessageThat()

View file

@ -77,12 +77,12 @@ public class EscrowTaskRunnerTest {
void testRun_cursorIsToday_advancesCursorToTomorrow() throws Exception {
clock.setTo(DateTime.parse("2006-06-06T00:30:00Z"));
persistResource(
Cursor.create(CursorType.RDE_STAGING, DateTime.parse("2006-06-06TZ"), registry));
Cursor.createScoped(CursorType.RDE_STAGING, DateTime.parse("2006-06-06TZ"), registry));
runner.lockRunAndRollForward(
task, registry, standardSeconds(30), CursorType.RDE_STAGING, standardDays(1));
verify(task).runWithLock(DateTime.parse("2006-06-06TZ"));
tm().clearSessionCache();
Cursor cursor = loadByKey(Cursor.createVKey(CursorType.RDE_STAGING, registry.getTldStr()));
Cursor cursor = loadByKey(Cursor.createScopedVKey(CursorType.RDE_STAGING, registry));
assertThat(cursor.getCursorTime()).isEqualTo(DateTime.parse("2006-06-07TZ"));
}
@ -92,7 +92,7 @@ public class EscrowTaskRunnerTest {
runner.lockRunAndRollForward(
task, registry, standardSeconds(30), CursorType.RDE_STAGING, standardDays(1));
verify(task).runWithLock(DateTime.parse("2006-06-06TZ"));
Cursor cursor = loadByKey(Cursor.createVKey(CursorType.RDE_STAGING, "lol"));
Cursor cursor = loadByKey(Cursor.createScopedVKey(CursorType.RDE_STAGING, registry));
assertThat(cursor.getCursorTime()).isEqualTo(DateTime.parse("2006-06-07TZ"));
}
@ -100,7 +100,7 @@ public class EscrowTaskRunnerTest {
void testRun_cursorInTheFuture_doesNothing() {
clock.setTo(DateTime.parse("2006-06-06T00:30:00Z"));
persistResource(
Cursor.create(CursorType.RDE_STAGING, DateTime.parse("2006-06-07TZ"), registry));
Cursor.createScoped(CursorType.RDE_STAGING, DateTime.parse("2006-06-07TZ"), registry));
NoContentException thrown =
assertThrows(
NoContentException.class,
@ -115,7 +115,7 @@ public class EscrowTaskRunnerTest {
String lockName = "EscrowTaskRunner " + task.getClass().getSimpleName();
clock.setTo(DateTime.parse("2006-06-06T00:30:00Z"));
persistResource(
Cursor.create(CursorType.RDE_STAGING, DateTime.parse("2006-06-06TZ"), registry));
Cursor.createScoped(CursorType.RDE_STAGING, DateTime.parse("2006-06-06TZ"), registry));
runner.lockHandler = new FakeLockHandler(false);
ServiceUnavailableException thrown =
assertThrows(

View file

@ -101,10 +101,9 @@ public class PendingDepositCheckerTest {
createTldWithEscrowEnabled("lol");
clock.advanceOneMilli();
Registry registry = Registry.get("lol");
Truth8.assertThat(loadByKeyIfPresent(Cursor.createVKey(RDE_STAGING, registry.getTldStr())))
.isEmpty();
Truth8.assertThat(loadByKeyIfPresent(Cursor.createScopedVKey(RDE_STAGING, registry))).isEmpty();
checker.getTldsAndWatermarksPendingDepositForRdeAndBrda();
assertThat(loadByKey(Cursor.createVKey(RDE_STAGING, registry.getTldStr())).getCursorTime())
assertThat(loadByKey(Cursor.createScopedVKey(RDE_STAGING, registry)).getCursorTime())
.isEqualTo(DateTime.parse("2000-01-01TZ"));
}
@ -117,7 +116,7 @@ public class PendingDepositCheckerTest {
setCursor(Registry.get("lol"), RDE_STAGING, yesterday);
clock.advanceOneMilli();
checker.getTldsAndWatermarksPendingDepositForRdeAndBrda();
Cursor cursor = loadByKey(Cursor.createVKey(RDE_STAGING, "lol"));
Cursor cursor = loadByKey(Cursor.createScopedVKey(RDE_STAGING, Registry.get("lol")));
assertThat(cursor.getCursorTime()).isEqualTo(yesterday);
}
@ -129,9 +128,9 @@ public class PendingDepositCheckerTest {
clock.advanceOneMilli();
setCursor(registry, RDE_STAGING, DateTime.parse("2000-01-02TZ")); // assume rde is already done
clock.advanceOneMilli();
Truth8.assertThat(loadByKeyIfPresent(Cursor.createVKey(BRDA, registry.getTldStr()))).isEmpty();
Truth8.assertThat(loadByKeyIfPresent(Cursor.createScopedVKey(BRDA, registry))).isEmpty();
assertThat(checker.getTldsAndWatermarksPendingDepositForRdeAndBrda()).isEmpty();
Truth8.assertThat(loadByKeyIfPresent(Cursor.createVKey(BRDA, registry.getTldStr()))).isEmpty();
Truth8.assertThat(loadByKeyIfPresent(Cursor.createScopedVKey(BRDA, registry))).isEmpty();
}
@TestOfyAndSql
@ -171,7 +170,7 @@ public class PendingDepositCheckerTest {
private static void setCursor(
final Registry registry, final CursorType cursorType, final DateTime value) {
tm().transact(() -> tm().put(Cursor.create(cursorType, value, registry)));
tm().transact(() -> tm().put(Cursor.createScoped(cursorType, value, registry)));
}
private static void createTldWithEscrowEnabled(final String tld) {

View file

@ -97,6 +97,7 @@ public class RdeReportActionTest {
private final GcsUtils gcsUtils = new GcsUtils(LocalStorageHelper.getOptions());
private final BlobId reportFile =
BlobId.of("tub", "test_2006-06-06_full_S1_R0-report.xml.ghostryde");
private Registry registry;
private RdeReportAction createAction() {
RdeReporter reporter = new RdeReporter();
@ -120,11 +121,9 @@ public class RdeReportActionTest {
@BeforeEach
void beforeEach() throws Exception {
createTld("test");
persistResource(
Cursor.create(RDE_REPORT, DateTime.parse("2006-06-06TZ"), Registry.get("test")));
persistResource(
Cursor.create(RDE_UPLOAD, DateTime.parse("2006-06-07TZ"), Registry.get("test")));
registry = createTld("test");
persistResource(Cursor.createScoped(RDE_REPORT, DateTime.parse("2006-06-06TZ"), registry));
persistResource(Cursor.createScoped(RDE_UPLOAD, DateTime.parse("2006-06-07TZ"), registry));
gcsUtils.createFromBytes(reportFile, Ghostryde.encode(REPORT_XML.read(), encryptKey));
tm().transact(() -> RdeRevision.saveRevision("test", DateTime.parse("2006-06-06TZ"), FULL, 0));
}
@ -211,7 +210,7 @@ public class RdeReportActionTest {
}
void testRunWithLock_nonexistentCursor_throws204() {
tm().transact(() -> tm().delete(Cursor.createVKey(RDE_UPLOAD, "test")));
tm().transact(() -> tm().delete(Cursor.createScopedVKey(RDE_UPLOAD, Registry.get("test"))));
NoContentException thrown =
assertThrows(
NoContentException.class, () -> createAction().runWithLock(loadRdeReportCursor()));
@ -225,7 +224,7 @@ public class RdeReportActionTest {
@TestOfyAndSql
void testRunWithLock_uploadNotFinished_throws204() {
persistResource(
Cursor.create(RDE_UPLOAD, DateTime.parse("2006-06-06TZ"), Registry.get("test")));
Cursor.createScoped(RDE_UPLOAD, DateTime.parse("2006-06-06TZ"), Registry.get("test")));
NoContentException thrown =
assertThrows(
NoContentException.class, () -> createAction().runWithLock(loadRdeReportCursor()));
@ -270,7 +269,7 @@ public class RdeReportActionTest {
}
private DateTime loadRdeReportCursor() {
return loadByKey(Cursor.createVKey(RDE_REPORT, "test")).getCursorTime();
return loadByKey(Cursor.createScopedVKey(RDE_REPORT, registry)).getCursorTime();
}
private static ImmutableMap<String, String> mapifyHeaders(Iterable<HTTPHeader> headers) {

View file

@ -43,7 +43,7 @@ import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Unit tests for {@link RdeStagingAction} in Cloud SQL. */
/** Unit tests for {@link RdeStagingAction}. */
@DualDatabaseTest
public class RdeStagingActionTest extends BeamActionTestBase {

View file

@ -267,7 +267,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
RdeUploadAction action = createAction(uploadUrl);
action.lazyJsch = Lazies.of(createThrowingJSchSpy(action.lazyJsch.get(), 2));
action.runWithLock(uploadCursor);
@ -286,7 +286,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
RdeUploadAction action = createAction(uploadUrl);
action.lazyJsch = Lazies.of(createThrowingJSchSpy(action.lazyJsch.get(), 3));
RuntimeException thrown =
@ -300,7 +300,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
gcsUtils.delete(GHOSTRYDE_FILE_WITH_PREFIX);
gcsUtils.delete(LENGTH_FILE_WITH_PREFIX);
gcsUtils.delete(REPORT_FILE_WITH_PREFIX);
@ -320,7 +320,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
gcsUtils.delete(GHOSTRYDE_FILE_WITH_PREFIX);
gcsUtils.delete(LENGTH_FILE_WITH_PREFIX);
gcsUtils.delete(REPORT_FILE_WITH_PREFIX);
@ -345,7 +345,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
RdeUploadAction action = createAction(uploadUrl);
action.prefix = Optional.of(JOB_PREFIX + "-job-name/");
gcsUtils.delete(GHOSTRYDE_FILE);
@ -374,7 +374,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
RdeUploadAction action = createAction(uploadUrl);
gcsUtils.delete(GHOSTRYDE_FILE);
gcsUtils.delete(LENGTH_FILE);
@ -415,7 +415,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistSimpleResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistSimpleResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
BlobId ghostrydeR1FileWithPrefix =
BlobId.of("bucket", JOB_PREFIX + "-job-name/tld_2010-10-17_full_S1_R1.xml.ghostryde");
BlobId lengthR1FileWithPrefix =
@ -446,7 +446,7 @@ public class RdeUploadActionTest {
URI uploadUrl = URI.create(String.format("sftp://user:password@localhost:%d/", port));
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
createAction(uploadUrl).runWithLock(uploadCursor);
// Only verify signature for SFTP versions, since we check elsewhere that the GCS files are
// identical to the ones sent over SFTP.
@ -484,7 +484,7 @@ public class RdeUploadActionTest {
URI url = URI.create("sftp://user:password@localhost:32323/");
DateTime stagingCursor = DateTime.parse("2010-10-17TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
NoContentException thrown =
assertThrows(NoContentException.class, () -> createAction(url).runWithLock(uploadCursor));
assertThat(thrown)
@ -501,8 +501,8 @@ public class RdeUploadActionTest {
DateTime stagingCursor = DateTime.parse("2010-10-18TZ");
DateTime uploadCursor = DateTime.parse("2010-10-17TZ");
DateTime sftpCursor = uploadCursor.minusMinutes(97); // Within the 2 hour cooldown period.
persistResource(Cursor.create(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.create(RDE_UPLOAD_SFTP, sftpCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_STAGING, stagingCursor, Registry.get("tld")));
persistResource(Cursor.createScoped(RDE_UPLOAD_SFTP, sftpCursor, Registry.get("tld")));
NoContentException thrown =
assertThrows(NoContentException.class, () -> action.runWithLock(uploadCursor));
assertThat(thrown)

View file

@ -105,16 +105,16 @@ class IcannReportingUploadActionTest {
when(mockReporter.send(PAYLOAD_SUCCESS, "foo-activity-200606.csv")).thenReturn(true);
clock.setTo(DateTime.parse("2006-07-05T00:30:00Z"));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_ACTIVITY, DateTime.parse("2006-07-01TZ"), Registry.get("tld")));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_TX, DateTime.parse("2006-07-01TZ"), Registry.get("tld")));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_ACTIVITY, DateTime.parse("2006-07-01TZ"), Registry.get("foo")));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_TX, DateTime.parse("2006-07-01TZ"), Registry.get("foo")));
loggerToIntercept.addHandler(logHandler);
}
@ -146,10 +146,10 @@ class IcannReportingUploadActionTest {
void testSuccess_january() throws Exception {
clock.setTo(DateTime.parse("2006-01-22T00:30:00Z"));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_ACTIVITY, DateTime.parse("2006-01-01TZ"), Registry.get("tld")));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_TX, DateTime.parse("2006-01-01TZ"), Registry.get("tld")));
gcsUtils.createFromBytes(
BlobId.of("basin/icann/monthly/2005-12", "tld-transactions-200512.csv"), PAYLOAD_SUCCESS);
@ -183,7 +183,8 @@ class IcannReportingUploadActionTest {
IcannReportingUploadAction action = createAction();
action.run();
tm().clearSessionCache();
Cursor cursor = loadByKey(Cursor.createVKey(CursorType.ICANN_UPLOAD_ACTIVITY, "tld"));
Cursor cursor =
loadByKey(Cursor.createScopedVKey(CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("tld")));
assertThat(cursor.getCursorTime()).isEqualTo(DateTime.parse("2006-08-01TZ"));
}
@ -241,7 +242,8 @@ class IcannReportingUploadActionTest {
runTest_nonRetryableException(
new IOException("Your IP address 25.147.130.158 is not allowed to connect"));
tm().clearSessionCache();
Cursor cursor = loadByKey(Cursor.createVKey(CursorType.ICANN_UPLOAD_ACTIVITY, "tld"));
Cursor cursor =
loadByKey(Cursor.createScopedVKey(CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("tld")));
assertThat(cursor.getCursorTime()).isEqualTo(DateTime.parse("2006-07-01TZ"));
}
@ -251,7 +253,8 @@ class IcannReportingUploadActionTest {
IcannReportingUploadAction action = createAction();
action.run();
tm().clearSessionCache();
Cursor cursor = loadByKey(Cursor.createVKey(CursorType.ICANN_UPLOAD_ACTIVITY, "foo"));
Cursor cursor =
loadByKey(Cursor.createScopedVKey(CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("foo")));
assertThat(cursor.getCursorTime()).isEqualTo(DateTime.parse("2006-07-01TZ"));
verifyNoMoreInteractions(mockReporter);
}
@ -286,7 +289,7 @@ class IcannReportingUploadActionTest {
void testFail_fileNotFound() throws Exception {
clock.setTo(DateTime.parse("2006-01-22T00:30:00Z"));
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_ACTIVITY, DateTime.parse("2006-01-01TZ"), Registry.get("tld")));
IcannReportingUploadAction action = createAction();
action.run();
@ -302,7 +305,7 @@ class IcannReportingUploadActionTest {
@TestOfyAndSql
void testWarning_fileNotStagedYet() throws Exception {
persistResource(
Cursor.create(
Cursor.createScoped(
CursorType.ICANN_UPLOAD_ACTIVITY, DateTime.parse("2006-08-01TZ"), Registry.get("foo")));
clock.setTo(DateTime.parse("2006-08-01T00:30:00Z"));
IcannReportingUploadAction action = createAction();
@ -352,9 +355,10 @@ class IcannReportingUploadActionTest {
new InternetAddress("sender@example.com")));
Cursor newActivityCursor =
loadByKey(Cursor.createVKey(CursorType.ICANN_UPLOAD_ACTIVITY, "new"));
loadByKey(Cursor.createScopedVKey(CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("new")));
assertThat(newActivityCursor.getCursorTime()).isEqualTo(DateTime.parse("2006-08-01TZ"));
Cursor newTransactionCursor = loadByKey(Cursor.createVKey(CursorType.ICANN_UPLOAD_TX, "new"));
Cursor newTransactionCursor =
loadByKey(Cursor.createScopedVKey(CursorType.ICANN_UPLOAD_TX, Registry.get("new")));
assertThat(newTransactionCursor.getCursorTime()).isEqualTo(DateTime.parse("2006-08-01TZ"));
}
}

View file

@ -388,12 +388,12 @@ public class DatabaseHelper {
}
/** Creates and persists a tld. */
public static void createTld(String tld) {
createTld(tld, GENERAL_AVAILABILITY);
public static Registry createTld(String tld) {
return createTld(tld, GENERAL_AVAILABILITY);
}
public static void createTld(String tld, String roidSuffix) {
createTld(tld, roidSuffix, ImmutableSortedMap.of(START_OF_TIME, GENERAL_AVAILABILITY));
public static Registry createTld(String tld, String roidSuffix) {
return createTld(tld, roidSuffix, ImmutableSortedMap.of(START_OF_TIME, GENERAL_AVAILABILITY));
}
/** Creates and persists the given TLDs. */
@ -403,23 +403,25 @@ public class DatabaseHelper {
}
}
public static void createTld(String tld, TldState tldState) {
createTld(tld, ImmutableSortedMap.of(START_OF_TIME, tldState));
public static Registry createTld(String tld, TldState tldState) {
return createTld(tld, ImmutableSortedMap.of(START_OF_TIME, tldState));
}
public static void createTld(String tld, ImmutableSortedMap<DateTime, TldState> tldStates) {
public static Registry createTld(String tld, ImmutableSortedMap<DateTime, TldState> tldStates) {
// Coerce the TLD string into a valid ROID suffix.
String roidSuffix =
Ascii.toUpperCase(tld.replaceFirst(ACE_PREFIX_REGEX, "").replace('.', '_'))
.replace('-', '_');
createTld(tld, roidSuffix.length() > 8 ? roidSuffix.substring(0, 8) : roidSuffix, tldStates);
return createTld(
tld, roidSuffix.length() > 8 ? roidSuffix.substring(0, 8) : roidSuffix, tldStates);
}
public static void createTld(
public static Registry createTld(
String tld, String roidSuffix, ImmutableSortedMap<DateTime, TldState> tldStates) {
persistResource(newRegistry(tld, roidSuffix, tldStates));
Registry registry = persistResource(newRegistry(tld, roidSuffix, tldStates));
allowRegistrarAccess("TheRegistrar", tld);
allowRegistrarAccess("NewRegistrar", tld);
return registry;
}
public static void deleteTld(String tld) {

View file

@ -15,6 +15,7 @@
package google.registry.testing;
import google.registry.model.AppEngineEnvironment;
import google.registry.model.annotations.DeleteAfterMigration;
import org.junit.jupiter.api.extension.AfterEachCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
@ -37,6 +38,7 @@ import org.junit.jupiter.api.extension.ExtensionContext;
*
* @see AppEngineEnvironment
*/
@DeleteAfterMigration
public class DatastoreEntityExtension implements BeforeEachCallback, AfterEachCallback {
private final AppEngineEnvironment environment;

View file

@ -59,7 +59,7 @@ public class ListCursorsCommandTest extends CommandTestCase<ListCursorsCommand>
void testListCursors_twoTldsOneAbsent_printsAbsentAndTimestampSorted() throws Exception {
createTlds("foo", "bar");
persistResource(
Cursor.create(CursorType.BRDA, DateTime.parse("1984-12-18TZ"), Registry.get("bar")));
Cursor.createScoped(CursorType.BRDA, DateTime.parse("1984-12-18TZ"), Registry.get("bar")));
runCommand("--type=BRDA");
assertThat(getStdoutAsLines())
.containsExactly(

View file

@ -40,13 +40,12 @@ class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsCommand> {
@BeforeEach
void beforeEach() {
createTld("foo");
registry = Registry.get("foo");
registry = createTld("foo");
}
void doUpdateTest() throws Exception {
runCommandForced("--type=brda", "--timestamp=1984-12-18T00:00:00Z", "foo");
assertThat(loadByKey(Cursor.createVKey(CursorType.BRDA, "foo")).getCursorTime())
assertThat(loadByKey(Cursor.createScopedVKey(CursorType.BRDA, registry)).getCursorTime())
.isEqualTo(DateTime.parse("1984-12-18TZ"));
String changes = command.prompt();
assertThat(changes)
@ -66,14 +65,13 @@ class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsCommand> {
@TestOfyAndSql
void testSuccess_oldValueisEmpty() throws Exception {
assertThat(loadByKeyIfPresent(Cursor.createVKey(CursorType.BRDA, registry.getTldStr())))
.isEmpty();
assertThat(loadByKeyIfPresent(Cursor.createScopedVKey(CursorType.BRDA, registry))).isEmpty();
doUpdateTest();
}
@TestOfyAndSql
void testSuccess_hasOldValue() throws Exception {
persistResource(Cursor.create(CursorType.BRDA, DateTime.parse("1950-12-18TZ"), registry));
persistResource(Cursor.createScoped(CursorType.BRDA, DateTime.parse("1950-12-18TZ"), registry));
doUpdateTest();
}
@ -92,14 +90,15 @@ class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsCommand> {
@TestOfyAndSql
void testSuccess_multipleTlds_hasOldValue() throws Exception {
createTld("bar");
Registry barRegistry = createTld("bar");
Registry registry2 = Registry.get("bar");
persistResource(Cursor.create(CursorType.BRDA, DateTime.parse("1950-12-18TZ"), registry));
persistResource(Cursor.create(CursorType.BRDA, DateTime.parse("1950-12-18TZ"), registry2));
persistResource(Cursor.createScoped(CursorType.BRDA, DateTime.parse("1950-12-18TZ"), registry));
persistResource(
Cursor.createScoped(CursorType.BRDA, DateTime.parse("1950-12-18TZ"), registry2));
runCommandForced("--type=brda", "--timestamp=1984-12-18T00:00:00Z", "foo", "bar");
assertThat(loadByKey(Cursor.createVKey(CursorType.BRDA, "foo")).getCursorTime())
assertThat(loadByKey(Cursor.createScopedVKey(CursorType.BRDA, registry)).getCursorTime())
.isEqualTo(DateTime.parse("1984-12-18TZ"));
assertThat(loadByKey(Cursor.createVKey(CursorType.BRDA, "bar")).getCursorTime())
assertThat(loadByKey(Cursor.createScopedVKey(CursorType.BRDA, barRegistry)).getCursorTime())
.isEqualTo(DateTime.parse("1984-12-18TZ"));
String changes = command.prompt();
assertThat(changes)
@ -110,13 +109,13 @@ class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsCommand> {
@TestOfyAndSql
void testSuccess_multipleTlds_oldValueisEmpty() throws Exception {
createTld("bar");
assertThat(loadByKeyIfPresent(Cursor.createVKey(CursorType.BRDA, "foo"))).isEmpty();
assertThat(loadByKeyIfPresent(Cursor.createVKey(CursorType.BRDA, "bar"))).isEmpty();
Registry barRegistry = createTld("bar");
assertThat(loadByKeyIfPresent(Cursor.createScopedVKey(CursorType.BRDA, registry))).isEmpty();
assertThat(loadByKeyIfPresent(Cursor.createScopedVKey(CursorType.BRDA, barRegistry))).isEmpty();
runCommandForced("--type=brda", "--timestamp=1984-12-18T00:00:00Z", "foo", "bar");
assertThat(loadByKey(Cursor.createVKey(CursorType.BRDA, "foo")).getCursorTime())
assertThat(loadByKey(Cursor.createScopedVKey(CursorType.BRDA, registry)).getCursorTime())
.isEqualTo(DateTime.parse("1984-12-18TZ"));
assertThat(loadByKey(Cursor.createVKey(CursorType.BRDA, "bar")).getCursorTime())
assertThat(loadByKey(Cursor.createScopedVKey(CursorType.BRDA, barRegistry)).getCursorTime())
.isEqualTo(DateTime.parse("1984-12-18TZ"));
String changes = command.prompt();
assertThat(changes)

View file

@ -1,7 +1,6 @@
AllocationToken
Cancellation
ContactResource
Cursor
DomainBase
EntityGroupRoot
EppResourceIndex

View file

@ -1,4 +1,3 @@
Cursor
Registrar
Registry
ServerSecret

View file

@ -79,12 +79,6 @@ enum google.registry.model.billing.BillingEvent$RenewalPriceBehavior {
NONPREMIUM;
SPECIFIED;
}
class google.registry.model.common.Cursor {
@Id java.lang.String id;
@Parent com.googlecode.objectify.Key<google.registry.model.common.EntityGroupRoot> parent;
google.registry.model.UpdateAutoTimestamp lastUpdateTime;
org.joda.time.DateTime cursorTime;
}
class google.registry.model.common.EntityGroupRoot {
@Id java.lang.String id;
google.registry.model.UpdateAutoTimestamp updateTimestamp;