mirror of
https://github.com/google/nomulus.git
synced 2025-07-10 13:13:28 +02:00
Add dual write for Cursors (#414)
* Add dual write for Cursors * Fix UpdateCursorCommand to dual write multiple cursors * Small fixes * Make UpdateCursorsCommand implement CommandWithCloudSql
This commit is contained in:
parent
ad2cf933c2
commit
0b717d40ff
20 changed files with 319 additions and 62 deletions
|
@ -58,6 +58,7 @@ import google.registry.request.Action;
|
||||||
import google.registry.request.Parameter;
|
import google.registry.request.Parameter;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -313,8 +314,7 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
|
||||||
logger.atInfo().log(
|
logger.atInfo().log(
|
||||||
"Recurring event expansion %s complete for billing event range [%s, %s).",
|
"Recurring event expansion %s complete for billing event range [%s, %s).",
|
||||||
isDryRun ? "(dry run) " : "", cursorTime, executionTime);
|
isDryRun ? "(dry run) " : "", cursorTime, executionTime);
|
||||||
tm()
|
tm().transact(
|
||||||
.transact(
|
|
||||||
() -> {
|
() -> {
|
||||||
Cursor cursor = ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
|
Cursor cursor = ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
|
||||||
DateTime currentCursorTime =
|
DateTime currentCursorTime =
|
||||||
|
@ -326,7 +326,9 @@ public class ExpandRecurringBillingEventsAction implements Runnable {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isDryRun) {
|
if (!isDryRun) {
|
||||||
ofy().save().entity(Cursor.createGlobal(RECURRING_BILLING, executionTime));
|
CursorDao.saveCursor(
|
||||||
|
Cursor.createGlobal(RECURRING_BILLING, executionTime),
|
||||||
|
google.registry.schema.cursor.Cursor.GLOBAL);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,6 @@ import static google.registry.model.registrar.RegistrarContact.Type.LEGAL;
|
||||||
import static google.registry.model.registrar.RegistrarContact.Type.MARKETING;
|
import static google.registry.model.registrar.RegistrarContact.Type.MARKETING;
|
||||||
import static google.registry.model.registrar.RegistrarContact.Type.TECH;
|
import static google.registry.model.registrar.RegistrarContact.Type.TECH;
|
||||||
import static google.registry.model.registrar.RegistrarContact.Type.WHOIS;
|
import static google.registry.model.registrar.RegistrarContact.Type.WHOIS;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
@ -37,6 +36,7 @@ import google.registry.model.common.Cursor;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.model.registrar.RegistrarAddress;
|
import google.registry.model.registrar.RegistrarAddress;
|
||||||
import google.registry.model.registrar.RegistrarContact;
|
import google.registry.model.registrar.RegistrarContact;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import google.registry.util.DateTimeUtils;
|
import google.registry.util.DateTimeUtils;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -153,9 +153,9 @@ class SyncRegistrarsSheet {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
})
|
})
|
||||||
.collect(toImmutableList()));
|
.collect(toImmutableList()));
|
||||||
tm()
|
CursorDao.saveCursor(
|
||||||
.transact(
|
Cursor.createGlobal(SYNC_REGISTRAR_SHEET, executionTime),
|
||||||
() -> ofy().save().entity(Cursor.createGlobal(SYNC_REGISTRAR_SHEET, executionTime)));
|
google.registry.schema.cursor.Cursor.GLOBAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String convertContacts(
|
private static String convertContacts(
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static google.registry.model.common.EntityGroupRoot.getCrossTldKey;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
|
||||||
|
import com.google.common.base.Splitter;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.annotation.Entity;
|
import com.googlecode.objectify.annotation.Entity;
|
||||||
import com.googlecode.objectify.annotation.Id;
|
import com.googlecode.objectify.annotation.Id;
|
||||||
|
@ -27,6 +28,7 @@ import com.googlecode.objectify.annotation.Parent;
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.UpdateAutoTimestamp;
|
import google.registry.model.UpdateAutoTimestamp;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
|
import java.util.List;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -127,6 +129,11 @@ public class Cursor extends ImmutableObject {
|
||||||
return lastUpdateTime.getTimestamp();
|
return lastUpdateTime.getTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public CursorType getType() {
|
||||||
|
List<String> id = Splitter.on('_').splitToList(this.id);
|
||||||
|
return CursorType.valueOf(String.join("_", id.subList(1, id.size())));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that the type of the scoped object (or null) matches the required type for the specified
|
* 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).
|
* cursor (or null, if the cursor is a global cursor).
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
package google.registry.rde;
|
package google.registry.rde;
|
||||||
|
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
|
||||||
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.model.common.Cursor;
|
import google.registry.model.common.Cursor;
|
||||||
|
@ -24,6 +23,7 @@ import google.registry.model.registry.Registry;
|
||||||
import google.registry.request.HttpException.NoContentException;
|
import google.registry.request.HttpException.NoContentException;
|
||||||
import google.registry.request.HttpException.ServiceUnavailableException;
|
import google.registry.request.HttpException.ServiceUnavailableException;
|
||||||
import google.registry.request.lock.LockHandler;
|
import google.registry.request.lock.LockHandler;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
@ -99,7 +99,7 @@ class EscrowTaskRunner {
|
||||||
task.runWithLock(nextRequiredRun);
|
task.runWithLock(nextRequiredRun);
|
||||||
DateTime nextRun = nextRequiredRun.plus(interval);
|
DateTime nextRun = nextRequiredRun.plus(interval);
|
||||||
logger.atInfo().log("Rolling cursor forward to %s.", nextRun);
|
logger.atInfo().log("Rolling cursor forward to %s.", nextRun);
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.create(cursorType, nextRun, registry)));
|
CursorDao.saveCursor(Cursor.create(cursorType, nextRun, registry), registry.getTldStr());
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
String lockName = String.format("EscrowTaskRunner %s", task.getClass().getSimpleName());
|
String lockName = String.format("EscrowTaskRunner %s", task.getClass().getSimpleName());
|
||||||
|
|
|
@ -27,6 +27,7 @@ import google.registry.model.rde.RdeMode;
|
||||||
import google.registry.model.registry.Registries;
|
import google.registry.model.registry.Registries;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.registry.Registry.TldType;
|
import google.registry.model.registry.Registry.TldType;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
@ -107,14 +108,14 @@ public final class PendingDepositChecker {
|
||||||
final Registry registry,
|
final Registry registry,
|
||||||
final CursorType cursorType,
|
final CursorType cursorType,
|
||||||
final DateTime initialValue) {
|
final DateTime initialValue) {
|
||||||
return tm()
|
return tm().transact(
|
||||||
.transact(
|
|
||||||
() -> {
|
() -> {
|
||||||
Cursor cursor = ofy().load().key(Cursor.createKey(cursorType, registry)).now();
|
Cursor cursor = ofy().load().key(Cursor.createKey(cursorType, registry)).now();
|
||||||
if (cursor != null) {
|
if (cursor != null) {
|
||||||
return cursor.getCursorTime();
|
return cursor.getCursorTime();
|
||||||
}
|
}
|
||||||
ofy().save().entity(Cursor.create(cursorType, initialValue, registry));
|
CursorDao.saveCursor(
|
||||||
|
Cursor.create(cursorType, initialValue, registry), registry.getTldStr());
|
||||||
return initialValue;
|
return initialValue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ import google.registry.model.rde.RdeRevision;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.request.RequestParameters;
|
import google.registry.request.RequestParameters;
|
||||||
import google.registry.request.lock.LockHandler;
|
import google.registry.request.lock.LockHandler;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.tldconfig.idn.IdnTableEnum;
|
import google.registry.tldconfig.idn.IdnTableEnum;
|
||||||
import google.registry.util.TaskQueueUtils;
|
import google.registry.util.TaskQueueUtils;
|
||||||
import google.registry.xjc.rdeheader.XjcRdeHeader;
|
import google.registry.xjc.rdeheader.XjcRdeHeader;
|
||||||
|
@ -198,13 +199,12 @@ public final class RdeStagingReducer extends Reducer<PendingDeposit, DepositFrag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we're done, kick off RdeUploadAction and roll forward the cursor transactionally.
|
// Now that we're done, kick off RdeUploadAction and roll the cursor forward.
|
||||||
if (key.manual()) {
|
if (key.manual()) {
|
||||||
logger.atInfo().log("Manual operation; not advancing cursor or enqueuing upload task");
|
logger.atInfo().log("Manual operation; not advancing cursor or enqueuing upload task");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tm()
|
tm().transact(
|
||||||
.transact(
|
|
||||||
() -> {
|
() -> {
|
||||||
Registry registry = Registry.get(tld);
|
Registry registry = Registry.get(tld);
|
||||||
DateTime position =
|
DateTime position =
|
||||||
|
@ -221,7 +221,8 @@ public final class RdeStagingReducer extends Reducer<PendingDeposit, DepositFrag
|
||||||
"Partial ordering of RDE deposits broken: %s %s",
|
"Partial ordering of RDE deposits broken: %s %s",
|
||||||
position,
|
position,
|
||||||
key);
|
key);
|
||||||
ofy().save().entity(Cursor.create(key.cursor(), newPosition, registry)).now();
|
CursorDao.saveCursor(
|
||||||
|
Cursor.create(key.cursor(), newPosition, registry), registry.getTldStr());
|
||||||
logger.atInfo().log(
|
logger.atInfo().log(
|
||||||
"Rolled forward %s on %s cursor to %s", key.cursor(), tld, newPosition);
|
"Rolled forward %s on %s cursor to %s", key.cursor(), tld, newPosition);
|
||||||
RdeRevision.saveRevision(tld, watermark, mode, revision);
|
RdeRevision.saveRevision(tld, watermark, mode, revision);
|
||||||
|
|
|
@ -52,6 +52,7 @@ import google.registry.request.Parameter;
|
||||||
import google.registry.request.RequestParameters;
|
import google.registry.request.RequestParameters;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import google.registry.util.Retrier;
|
import google.registry.util.Retrier;
|
||||||
import google.registry.util.TaskQueueUtils;
|
import google.registry.util.TaskQueueUtils;
|
||||||
|
@ -170,12 +171,11 @@ public final class RdeUploadAction implements Runnable, EscrowTask {
|
||||||
() -> upload(xmlFilename, xmlLength, watermark, name), JSchException.class);
|
() -> upload(xmlFilename, xmlLength, watermark, name), JSchException.class);
|
||||||
logger.atInfo().log(
|
logger.atInfo().log(
|
||||||
"Updating RDE cursor '%s' for TLD '%s' following successful upload.", RDE_UPLOAD_SFTP, tld);
|
"Updating RDE cursor '%s' for TLD '%s' following successful upload.", RDE_UPLOAD_SFTP, tld);
|
||||||
tm()
|
tm().transact(
|
||||||
.transact(
|
|
||||||
() -> {
|
() -> {
|
||||||
Cursor updatedSftpCursor =
|
CursorDao.saveCursor(
|
||||||
Cursor.create(RDE_UPLOAD_SFTP, tm().getTransactionTime(), Registry.get(tld));
|
Cursor.create(RDE_UPLOAD_SFTP, tm().getTransactionTime(), Registry.get(tld)),
|
||||||
ofy().save().entity(updatedSftpCursor);
|
tld);
|
||||||
});
|
});
|
||||||
response.setContentType(PLAIN_TEXT_UTF_8);
|
response.setContentType(PLAIN_TEXT_UTF_8);
|
||||||
response.setPayload(String.format("OK %s %s\n", tld, watermark));
|
response.setPayload(String.format("OK %s %s\n", tld, watermark));
|
||||||
|
|
|
@ -44,6 +44,7 @@ import google.registry.request.Parameter;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import google.registry.request.lock.LockHandler;
|
import google.registry.request.lock.LockHandler;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.util.Clock;
|
import google.registry.util.Clock;
|
||||||
import google.registry.util.EmailMessage;
|
import google.registry.util.EmailMessage;
|
||||||
import google.registry.util.Retrier;
|
import google.registry.util.Retrier;
|
||||||
|
@ -51,6 +52,7 @@ import google.registry.util.SendEmailService;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -186,7 +188,9 @@ public final class IcannReportingUploadAction implements Runnable {
|
||||||
cursorType,
|
cursorType,
|
||||||
cursorTime.withTimeAtStartOfDay().withDayOfMonth(1).plusMonths(1),
|
cursorTime.withTimeAtStartOfDay().withDayOfMonth(1).plusMonths(1),
|
||||||
Registry.get(tldStr));
|
Registry.get(tldStr));
|
||||||
tm().transact(() -> ofy().save().entity(newCursor));
|
CursorDao.saveCursor(
|
||||||
|
newCursor,
|
||||||
|
Optional.ofNullable(tldStr).orElse(google.registry.schema.cursor.Cursor.GLOBAL));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,13 @@
|
||||||
package google.registry.schema.cursor;
|
package google.registry.schema.cursor;
|
||||||
|
|
||||||
import static com.google.appengine.api.search.checkers.Preconditions.checkNotNull;
|
import static com.google.appengine.api.search.checkers.Preconditions.checkNotNull;
|
||||||
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
import static google.registry.model.transaction.TransactionManagerFactory.jpaTm;
|
||||||
|
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.model.common.Cursor.CursorType;
|
import google.registry.model.common.Cursor.CursorType;
|
||||||
import google.registry.schema.cursor.Cursor.CursorId;
|
import google.registry.schema.cursor.Cursor.CursorId;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -24,6 +29,8 @@ import java.util.List;
|
||||||
/** Data access object class for {@link Cursor}. */
|
/** Data access object class for {@link Cursor}. */
|
||||||
public class CursorDao {
|
public class CursorDao {
|
||||||
|
|
||||||
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
||||||
public static void save(Cursor cursor) {
|
public static void save(Cursor cursor) {
|
||||||
jpaTm()
|
jpaTm()
|
||||||
.transact(
|
.transact(
|
||||||
|
@ -32,9 +39,19 @@ public class CursorDao {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void saveAll(ImmutableSet<Cursor> cursors) {
|
||||||
|
jpaTm()
|
||||||
|
.transact(
|
||||||
|
() -> {
|
||||||
|
for (Cursor cursor : cursors) {
|
||||||
|
jpaTm().getEntityManager().merge(cursor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static Cursor load(CursorType type, String scope) {
|
public static Cursor load(CursorType type, String scope) {
|
||||||
checkNotNull(scope, "The scope of the cursor to load cannot be null");
|
checkNotNull(scope, "The scope of the cursor to load cannot be null");
|
||||||
checkNotNull(type, "The type of the cursor to load must be specified");
|
checkNotNull(type, "The type of the cursor to load cannot be null");
|
||||||
return jpaTm()
|
return jpaTm()
|
||||||
.transact(() -> jpaTm().getEntityManager().find(Cursor.class, new CursorId(type, scope)));
|
.transact(() -> jpaTm().getEntityManager().find(Cursor.class, new CursorId(type, scope)));
|
||||||
}
|
}
|
||||||
|
@ -67,4 +84,50 @@ public class CursorDao {
|
||||||
.setParameter("type", type)
|
.setParameter("type", type)
|
||||||
.getResultList());
|
.getResultList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This writes the given cursor to Datastore. If the save to Datastore succeeds, then a new
|
||||||
|
* Schema/Cursor object is created and attempted to save to Cloud SQL. If the save to Cloud SQL
|
||||||
|
* fails, the exception is logged, but does not cause the method to fail.
|
||||||
|
*/
|
||||||
|
public static void saveCursor(google.registry.model.common.Cursor cursor, String scope) {
|
||||||
|
tm().transact(() -> ofy().save().entity(cursor));
|
||||||
|
CursorType type = cursor.getType();
|
||||||
|
try {
|
||||||
|
Cursor cloudSqlCursor = Cursor.create(type, scope, cursor.getCursorTime());
|
||||||
|
save(cloudSqlCursor);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.atSevere().withCause(e).log("Error saving cursor to Cloud SQL.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This takes in multiple cursors and saves them to Datastore. If those saves succeed, it attempts
|
||||||
|
* to save the cursors to Cloud SQL. If the save to Cloud SQL fails, the exception is logged, but
|
||||||
|
* does not cause the method to fail.
|
||||||
|
*/
|
||||||
|
public static void saveCursors(
|
||||||
|
ImmutableMap<google.registry.model.common.Cursor, String> cursors) {
|
||||||
|
// Save the cursors to Datastore
|
||||||
|
tm().transact(
|
||||||
|
() -> {
|
||||||
|
for (google.registry.model.common.Cursor cursor : cursors.keySet()) {
|
||||||
|
ofy().save().entity(cursor);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Try to save the cursors to Cloud SQL
|
||||||
|
try {
|
||||||
|
ImmutableSet.Builder<Cursor> cloudSqlCursors = new ImmutableSet.Builder<>();
|
||||||
|
cursors
|
||||||
|
.keySet()
|
||||||
|
.forEach(
|
||||||
|
cursor ->
|
||||||
|
cloudSqlCursors.add(
|
||||||
|
Cursor.create(
|
||||||
|
cursor.getType(), cursors.get(cursor), cursor.getCursorTime())));
|
||||||
|
saveAll(cloudSqlCursors.build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.atSevere().withCause(e).log("Error saving cursor to Cloud SQL.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,21 +14,22 @@
|
||||||
|
|
||||||
package google.registry.tools;
|
package google.registry.tools;
|
||||||
|
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
||||||
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
import static google.registry.util.CollectionUtils.isNullOrEmpty;
|
||||||
|
|
||||||
import com.beust.jcommander.Parameter;
|
import com.beust.jcommander.Parameter;
|
||||||
import com.beust.jcommander.Parameters;
|
import com.beust.jcommander.Parameters;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
import google.registry.model.common.Cursor;
|
import google.registry.model.common.Cursor;
|
||||||
import google.registry.model.common.Cursor.CursorType;
|
import google.registry.model.common.Cursor.CursorType;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.tools.params.DateTimeParameter;
|
import google.registry.tools.params.DateTimeParameter;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/** Modifies {@link Cursor} timestamps used by locking rolling cursor tasks, like in RDE. */
|
/** Modifies {@link Cursor} timestamps used by locking rolling cursor tasks, like in RDE. */
|
||||||
@Parameters(separators = " =", commandDescription = "Modifies cursor timestamps used by LRC tasks")
|
@Parameters(separators = " =", commandDescription = "Modifies cursor timestamps used by LRC tasks")
|
||||||
final class UpdateCursorsCommand extends MutatingCommand {
|
final class UpdateCursorsCommand extends ConfirmingCommand implements CommandWithCloudSql {
|
||||||
|
|
||||||
@Parameter(description = "TLDs on which to operate. Omit for global cursors.")
|
@Parameter(description = "TLDs on which to operate. Omit for global cursors.")
|
||||||
private List<String> tlds;
|
private List<String> tlds;
|
||||||
|
@ -46,19 +47,46 @@ final class UpdateCursorsCommand extends MutatingCommand {
|
||||||
required = true)
|
required = true)
|
||||||
private DateTime newTimestamp;
|
private DateTime newTimestamp;
|
||||||
|
|
||||||
|
ImmutableMap<Cursor, String> cursorsToUpdate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
|
ImmutableMap.Builder<Cursor, String> cursorsToUpdateBuilder = new ImmutableMap.Builder<>();
|
||||||
if (isNullOrEmpty(tlds)) {
|
if (isNullOrEmpty(tlds)) {
|
||||||
Cursor cursor = ofy().load().key(Cursor.createGlobalKey(cursorType)).now();
|
cursorsToUpdateBuilder.put(
|
||||||
stageEntityChange(cursor, Cursor.createGlobal(cursorType, newTimestamp));
|
Cursor.createGlobal(cursorType, newTimestamp),
|
||||||
|
google.registry.schema.cursor.Cursor.GLOBAL);
|
||||||
} else {
|
} else {
|
||||||
for (String tld : tlds) {
|
for (String tld : tlds) {
|
||||||
Registry registry = Registry.get(tld);
|
Registry registry = Registry.get(tld);
|
||||||
Cursor cursor = ofy().load().key(Cursor.createKey(cursorType, registry)).now();
|
cursorsToUpdateBuilder.put(
|
||||||
stageEntityChange(
|
Cursor.create(cursorType, newTimestamp, registry), registry.getTldStr());
|
||||||
cursor,
|
|
||||||
Cursor.create(cursorType, newTimestamp, registry));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cursorsToUpdate = cursorsToUpdateBuilder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String execute() throws Exception {
|
||||||
|
CursorDao.saveCursors(cursorsToUpdate);
|
||||||
|
return String.format("Updated %d cursors.\n", cursorsToUpdate.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the changes that have been staged thus far. */
|
||||||
|
@Override
|
||||||
|
protected String prompt() {
|
||||||
|
StringBuilder changes = new StringBuilder();
|
||||||
|
if (cursorsToUpdate.isEmpty()) {
|
||||||
|
return "No cursor changes to apply.";
|
||||||
|
}
|
||||||
|
cursorsToUpdate.entrySet().stream()
|
||||||
|
.forEach(entry -> changes.append(getChangeString(entry.getKey(), entry.getValue())));
|
||||||
|
return changes.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getChangeString(Cursor cursor, String scope) {
|
||||||
|
return String.format(
|
||||||
|
"Change cursorTime of %s for Scope:%s to %s\n",
|
||||||
|
cursor.getType(), scope, cursor.getCursorTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@ package google.registry.backup;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.model.common.Cursor.CursorType.RDE_REPORT;
|
import static google.registry.model.common.Cursor.CursorType.RDE_REPORT;
|
||||||
import static google.registry.model.ofy.CommitLogBucket.getBucketKey;
|
import static google.registry.model.ofy.CommitLogBucket.getBucketKey;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
@ -31,6 +30,7 @@ import google.registry.model.ofy.DatastoreTransactionManager;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.transaction.TransactionManager;
|
import google.registry.model.transaction.TransactionManager;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
@ -54,6 +54,7 @@ public class CommitLogCheckpointStrategyTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final InjectRule inject = new InjectRule();
|
public final InjectRule inject = new InjectRule();
|
||||||
|
|
||||||
|
|
||||||
final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||||
final Ofy ofy = new Ofy(clock);
|
final Ofy ofy = new Ofy(clock);
|
||||||
final TransactionManager tm = new DatastoreTransactionManager(ofy);
|
final TransactionManager tm = new DatastoreTransactionManager(ofy);
|
||||||
|
@ -293,11 +294,10 @@ public class CommitLogCheckpointStrategyTest {
|
||||||
private void writeCommitLogToBucket(final int bucketId) {
|
private void writeCommitLogToBucket(final int bucketId) {
|
||||||
fakeBucketIdSupplier.value = bucketId;
|
fakeBucketIdSupplier.value = bucketId;
|
||||||
tm.transact(
|
tm.transact(
|
||||||
() -> {
|
() ->
|
||||||
Cursor cursor =
|
CursorDao.saveCursor(
|
||||||
Cursor.create(RDE_REPORT, tm.getTransactionTime(), Registry.get("tld" + bucketId));
|
Cursor.create(RDE_REPORT, tm.getTransactionTime(), Registry.get("tld" + bucketId)),
|
||||||
ofy().save().entity(cursor);
|
"tld" + bucketId));
|
||||||
});
|
|
||||||
fakeBucketIdSupplier.value = null;
|
fakeBucketIdSupplier.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
||||||
import static google.registry.model.domain.Period.Unit.YEARS;
|
import static google.registry.model.domain.Period.Unit.YEARS;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
import static google.registry.model.reporting.HistoryEntry.Type.DOMAIN_AUTORENEW;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
|
||||||
import static google.registry.testing.DatastoreHelper.assertBillingEvents;
|
import static google.registry.testing.DatastoreHelper.assertBillingEvents;
|
||||||
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
|
import static google.registry.testing.DatastoreHelper.assertBillingEventsForResource;
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
|
@ -50,6 +49,7 @@ import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.reporting.DomainTransactionRecord;
|
import google.registry.model.reporting.DomainTransactionRecord;
|
||||||
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
|
||||||
import google.registry.model.reporting.HistoryEntry;
|
import google.registry.model.reporting.HistoryEntry;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
@ -103,7 +103,9 @@ public class ExpandRecurringBillingEventsActionTest
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveCursor(final DateTime cursorTime) {
|
private void saveCursor(final DateTime cursorTime) {
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.createGlobal(RECURRING_BILLING, cursorTime)));
|
CursorDao.saveCursor(
|
||||||
|
Cursor.createGlobal(RECURRING_BILLING, cursorTime),
|
||||||
|
google.registry.schema.cursor.Cursor.GLOBAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void runMapreduce() throws Exception {
|
private void runMapreduce() throws Exception {
|
||||||
|
|
|
@ -62,6 +62,7 @@ public class SyncRegistrarsSheetTest {
|
||||||
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
|
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
|
||||||
@Rule public final InjectRule inject = new InjectRule();
|
@Rule public final InjectRule inject = new InjectRule();
|
||||||
|
|
||||||
|
|
||||||
@Captor private ArgumentCaptor<ImmutableList<ImmutableMap<String, String>>> rowsCaptor;
|
@Captor private ArgumentCaptor<ImmutableList<ImmutableMap<String, String>>> rowsCaptor;
|
||||||
@Mock private SheetSynchronizer sheetSynchronizer;
|
@Mock private SheetSynchronizer sheetSynchronizer;
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ 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.RDE_UPLOAD;
|
||||||
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
import static google.registry.model.common.Cursor.CursorType.RECURRING_BILLING;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
import static google.registry.testing.DatastoreHelper.persistActiveDomain;
|
||||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
@ -28,6 +27,7 @@ import static org.junit.Assert.assertThrows;
|
||||||
import google.registry.model.EntityTestCase;
|
import google.registry.model.EntityTestCase;
|
||||||
import google.registry.model.domain.DomainBase;
|
import google.registry.model.domain.DomainBase;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ public class CursorTest extends EntityTestCase {
|
||||||
createTld("tld");
|
createTld("tld");
|
||||||
clock.advanceOneMilli();
|
clock.advanceOneMilli();
|
||||||
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
|
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.create(RDE_UPLOAD, time, Registry.get("tld"))));
|
CursorDao.saveCursor(Cursor.create(RDE_UPLOAD, time, Registry.get("tld")), "tld");
|
||||||
assertThat(ofy().load().key(Cursor.createKey(BRDA, Registry.get("tld"))).now()).isNull();
|
assertThat(ofy().load().key(Cursor.createKey(BRDA, Registry.get("tld"))).now()).isNull();
|
||||||
assertThat(
|
assertThat(
|
||||||
ofy()
|
ofy()
|
||||||
|
@ -53,7 +53,8 @@ public class CursorTest extends EntityTestCase {
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_persistGlobalCursor() {
|
public void testSuccess_persistGlobalCursor() {
|
||||||
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
|
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.createGlobal(RECURRING_BILLING, time)));
|
CursorDao.saveCursor(
|
||||||
|
Cursor.createGlobal(RECURRING_BILLING, time), google.registry.schema.cursor.Cursor.GLOBAL);
|
||||||
assertThat(ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now().getCursorTime())
|
assertThat(ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now().getCursorTime())
|
||||||
.isEqualTo(time);
|
.isEqualTo(time);
|
||||||
}
|
}
|
||||||
|
@ -61,7 +62,8 @@ public class CursorTest extends EntityTestCase {
|
||||||
@Test
|
@Test
|
||||||
public void testIndexing() throws Exception {
|
public void testIndexing() throws Exception {
|
||||||
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
|
final DateTime time = DateTime.parse("2012-07-12T03:30:00.000Z");
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.createGlobal(RECURRING_BILLING, time)));
|
CursorDao.saveCursor(
|
||||||
|
Cursor.createGlobal(RECURRING_BILLING, time), google.registry.schema.cursor.Cursor.GLOBAL);
|
||||||
Cursor cursor = ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
|
Cursor cursor = ofy().load().key(Cursor.createGlobalKey(RECURRING_BILLING)).now();
|
||||||
verifyIndexing(cursor);
|
verifyIndexing(cursor);
|
||||||
}
|
}
|
||||||
|
@ -75,8 +77,7 @@ public class CursorTest extends EntityTestCase {
|
||||||
IllegalArgumentException thrown =
|
IllegalArgumentException thrown =
|
||||||
assertThrows(
|
assertThrows(
|
||||||
IllegalArgumentException.class,
|
IllegalArgumentException.class,
|
||||||
() ->
|
() -> CursorDao.saveCursor(Cursor.create(RDE_UPLOAD, time, domain), domain.getTld()));
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.create(RDE_UPLOAD, time, domain))));
|
|
||||||
assertThat(thrown)
|
assertThat(thrown)
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.contains("Class required for cursor does not match scope class");
|
.contains("Class required for cursor does not match scope class");
|
||||||
|
|
|
@ -59,7 +59,6 @@ public class EscrowTaskRunnerTest {
|
||||||
private EscrowTaskRunner runner;
|
private EscrowTaskRunner runner;
|
||||||
private Registry registry;
|
private Registry registry;
|
||||||
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
createTld("lol");
|
createTld("lol");
|
||||||
|
|
|
@ -20,7 +20,6 @@ import static google.registry.model.common.Cursor.CursorType.RDE_STAGING;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.rde.RdeMode.FULL;
|
import static google.registry.model.rde.RdeMode.FULL;
|
||||||
import static google.registry.model.rde.RdeMode.THIN;
|
import static google.registry.model.rde.RdeMode.THIN;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
import static org.joda.time.DateTimeConstants.TUESDAY;
|
import static org.joda.time.DateTimeConstants.TUESDAY;
|
||||||
|
@ -31,6 +30,7 @@ import google.registry.model.common.Cursor;
|
||||||
import google.registry.model.common.Cursor.CursorType;
|
import google.registry.model.common.Cursor.CursorType;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
@ -164,7 +164,7 @@ public class PendingDepositCheckerTest {
|
||||||
|
|
||||||
private static void setCursor(
|
private static void setCursor(
|
||||||
final Registry registry, final CursorType cursorType, final DateTime value) {
|
final Registry registry, final CursorType cursorType, final DateTime value) {
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.create(cursorType, value, registry)));
|
CursorDao.saveCursor(Cursor.create(cursorType, value, registry), registry.getTldStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void createTldWithEscrowEnabled(final String tld) {
|
private static void createTldWithEscrowEnabled(final String tld) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.model.common.Cursor.CursorType.BRDA;
|
import static google.registry.model.common.Cursor.CursorType.BRDA;
|
||||||
import static google.registry.model.common.Cursor.CursorType.RDE_STAGING;
|
import static google.registry.model.common.Cursor.CursorType.RDE_STAGING;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.model.transaction.TransactionManagerFactory.tm;
|
|
||||||
import static google.registry.rde.RdeFixtures.makeContactResource;
|
import static google.registry.rde.RdeFixtures.makeContactResource;
|
||||||
import static google.registry.rde.RdeFixtures.makeDomainBase;
|
import static google.registry.rde.RdeFixtures.makeDomainBase;
|
||||||
import static google.registry.rde.RdeFixtures.makeHostResource;
|
import static google.registry.rde.RdeFixtures.makeHostResource;
|
||||||
|
@ -55,6 +54,7 @@ import google.registry.model.ofy.Ofy;
|
||||||
import google.registry.model.registry.Registry;
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.request.HttpException.BadRequestException;
|
import google.registry.request.HttpException.BadRequestException;
|
||||||
import google.registry.request.RequestParameters;
|
import google.registry.request.RequestParameters;
|
||||||
|
import google.registry.schema.cursor.CursorDao;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeKeyringModule;
|
import google.registry.testing.FakeKeyringModule;
|
||||||
import google.registry.testing.FakeLockHandler;
|
import google.registry.testing.FakeLockHandler;
|
||||||
|
@ -848,7 +848,7 @@ public class RdeStagingActionTest extends MapreduceTestCase<RdeStagingAction> {
|
||||||
private void setCursor(
|
private void setCursor(
|
||||||
final Registry registry, final CursorType cursorType, final DateTime value) {
|
final Registry registry, final CursorType cursorType, final DateTime value) {
|
||||||
clock.advanceOneMilli();
|
clock.advanceOneMilli();
|
||||||
tm().transact(() -> ofy().save().entity(Cursor.create(cursorType, value, registry)).now());
|
CursorDao.saveCursor(Cursor.create(cursorType, value, registry), registry.getTldStr());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> T unmarshal(Class<T> clazz, byte[] xml) throws XmlException {
|
public static <T> T unmarshal(Class<T> clazz, byte[] xml) throws XmlException {
|
||||||
|
|
|
@ -133,6 +133,7 @@ public class RdeUploadActionTest {
|
||||||
.withTaskQueue()
|
.withTaskQueue()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final EscrowTaskRunner runner = mock(EscrowTaskRunner.class);
|
private final EscrowTaskRunner runner = mock(EscrowTaskRunner.class);
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2010-10-17TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2010-10-17TZ"));
|
||||||
|
|
|
@ -15,12 +15,23 @@
|
||||||
package google.registry.schema.cursor;
|
package google.registry.schema.cursor;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
|
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||||
|
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.common.testing.TestLogHandler;
|
||||||
import google.registry.model.common.Cursor.CursorType;
|
import google.registry.model.common.Cursor.CursorType;
|
||||||
|
import google.registry.model.registry.Registry;
|
||||||
import google.registry.model.transaction.JpaTestRules;
|
import google.registry.model.transaction.JpaTestRules;
|
||||||
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
import google.registry.model.transaction.JpaTestRules.JpaIntegrationTestRule;
|
||||||
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -32,10 +43,15 @@ public class CursorDaoTest {
|
||||||
|
|
||||||
private FakeClock fakeClock = new FakeClock();
|
private FakeClock fakeClock = new FakeClock();
|
||||||
|
|
||||||
|
private final TestLogHandler logHandler = new TestLogHandler();
|
||||||
|
private final Logger loggerToIntercept = Logger.getLogger(CursorDao.class.getCanonicalName());
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final JpaIntegrationTestRule jpaRule =
|
public final JpaIntegrationTestRule jpaRule =
|
||||||
new JpaTestRules.Builder().buildIntegrationTestRule();
|
new JpaTestRules.Builder().buildIntegrationTestRule();
|
||||||
|
|
||||||
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void save_worksSuccessfullyOnNewCursor() {
|
public void save_worksSuccessfullyOnNewCursor() {
|
||||||
Cursor cursor = Cursor.create(CursorType.BRDA, "tld", fakeClock.nowUtc());
|
Cursor cursor = Cursor.create(CursorType.BRDA, "tld", fakeClock.nowUtc());
|
||||||
|
@ -73,16 +89,30 @@ public class CursorDaoTest {
|
||||||
assertThat(returnedCursor.getCursorTime()).isEqualTo(cursor2.getCursorTime());
|
assertThat(returnedCursor.getCursorTime()).isEqualTo(cursor2.getCursorTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveAll_worksSuccessfully() {
|
||||||
|
Cursor cursor = Cursor.createGlobal(CursorType.RECURRING_BILLING, fakeClock.nowUtc());
|
||||||
|
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
||||||
|
ImmutableSet<Cursor> cursors = ImmutableSet.<Cursor>builder().add(cursor, cursor2).build();
|
||||||
|
CursorDao.saveAll(cursors);
|
||||||
|
assertThat(CursorDao.loadAll()).hasSize(2);
|
||||||
|
assertThat(CursorDao.load(CursorType.RECURRING_BILLING).getCursorTime())
|
||||||
|
.isEqualTo(cursor.getCursorTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveAll_worksSuccessfullyEmptySet() {
|
||||||
|
CursorDao.saveAll(ImmutableSet.of());
|
||||||
|
assertThat(CursorDao.loadAll()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void load_worksSuccessfully() {
|
public void load_worksSuccessfully() {
|
||||||
Cursor cursor = Cursor.createGlobal(CursorType.RECURRING_BILLING, fakeClock.nowUtc());
|
Cursor cursor = Cursor.createGlobal(CursorType.RECURRING_BILLING, fakeClock.nowUtc());
|
||||||
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
||||||
Cursor cursor3 = Cursor.create(CursorType.RDE_REPORT, "foo", fakeClock.nowUtc());
|
Cursor cursor3 = Cursor.create(CursorType.RDE_REPORT, "foo", fakeClock.nowUtc());
|
||||||
Cursor cursor4 = Cursor.create(CursorType.BRDA, "foo", fakeClock.nowUtc());
|
Cursor cursor4 = Cursor.create(CursorType.BRDA, "foo", fakeClock.nowUtc());
|
||||||
CursorDao.save(cursor);
|
CursorDao.saveAll(ImmutableSet.of(cursor, cursor2, cursor3, cursor4));
|
||||||
CursorDao.save(cursor2);
|
|
||||||
CursorDao.save(cursor3);
|
|
||||||
CursorDao.save(cursor4);
|
|
||||||
Cursor returnedCursor = CursorDao.load(CursorType.RDE_REPORT, "tld");
|
Cursor returnedCursor = CursorDao.load(CursorType.RDE_REPORT, "tld");
|
||||||
assertThat(returnedCursor.getCursorTime()).isEqualTo(cursor2.getCursorTime());
|
assertThat(returnedCursor.getCursorTime()).isEqualTo(cursor2.getCursorTime());
|
||||||
returnedCursor = CursorDao.load(CursorType.BRDA, "foo");
|
returnedCursor = CursorDao.load(CursorType.BRDA, "foo");
|
||||||
|
@ -97,10 +127,7 @@ public class CursorDaoTest {
|
||||||
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
||||||
Cursor cursor3 = Cursor.create(CursorType.RDE_REPORT, "foo", fakeClock.nowUtc());
|
Cursor cursor3 = Cursor.create(CursorType.RDE_REPORT, "foo", fakeClock.nowUtc());
|
||||||
Cursor cursor4 = Cursor.create(CursorType.BRDA, "foo", fakeClock.nowUtc());
|
Cursor cursor4 = Cursor.create(CursorType.BRDA, "foo", fakeClock.nowUtc());
|
||||||
CursorDao.save(cursor);
|
CursorDao.saveAll(ImmutableSet.of(cursor, cursor2, cursor3, cursor4));
|
||||||
CursorDao.save(cursor2);
|
|
||||||
CursorDao.save(cursor3);
|
|
||||||
CursorDao.save(cursor4);
|
|
||||||
List<Cursor> returnedCursors = CursorDao.loadAll();
|
List<Cursor> returnedCursors = CursorDao.loadAll();
|
||||||
assertThat(returnedCursors.size()).isEqualTo(4);
|
assertThat(returnedCursors.size()).isEqualTo(4);
|
||||||
}
|
}
|
||||||
|
@ -117,10 +144,7 @@ public class CursorDaoTest {
|
||||||
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
Cursor cursor2 = Cursor.create(CursorType.RDE_REPORT, "tld", fakeClock.nowUtc());
|
||||||
Cursor cursor3 = Cursor.create(CursorType.RDE_REPORT, "foo", fakeClock.nowUtc());
|
Cursor cursor3 = Cursor.create(CursorType.RDE_REPORT, "foo", fakeClock.nowUtc());
|
||||||
Cursor cursor4 = Cursor.create(CursorType.BRDA, "foo", fakeClock.nowUtc());
|
Cursor cursor4 = Cursor.create(CursorType.BRDA, "foo", fakeClock.nowUtc());
|
||||||
CursorDao.save(cursor);
|
CursorDao.saveAll(ImmutableSet.of(cursor, cursor2, cursor3, cursor4));
|
||||||
CursorDao.save(cursor2);
|
|
||||||
CursorDao.save(cursor3);
|
|
||||||
CursorDao.save(cursor4);
|
|
||||||
List<Cursor> returnedCursors = CursorDao.loadByType(CursorType.RDE_REPORT);
|
List<Cursor> returnedCursors = CursorDao.loadByType(CursorType.RDE_REPORT);
|
||||||
assertThat(returnedCursors.size()).isEqualTo(2);
|
assertThat(returnedCursors.size()).isEqualTo(2);
|
||||||
}
|
}
|
||||||
|
@ -130,4 +154,109 @@ public class CursorDaoTest {
|
||||||
List<Cursor> returnedCursors = CursorDao.loadByType(CursorType.RDE_REPORT);
|
List<Cursor> returnedCursors = CursorDao.loadByType(CursorType.RDE_REPORT);
|
||||||
assertThat(returnedCursors.size()).isEqualTo(0);
|
assertThat(returnedCursors.size()).isEqualTo(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveCursor_worksSuccessfully() {
|
||||||
|
createTld("tld");
|
||||||
|
google.registry.model.common.Cursor cursor =
|
||||||
|
google.registry.model.common.Cursor.create(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, fakeClock.nowUtc(), Registry.get("tld"));
|
||||||
|
CursorDao.saveCursor(cursor, "tld");
|
||||||
|
Cursor createdCursor = CursorDao.load(CursorType.ICANN_UPLOAD_ACTIVITY, "tld");
|
||||||
|
google.registry.model.common.Cursor dataStoreCursor =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.key(
|
||||||
|
google.registry.model.common.Cursor.createKey(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("tld")))
|
||||||
|
.now();
|
||||||
|
assertThat(createdCursor.getCursorTime()).isEqualTo(cursor.getCursorTime());
|
||||||
|
assertThat(cursor).isEqualTo(dataStoreCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveCursor_worksSuccessfullyOnGlobalCursor() {
|
||||||
|
google.registry.model.common.Cursor cursor =
|
||||||
|
google.registry.model.common.Cursor.createGlobal(
|
||||||
|
CursorType.RECURRING_BILLING, fakeClock.nowUtc());
|
||||||
|
CursorDao.saveCursor(cursor, Cursor.GLOBAL);
|
||||||
|
Cursor createdCursor = CursorDao.load(CursorType.RECURRING_BILLING);
|
||||||
|
google.registry.model.common.Cursor dataStoreCursor =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.key(google.registry.model.common.Cursor.createGlobalKey(CursorType.RECURRING_BILLING))
|
||||||
|
.now();
|
||||||
|
assertThat(createdCursor.getCursorTime()).isEqualTo(cursor.getCursorTime());
|
||||||
|
assertThat(cursor).isEqualTo(dataStoreCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveCursor_logsErrorWhenSaveToCloudSqlFails() {
|
||||||
|
loggerToIntercept.addHandler(logHandler);
|
||||||
|
createTld("tld");
|
||||||
|
google.registry.model.common.Cursor cursor =
|
||||||
|
google.registry.model.common.Cursor.create(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, fakeClock.nowUtc(), Registry.get("tld"));
|
||||||
|
CursorDao.saveCursor(cursor, null);
|
||||||
|
assertAboutLogs()
|
||||||
|
.that(logHandler)
|
||||||
|
.hasLogAtLevelWithMessage(Level.SEVERE, "Error saving cursor to Cloud SQL.");
|
||||||
|
google.registry.model.common.Cursor dataStoreCursor =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.key(
|
||||||
|
google.registry.model.common.Cursor.createKey(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("tld")))
|
||||||
|
.now();
|
||||||
|
assertThat(cursor).isEqualTo(dataStoreCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void saveCursors_worksSuccessfully() {
|
||||||
|
createTlds("tld", "foo");
|
||||||
|
google.registry.model.common.Cursor cursor1 =
|
||||||
|
google.registry.model.common.Cursor.create(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, fakeClock.nowUtc(), Registry.get("tld"));
|
||||||
|
google.registry.model.common.Cursor cursor2 =
|
||||||
|
google.registry.model.common.Cursor.create(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, fakeClock.nowUtc(), Registry.get("foo"));
|
||||||
|
google.registry.model.common.Cursor cursor3 =
|
||||||
|
google.registry.model.common.Cursor.createGlobal(
|
||||||
|
CursorType.RECURRING_BILLING, fakeClock.nowUtc());
|
||||||
|
ImmutableMap<google.registry.model.common.Cursor, String> cursors =
|
||||||
|
ImmutableMap.<google.registry.model.common.Cursor, String>builder()
|
||||||
|
.put(cursor1, "tld")
|
||||||
|
.put(cursor2, "foo")
|
||||||
|
.put(cursor3, Cursor.GLOBAL)
|
||||||
|
.build();
|
||||||
|
CursorDao.saveCursors(cursors);
|
||||||
|
Cursor createdCursor1 = CursorDao.load(CursorType.ICANN_UPLOAD_ACTIVITY, "tld");
|
||||||
|
google.registry.model.common.Cursor dataStoreCursor1 =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.key(
|
||||||
|
google.registry.model.common.Cursor.createKey(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("tld")))
|
||||||
|
.now();
|
||||||
|
assertThat(createdCursor1.getCursorTime()).isEqualTo(cursor1.getCursorTime());
|
||||||
|
assertThat(cursor1).isEqualTo(dataStoreCursor1);
|
||||||
|
Cursor createdCursor2 = CursorDao.load(CursorType.ICANN_UPLOAD_ACTIVITY, "foo");
|
||||||
|
google.registry.model.common.Cursor dataStoreCursor2 =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.key(
|
||||||
|
google.registry.model.common.Cursor.createKey(
|
||||||
|
CursorType.ICANN_UPLOAD_ACTIVITY, Registry.get("foo")))
|
||||||
|
.now();
|
||||||
|
assertThat(createdCursor2.getCursorTime()).isEqualTo(cursor2.getCursorTime());
|
||||||
|
assertThat(cursor2).isEqualTo(dataStoreCursor2);
|
||||||
|
Cursor createdCursor3 = CursorDao.load(CursorType.RECURRING_BILLING);
|
||||||
|
google.registry.model.common.Cursor dataStoreCursor3 =
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.key(google.registry.model.common.Cursor.createGlobalKey(CursorType.RECURRING_BILLING))
|
||||||
|
.now();
|
||||||
|
assertThat(createdCursor3.getCursorTime()).isEqualTo(cursor3.getCursorTime());
|
||||||
|
assertThat(cursor3).isEqualTo(dataStoreCursor3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@ public class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsComma
|
||||||
runCommandForced("--type=brda", "--timestamp=1984-12-18T00:00:00Z", "foo");
|
runCommandForced("--type=brda", "--timestamp=1984-12-18T00:00:00Z", "foo");
|
||||||
assertThat(ofy().load().key(Cursor.createKey(CursorType.BRDA, registry)).now().getCursorTime())
|
assertThat(ofy().load().key(Cursor.createKey(CursorType.BRDA, registry)).now().getCursorTime())
|
||||||
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
||||||
|
String changes = command.prompt();
|
||||||
|
assertThat(changes)
|
||||||
|
.isEqualTo("Change cursorTime of BRDA for Scope:foo to 1984-12-18T00:00:00.000Z\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void doGlobalUpdateTest() throws Exception {
|
void doGlobalUpdateTest() throws Exception {
|
||||||
|
@ -55,6 +58,11 @@ public class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsComma
|
||||||
.now()
|
.now()
|
||||||
.getCursorTime())
|
.getCursorTime())
|
||||||
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
||||||
|
String changes = command.prompt();
|
||||||
|
assertThat(changes)
|
||||||
|
.isEqualTo(
|
||||||
|
"Change cursorTime of RECURRING_BILLING for Scope:GLOBAL to"
|
||||||
|
+ " 1984-12-18T00:00:00.000Z\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -94,6 +102,11 @@ public class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsComma
|
||||||
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
||||||
assertThat(ofy().load().key(Cursor.createKey(CursorType.BRDA, registry2)).now().getCursorTime())
|
assertThat(ofy().load().key(Cursor.createKey(CursorType.BRDA, registry2)).now().getCursorTime())
|
||||||
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
||||||
|
String changes = command.prompt();
|
||||||
|
assertThat(changes)
|
||||||
|
.isEqualTo(
|
||||||
|
"Change cursorTime of BRDA for Scope:foo to 1984-12-18T00:00:00.000Z\n"
|
||||||
|
+ "Change cursorTime of BRDA for Scope:bar to 1984-12-18T00:00:00.000Z\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -107,6 +120,11 @@ public class UpdateCursorsCommandTest extends CommandTestCase<UpdateCursorsComma
|
||||||
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
||||||
assertThat(ofy().load().key(Cursor.createKey(CursorType.BRDA, registry2)).now().getCursorTime())
|
assertThat(ofy().load().key(Cursor.createKey(CursorType.BRDA, registry2)).now().getCursorTime())
|
||||||
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
.isEqualTo(DateTime.parse("1984-12-18TZ"));
|
||||||
|
String changes = command.prompt();
|
||||||
|
assertThat(changes)
|
||||||
|
.isEqualTo(
|
||||||
|
"Change cursorTime of BRDA for Scope:foo to 1984-12-18T00:00:00.000Z\n"
|
||||||
|
+ "Change cursorTime of BRDA for Scope:bar to 1984-12-18T00:00:00.000Z\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue