mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 12:07:51 +02:00
Daggerize/Actionize the load snapshot servlet
This is needed to eliminate the last non-injected use of BigqueryFactory. It gets rid of the deprecated HttpServletUtils now that we don't have lots of separate servlets, and changes the check snapshot servlet's usage of such. It also fixes up some related minor style issues in the update snapshot action (and its injectable parameters). ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=120547998
This commit is contained in:
parent
9e7934684e
commit
d65bf2a714
13 changed files with 248 additions and 419 deletions
|
@ -59,7 +59,7 @@ public class BigqueryFactory {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Subfactory subfactory = new Subfactory();
|
Subfactory subfactory = new Subfactory();
|
||||||
|
|
||||||
@Inject public BigqueryFactory() {}
|
@Inject BigqueryFactory() {}
|
||||||
|
|
||||||
/** This class is broken out solely so that it can be mocked inside of tests. */
|
/** This class is broken out solely so that it can be mocked inside of tests. */
|
||||||
static class Subfactory {
|
static class Subfactory {
|
||||||
|
|
|
@ -51,20 +51,6 @@ public interface RegistryConfig {
|
||||||
*/
|
*/
|
||||||
public String getDomainListsBucket();
|
public String getDomainListsBucket();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the BigQuery dataset for storing directly imported datastore snapshots.
|
|
||||||
*
|
|
||||||
* @see com.google.domain.registry.export.LoadSnapshotServlet
|
|
||||||
*/
|
|
||||||
public String getSnapshotsDataset();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the BigQuery dataset for storing views pointing to the latest datastore snapshot.
|
|
||||||
*
|
|
||||||
* @see com.google.domain.registry.export.UpdateSnapshotViewAction
|
|
||||||
*/
|
|
||||||
public String getLatestSnapshotDataset();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Number of sharded commit log buckets.
|
* Number of sharded commit log buckets.
|
||||||
*
|
*
|
||||||
|
|
|
@ -57,16 +57,6 @@ public class TestRegistryConfig implements RegistryConfig {
|
||||||
return getProjectId() + "-domain-lists";
|
return getProjectId() + "-domain-lists";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getSnapshotsDataset() {
|
|
||||||
return "snapshots";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getLatestSnapshotDataset() {
|
|
||||||
return "latest_snapshot";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getCommitsBucket() {
|
public String getCommitsBucket() {
|
||||||
return getProjectId() + "-commits";
|
return getProjectId() + "-commits";
|
||||||
|
|
|
@ -15,8 +15,11 @@
|
||||||
package com.google.domain.registry.export;
|
package com.google.domain.registry.export;
|
||||||
|
|
||||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||||
|
import static com.google.common.collect.Sets.intersection;
|
||||||
import static com.google.common.html.HtmlEscapers.htmlEscaper;
|
import static com.google.common.html.HtmlEscapers.htmlEscaper;
|
||||||
import static com.google.domain.registry.util.HttpServletUtils.getRequiredParameterValue;
|
import static com.google.domain.registry.export.LoadSnapshotAction.enqueueLoadSnapshotTask;
|
||||||
|
import static com.google.domain.registry.request.RequestParameters.extractRequiredParameter;
|
||||||
|
import static com.google.domain.registry.util.FormattingLogger.getLoggerForCallerClass;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||||
|
@ -28,12 +31,12 @@ import com.google.appengine.api.taskqueue.TaskHandle;
|
||||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Optional;
|
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.net.MediaType;
|
import com.google.common.net.MediaType;
|
||||||
import com.google.domain.registry.export.DatastoreBackupInfo.BackupStatus;
|
import com.google.domain.registry.export.DatastoreBackupInfo.BackupStatus;
|
||||||
|
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||||
import com.google.domain.registry.util.FormattingLogger;
|
import com.google.domain.registry.util.FormattingLogger;
|
||||||
import com.google.domain.registry.util.NonFinalForTesting;
|
import com.google.domain.registry.util.NonFinalForTesting;
|
||||||
|
|
||||||
|
@ -42,6 +45,7 @@ import org.joda.time.PeriodType;
|
||||||
import org.joda.time.format.PeriodFormat;
|
import org.joda.time.format.PeriodFormat;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.servlet.http.HttpServlet;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -62,14 +66,11 @@ public class CheckSnapshotServlet extends HttpServlet {
|
||||||
/** The maximum amount of time we allow a backup to run before abandoning it. */
|
/** The maximum amount of time we allow a backup to run before abandoning it. */
|
||||||
static final Duration MAXIMUM_BACKUP_RUNNING_TIME = Duration.standardHours(20);
|
static final Duration MAXIMUM_BACKUP_RUNNING_TIME = Duration.standardHours(20);
|
||||||
|
|
||||||
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
private static final FormattingLogger logger = getLoggerForCallerClass();
|
||||||
|
|
||||||
@NonFinalForTesting
|
@NonFinalForTesting
|
||||||
private static DatastoreBackupService backupService = DatastoreBackupService.get();
|
private static DatastoreBackupService backupService = DatastoreBackupService.get();
|
||||||
|
|
||||||
@NonFinalForTesting
|
|
||||||
private static LoadSnapshotServlet loadSnapshotServlet = new LoadSnapshotServlet();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void service(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
public void service(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
||||||
try {
|
try {
|
||||||
|
@ -87,18 +88,27 @@ public class CheckSnapshotServlet extends HttpServlet {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
public void doGet(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
||||||
String snapshotName = getRequiredParameterValue(req, SNAPSHOT_NAME_PARAM);
|
// TODO(b/28266757): Remove this try/catch/rethrow block once this servlet is Daggerized.
|
||||||
|
try {
|
||||||
|
String snapshotName = extractRequiredParameter(req, SNAPSHOT_NAME_PARAM);
|
||||||
rsp.getWriter().write(backupService.findByName(snapshotName).getInformation());
|
rsp.getWriter().write(backupService.findByName(snapshotName).getInformation());
|
||||||
|
} catch (BadRequestException e) {
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
||||||
String snapshotName = getRequiredParameterValue(req, SNAPSHOT_NAME_PARAM);
|
String snapshotName;
|
||||||
// TODO(b/19237926): make this non-optional once all new tasks will have this parameter.
|
String kindsToLoadParam;
|
||||||
String kindsToLoadParam = req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM);
|
// TODO(b/28266757): Remove this try/catch/rethrow block once this servlet is Daggerized.
|
||||||
Optional<ImmutableSet<String>> kindsToLoad = Optional.fromNullable(
|
try {
|
||||||
kindsToLoadParam == null ? null
|
snapshotName = extractRequiredParameter(req, SNAPSHOT_NAME_PARAM);
|
||||||
: ImmutableSet.copyOf(Splitter.on(',').split(kindsToLoadParam)));
|
kindsToLoadParam = extractRequiredParameter(req, SNAPSHOT_KINDS_TO_LOAD_PARAM);
|
||||||
|
} catch (BadRequestException e) {
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
|
}
|
||||||
|
Set<String> kindsToLoad = ImmutableSet.copyOf(Splitter.on(',').split(kindsToLoadParam));
|
||||||
|
|
||||||
// Look up the backup by the provided name, stopping if we can't find it.
|
// Look up the backup by the provided name, stopping if we can't find it.
|
||||||
DatastoreBackupInfo backup;
|
DatastoreBackupInfo backup;
|
||||||
|
@ -137,21 +147,20 @@ public class CheckSnapshotServlet extends HttpServlet {
|
||||||
String snapshotId = snapshotName.startsWith(ExportSnapshotServlet.SNAPSHOT_PREFIX)
|
String snapshotId = snapshotName.startsWith(ExportSnapshotServlet.SNAPSHOT_PREFIX)
|
||||||
? snapshotName.substring(ExportSnapshotServlet.SNAPSHOT_PREFIX.length())
|
? snapshotName.substring(ExportSnapshotServlet.SNAPSHOT_PREFIX.length())
|
||||||
: backup.getStartTime().toString("YYYYMMdd_HHmmss");
|
: backup.getStartTime().toString("YYYYMMdd_HHmmss");
|
||||||
// Log a warning if kindsToLoad is specified and not a subset of the exported snapshot kinds.
|
// Log a warning if kindsToLoad is not a subset of the exported snapshot kinds.
|
||||||
if (kindsToLoad.isPresent() && !backup.getKinds().containsAll(kindsToLoad.get())) {
|
if (!backup.getKinds().containsAll(kindsToLoad)) {
|
||||||
logger.warningfmt("Kinds to load included non-exported kinds: %s",
|
logger.warningfmt(
|
||||||
Sets.difference(kindsToLoad.get(), backup.getKinds()));
|
"Kinds to load included non-exported kinds: %s",
|
||||||
|
Sets.difference(kindsToLoad, backup.getKinds()));
|
||||||
}
|
}
|
||||||
// Load kinds from the snapshot, limited to those also in kindsToLoad (if it's present).
|
// Load kinds from the snapshot, limited to those also in kindsToLoad (if it's present).
|
||||||
ImmutableSet<String> exportedKindsToLoad = ImmutableSet.copyOf(kindsToLoad.isPresent()
|
ImmutableSet<String> exportedKindsToLoad =
|
||||||
? Sets.intersection(backup.getKinds(), kindsToLoad.get())
|
ImmutableSet.copyOf(intersection(backup.getKinds(), kindsToLoad));
|
||||||
: backup.getKinds());
|
|
||||||
String message = String.format("Datastore backup %s complete - ", snapshotName);
|
String message = String.format("Datastore backup %s complete - ", snapshotName);
|
||||||
if (exportedKindsToLoad.isEmpty()) {
|
if (exportedKindsToLoad.isEmpty()) {
|
||||||
message += "no kinds to load into BigQuery";
|
message += "no kinds to load into BigQuery";
|
||||||
} else {
|
} else {
|
||||||
loadSnapshotServlet.enqueueLoadTask(
|
enqueueLoadSnapshotTask(snapshotId, backup.getGcsFilename().get(), exportedKindsToLoad);
|
||||||
snapshotId, backup.getGcsFilename().get(), exportedKindsToLoad);
|
|
||||||
message += "BigQuery load task enqueued";
|
message += "BigQuery load task enqueued";
|
||||||
}
|
}
|
||||||
logger.info(message);
|
logger.info(message);
|
||||||
|
|
|
@ -17,9 +17,12 @@ package com.google.domain.registry.export;
|
||||||
import static com.google.domain.registry.export.BigqueryPollJobAction.CHAINED_TASK_QUEUE_HEADER;
|
import static com.google.domain.registry.export.BigqueryPollJobAction.CHAINED_TASK_QUEUE_HEADER;
|
||||||
import static com.google.domain.registry.export.BigqueryPollJobAction.JOB_ID_HEADER;
|
import static com.google.domain.registry.export.BigqueryPollJobAction.JOB_ID_HEADER;
|
||||||
import static com.google.domain.registry.export.BigqueryPollJobAction.PROJECT_ID_HEADER;
|
import static com.google.domain.registry.export.BigqueryPollJobAction.PROJECT_ID_HEADER;
|
||||||
import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_DATASET_ID_PARAM;
|
import static com.google.domain.registry.export.LoadSnapshotAction.LOAD_SNAPSHOT_FILE_PARAM;
|
||||||
import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_KIND_PARAM;
|
import static com.google.domain.registry.export.LoadSnapshotAction.LOAD_SNAPSHOT_ID_PARAM;
|
||||||
import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_TABLE_ID_PARAM;
|
import static com.google.domain.registry.export.LoadSnapshotAction.LOAD_SNAPSHOT_KINDS_PARAM;
|
||||||
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.UPDATE_SNAPSHOT_DATASET_ID_PARAM;
|
||||||
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.UPDATE_SNAPSHOT_KIND_PARAM;
|
||||||
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.UPDATE_SNAPSHOT_TABLE_ID_PARAM;
|
||||||
import static com.google.domain.registry.request.RequestParameters.extractRequiredHeader;
|
import static com.google.domain.registry.request.RequestParameters.extractRequiredHeader;
|
||||||
|
|
||||||
import com.google.domain.registry.request.Header;
|
import com.google.domain.registry.request.Header;
|
||||||
|
@ -35,21 +38,39 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
public final class ExportRequestModule {
|
public final class ExportRequestModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Parameter(SNAPSHOT_DATASET_ID_PARAM)
|
@Parameter(UPDATE_SNAPSHOT_DATASET_ID_PARAM)
|
||||||
static String provideDatasetId(HttpServletRequest req) {
|
static String provideUpdateSnapshotDatasetId(HttpServletRequest req) {
|
||||||
return extractRequiredHeader(req, SNAPSHOT_DATASET_ID_PARAM);
|
return extractRequiredHeader(req, UPDATE_SNAPSHOT_DATASET_ID_PARAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Parameter(SNAPSHOT_TABLE_ID_PARAM)
|
@Parameter(UPDATE_SNAPSHOT_TABLE_ID_PARAM)
|
||||||
static String provideTableId(HttpServletRequest req) {
|
static String provideUpdateSnapshotTableId(HttpServletRequest req) {
|
||||||
return extractRequiredHeader(req, SNAPSHOT_TABLE_ID_PARAM);
|
return extractRequiredHeader(req, UPDATE_SNAPSHOT_TABLE_ID_PARAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Parameter(SNAPSHOT_KIND_PARAM)
|
@Parameter(UPDATE_SNAPSHOT_KIND_PARAM)
|
||||||
static String provideKind(HttpServletRequest req) {
|
static String provideUpdateSnapshotKind(HttpServletRequest req) {
|
||||||
return extractRequiredHeader(req, SNAPSHOT_KIND_PARAM);
|
return extractRequiredHeader(req, UPDATE_SNAPSHOT_KIND_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter(LOAD_SNAPSHOT_FILE_PARAM)
|
||||||
|
static String provideLoadSnapshotFile(HttpServletRequest req) {
|
||||||
|
return extractRequiredHeader(req, LOAD_SNAPSHOT_FILE_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter(LOAD_SNAPSHOT_ID_PARAM)
|
||||||
|
static String provideLoadSnapshotId(HttpServletRequest req) {
|
||||||
|
return extractRequiredHeader(req, LOAD_SNAPSHOT_ID_PARAM);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter(LOAD_SNAPSHOT_KINDS_PARAM)
|
||||||
|
static String provideLoadSnapshotKinds(HttpServletRequest req) {
|
||||||
|
return extractRequiredHeader(req, LOAD_SNAPSHOT_KINDS_PARAM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
@ -14,27 +14,19 @@
|
||||||
|
|
||||||
package com.google.domain.registry.export;
|
package com.google.domain.registry.export;
|
||||||
|
|
||||||
|
import static com.google.appengine.api.taskqueue.QueueFactory.getQueue;
|
||||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.html.HtmlEscapers.htmlEscaper;
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.createViewUpdateTask;
|
||||||
import static com.google.domain.registry.util.HttpServletUtils.getRequiredParameterValue;
|
import static com.google.domain.registry.request.Action.Method.POST;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
import static com.google.domain.registry.util.FormattingLogger.getLoggerForCallerClass;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
|
||||||
|
|
||||||
import com.google.api.client.extensions.appengine.http.UrlFetchTransport;
|
|
||||||
import com.google.api.client.googleapis.extensions.appengine.auth.oauth2.AppIdentityCredential;
|
|
||||||
import com.google.api.client.json.jackson2.JacksonFactory;
|
|
||||||
import com.google.api.services.bigquery.Bigquery;
|
import com.google.api.services.bigquery.Bigquery;
|
||||||
import com.google.api.services.bigquery.BigqueryScopes;
|
|
||||||
import com.google.api.services.bigquery.model.Dataset;
|
|
||||||
import com.google.api.services.bigquery.model.DatasetReference;
|
|
||||||
import com.google.api.services.bigquery.model.Job;
|
import com.google.api.services.bigquery.model.Job;
|
||||||
import com.google.api.services.bigquery.model.JobConfiguration;
|
import com.google.api.services.bigquery.model.JobConfiguration;
|
||||||
import com.google.api.services.bigquery.model.JobConfigurationLoad;
|
import com.google.api.services.bigquery.model.JobConfigurationLoad;
|
||||||
import com.google.api.services.bigquery.model.JobReference;
|
import com.google.api.services.bigquery.model.JobReference;
|
||||||
import com.google.api.services.bigquery.model.TableReference;
|
import com.google.api.services.bigquery.model.TableReference;
|
||||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
|
||||||
import com.google.appengine.api.taskqueue.TaskHandle;
|
import com.google.appengine.api.taskqueue.TaskHandle;
|
||||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||||
|
@ -42,99 +34,82 @@ import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.net.MediaType;
|
|
||||||
import com.google.domain.registry.bigquery.BigqueryFactory;
|
import com.google.domain.registry.bigquery.BigqueryFactory;
|
||||||
import com.google.domain.registry.bigquery.BigqueryJobFailureException;
|
|
||||||
import com.google.domain.registry.bigquery.BigqueryUtils.SourceFormat;
|
import com.google.domain.registry.bigquery.BigqueryUtils.SourceFormat;
|
||||||
import com.google.domain.registry.bigquery.BigqueryUtils.WriteDisposition;
|
import com.google.domain.registry.bigquery.BigqueryUtils.WriteDisposition;
|
||||||
import com.google.domain.registry.config.RegistryEnvironment;
|
import com.google.domain.registry.config.ConfigModule.Config;
|
||||||
import com.google.domain.registry.export.BigqueryPollJobAction.BigqueryPollJobEnqueuer;
|
import com.google.domain.registry.export.BigqueryPollJobAction.BigqueryPollJobEnqueuer;
|
||||||
|
import com.google.domain.registry.request.Action;
|
||||||
|
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||||
|
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
||||||
|
import com.google.domain.registry.request.Parameter;
|
||||||
import com.google.domain.registry.util.Clock;
|
import com.google.domain.registry.util.Clock;
|
||||||
import com.google.domain.registry.util.FormattingLogger;
|
import com.google.domain.registry.util.FormattingLogger;
|
||||||
import com.google.domain.registry.util.NonFinalForTesting;
|
|
||||||
import com.google.domain.registry.util.Retrier;
|
|
||||||
import com.google.domain.registry.util.SystemClock;
|
|
||||||
import com.google.domain.registry.util.SystemSleeper;
|
|
||||||
import com.google.domain.registry.util.TaskEnqueuer;
|
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServlet;
|
import javax.inject.Inject;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/** Load a datastore snapshot from Google Cloud Storage into BigQuery. */
|
/** Action to load a Datastore snapshot from Google Cloud Storage into BigQuery. */
|
||||||
public class LoadSnapshotServlet extends HttpServlet {
|
@Action(path = LoadSnapshotAction.PATH, method = POST)
|
||||||
|
public class LoadSnapshotAction implements Runnable {
|
||||||
private static final RegistryEnvironment ENVIRONMENT = RegistryEnvironment.get();
|
|
||||||
|
|
||||||
/** Parameter names for passing parameters into the servlet. */
|
/** Parameter names for passing parameters into the servlet. */
|
||||||
static final String SNAPSHOT_ID_PARAM = "id";
|
static final String LOAD_SNAPSHOT_ID_PARAM = "id";
|
||||||
static final String SNAPSHOT_FILE_PARAM = "file";
|
static final String LOAD_SNAPSHOT_FILE_PARAM = "file";
|
||||||
static final String SNAPSHOT_KINDS_PARAM = "kinds";
|
static final String LOAD_SNAPSHOT_KINDS_PARAM = "kinds";
|
||||||
|
|
||||||
|
static final String SNAPSHOTS_DATASET = "snapshots";
|
||||||
|
|
||||||
/** Servlet-specific details needed for enqueuing tasks against itself. */
|
/** Servlet-specific details needed for enqueuing tasks against itself. */
|
||||||
static final String QUEUE = "export-snapshot"; // See queue.xml.
|
static final String QUEUE = "export-snapshot"; // See queue.xml.
|
||||||
static final String PATH = "/_dr/task/loadSnapshot"; // See web.xml.
|
static final String PATH = "/_dr/task/loadSnapshot"; // See web.xml.
|
||||||
|
|
||||||
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
private static final FormattingLogger logger = getLoggerForCallerClass();
|
||||||
|
|
||||||
@NonFinalForTesting
|
@Inject BigqueryFactory bigqueryFactory;
|
||||||
private static Clock clock = new SystemClock();
|
@Inject BigqueryPollJobEnqueuer bigqueryPollEnqueuer;
|
||||||
|
@Inject Clock clock;
|
||||||
|
@Inject @Config("projectId") String projectId;
|
||||||
|
@Inject @Parameter(LOAD_SNAPSHOT_FILE_PARAM) String snapshotFile;
|
||||||
|
@Inject @Parameter(LOAD_SNAPSHOT_ID_PARAM) String snapshotId;
|
||||||
|
@Inject @Parameter(LOAD_SNAPSHOT_KINDS_PARAM) String snapshotKinds;
|
||||||
|
@Inject LoadSnapshotAction() {}
|
||||||
|
|
||||||
@NonFinalForTesting
|
/** Enqueue a task for starting a backup load. */
|
||||||
private static BigqueryFactory bigqueryFactory = new BigqueryFactory();
|
public static TaskHandle enqueueLoadSnapshotTask(
|
||||||
|
|
||||||
@NonFinalForTesting
|
|
||||||
private static BigqueryPollJobEnqueuer bigqueryPollEnqueuer = new BigqueryPollJobEnqueuer(
|
|
||||||
new TaskEnqueuer(new Retrier(new SystemSleeper(), 5)));
|
|
||||||
|
|
||||||
/** Enqueue a task for starting a backup load. Not static for better testability. */
|
|
||||||
public TaskHandle enqueueLoadTask(
|
|
||||||
String snapshotId, String gcsFile, ImmutableSet<String> kinds) {
|
String snapshotId, String gcsFile, ImmutableSet<String> kinds) {
|
||||||
return QueueFactory.getQueue(QUEUE).add(
|
return getQueue(QUEUE).add(
|
||||||
TaskOptions.Builder.withUrl(PATH)
|
TaskOptions.Builder.withUrl(PATH)
|
||||||
.method(Method.POST)
|
.method(Method.POST)
|
||||||
.param(SNAPSHOT_ID_PARAM, snapshotId)
|
.param(LOAD_SNAPSHOT_ID_PARAM, snapshotId)
|
||||||
.param(SNAPSHOT_FILE_PARAM, gcsFile)
|
.param(LOAD_SNAPSHOT_FILE_PARAM, gcsFile)
|
||||||
.param(SNAPSHOT_KINDS_PARAM, Joiner.on(',').join(kinds)));
|
.param(LOAD_SNAPSHOT_KINDS_PARAM, Joiner.on(',').join(kinds)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
String snapshotId = getRequiredParameterValue(req, SNAPSHOT_ID_PARAM);
|
String message =
|
||||||
String gcsFilename = getRequiredParameterValue(req, SNAPSHOT_FILE_PARAM);
|
loadSnapshot(snapshotId, snapshotFile, Splitter.on(',').split(snapshotKinds));
|
||||||
ImmutableList<String> kinds = ImmutableList.copyOf(
|
logger.infofmt("Loaded snapshot successfully: %s", message);
|
||||||
Splitter.on(',').splitToList(getRequiredParameterValue(req, SNAPSHOT_KINDS_PARAM)));
|
|
||||||
|
|
||||||
String message = loadSnapshot(snapshotId, gcsFilename, kinds);
|
|
||||||
|
|
||||||
rsp.setStatus(SC_OK);
|
|
||||||
rsp.setContentType(MediaType.PLAIN_TEXT_UTF_8.toString());
|
|
||||||
rsp.getWriter().write("OK\n\n" + message);
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
logger.severe(e, e.toString());
|
logger.severe(e, "Error loading snapshot");
|
||||||
rsp.sendError(
|
if (e instanceof IllegalArgumentException) {
|
||||||
e instanceof IllegalArgumentException ? SC_BAD_REQUEST : SC_INTERNAL_SERVER_ERROR,
|
throw new BadRequestException("Error calling load snapshot: " + e.getMessage(), e);
|
||||||
htmlEscaper().escape(firstNonNull(e.getMessage(), e.toString())));
|
} else {
|
||||||
|
throw new InternalServerErrorException(
|
||||||
|
"Error loading snapshot: " + firstNonNull(e.getMessage(), e.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String loadSnapshot(String snapshotId, String gcsFilename, ImmutableList<String> kinds)
|
private String loadSnapshot(String snapshotId, String gcsFilename, Iterable<String> kinds)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
Bigquery bigquery = bigqueryFactory.create(
|
Bigquery bigquery = bigqueryFactory.create(projectId, SNAPSHOTS_DATASET);
|
||||||
getClass().getSimpleName(),
|
|
||||||
new UrlFetchTransport(),
|
|
||||||
new JacksonFactory(),
|
|
||||||
new AppIdentityCredential(BigqueryScopes.all()));
|
|
||||||
String projectId = ENVIRONMENT.config().getProjectId();
|
|
||||||
DateTime now = clock.nowUtc();
|
DateTime now = clock.nowUtc();
|
||||||
|
|
||||||
ensureDataset(bigquery, projectId, ENVIRONMENT.config().getSnapshotsDataset());
|
|
||||||
|
|
||||||
String loadMessage =
|
String loadMessage =
|
||||||
String.format("Loading datastore snapshot %s from %s...", snapshotId, gcsFilename);
|
String.format("Loading datastore snapshot %s from %s...", snapshotId, gcsFilename);
|
||||||
logger.info(loadMessage);
|
logger.info(loadMessage);
|
||||||
|
@ -155,9 +130,8 @@ public class LoadSnapshotServlet extends HttpServlet {
|
||||||
// well-known view in BigQuery to point at the newly loaded snapshot table for this kind.
|
// well-known view in BigQuery to point at the newly loaded snapshot table for this kind.
|
||||||
bigqueryPollEnqueuer.enqueuePollTask(
|
bigqueryPollEnqueuer.enqueuePollTask(
|
||||||
jobRef,
|
jobRef,
|
||||||
UpdateSnapshotViewAction.createViewUpdateTask(
|
createViewUpdateTask(SNAPSHOTS_DATASET, tableId, kindName),
|
||||||
ENVIRONMENT.config().getSnapshotsDataset(), tableId, kindName),
|
getQueue(UpdateSnapshotViewAction.QUEUE));
|
||||||
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
|
||||||
|
|
||||||
builder.append(String.format(" - %s:%s\n", projectId, jobId));
|
builder.append(String.format(" - %s:%s\n", projectId, jobId));
|
||||||
logger.infofmt("Submitted load job %s:%s", projectId, jobId);
|
logger.infofmt("Submitted load job %s:%s", projectId, jobId);
|
||||||
|
@ -165,24 +139,6 @@ public class LoadSnapshotServlet extends HttpServlet {
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ensureDataset(Bigquery bigquery, String projectId, String datasetId)
|
|
||||||
throws IOException {
|
|
||||||
try {
|
|
||||||
bigquery.datasets()
|
|
||||||
.insert(projectId,
|
|
||||||
new Dataset().setDatasetReference(
|
|
||||||
new DatasetReference()
|
|
||||||
.setProjectId(projectId)
|
|
||||||
.setDatasetId(datasetId)))
|
|
||||||
.execute();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// Swallow errors about a duplicate dataset, and throw any other ones.
|
|
||||||
if (!BigqueryJobFailureException.create(e).getReason().equals("duplicate")) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String getBackupInfoFileForKind(String backupInfoFile, String kindName) {
|
private static String getBackupInfoFileForKind(String backupInfoFile, String kindName) {
|
||||||
String extension = ".backup_info";
|
String extension = ".backup_info";
|
||||||
checkArgument(backupInfoFile.endsWith(extension), "backup info file extension missing");
|
checkArgument(backupInfoFile.endsWith(extension), "backup info file extension missing");
|
||||||
|
@ -190,10 +146,10 @@ public class LoadSnapshotServlet extends HttpServlet {
|
||||||
return Joiner.on('.').join(prefix, kindName, extension.substring(1));
|
return Joiner.on('.').join(prefix, kindName, extension.substring(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Job makeLoadJob(JobReference jobRef, String sourceUri, String tableId) {
|
private Job makeLoadJob(JobReference jobRef, String sourceUri, String tableId) {
|
||||||
TableReference tableReference = new TableReference()
|
TableReference tableReference = new TableReference()
|
||||||
.setProjectId(jobRef.getProjectId())
|
.setProjectId(jobRef.getProjectId())
|
||||||
.setDatasetId(ENVIRONMENT.config().getSnapshotsDataset())
|
.setDatasetId(SNAPSHOTS_DATASET)
|
||||||
.setTableId(tableId);
|
.setTableId(tableId);
|
||||||
return new Job()
|
return new Job()
|
||||||
.setJobReference(jobRef)
|
.setJobReference(jobRef)
|
|
@ -23,7 +23,7 @@ import com.google.api.services.bigquery.model.ViewDefinition;
|
||||||
import com.google.appengine.api.taskqueue.TaskOptions;
|
import com.google.appengine.api.taskqueue.TaskOptions;
|
||||||
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
import com.google.appengine.api.taskqueue.TaskOptions.Method;
|
||||||
import com.google.domain.registry.bigquery.BigqueryFactory;
|
import com.google.domain.registry.bigquery.BigqueryFactory;
|
||||||
import com.google.domain.registry.config.RegistryEnvironment;
|
import com.google.domain.registry.config.ConfigModule.Config;
|
||||||
import com.google.domain.registry.request.Action;
|
import com.google.domain.registry.request.Action;
|
||||||
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
||||||
import com.google.domain.registry.request.Parameter;
|
import com.google.domain.registry.request.Parameter;
|
||||||
|
@ -38,12 +38,12 @@ import javax.inject.Inject;
|
||||||
@Action(path = UpdateSnapshotViewAction.PATH, method = POST)
|
@Action(path = UpdateSnapshotViewAction.PATH, method = POST)
|
||||||
public class UpdateSnapshotViewAction implements Runnable {
|
public class UpdateSnapshotViewAction implements Runnable {
|
||||||
|
|
||||||
private static final RegistryEnvironment ENVIRONMENT = RegistryEnvironment.get();
|
|
||||||
|
|
||||||
/** Headers for passing parameters into the servlet. */
|
/** Headers for passing parameters into the servlet. */
|
||||||
static final String SNAPSHOT_DATASET_ID_PARAM = "dataset";
|
static final String UPDATE_SNAPSHOT_DATASET_ID_PARAM = "dataset";
|
||||||
static final String SNAPSHOT_TABLE_ID_PARAM = "table";
|
static final String UPDATE_SNAPSHOT_TABLE_ID_PARAM = "table";
|
||||||
static final String SNAPSHOT_KIND_PARAM = "kind";
|
static final String UPDATE_SNAPSHOT_KIND_PARAM = "kind";
|
||||||
|
|
||||||
|
static final String LATEST_SNAPSHOT_DATASET = "latest_snapshot";
|
||||||
|
|
||||||
/** Servlet-specific details needed for enqueuing tasks against itself. */
|
/** Servlet-specific details needed for enqueuing tasks against itself. */
|
||||||
static final String QUEUE = "export-snapshot-update-view"; // See queue.xml.
|
static final String QUEUE = "export-snapshot-update-view"; // See queue.xml.
|
||||||
|
@ -51,9 +51,10 @@ public class UpdateSnapshotViewAction implements Runnable {
|
||||||
|
|
||||||
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
||||||
|
|
||||||
@Inject @Parameter(SNAPSHOT_DATASET_ID_PARAM) String datasetId;
|
@Inject @Parameter(UPDATE_SNAPSHOT_DATASET_ID_PARAM) String datasetId;
|
||||||
@Inject @Parameter(SNAPSHOT_TABLE_ID_PARAM) String tableId;
|
@Inject @Parameter(UPDATE_SNAPSHOT_TABLE_ID_PARAM) String tableId;
|
||||||
@Inject @Parameter(SNAPSHOT_KIND_PARAM) String kindName;
|
@Inject @Parameter(UPDATE_SNAPSHOT_KIND_PARAM) String kindName;
|
||||||
|
@Inject @Config("projectId") String projectId;
|
||||||
@Inject BigqueryFactory bigqueryFactory;
|
@Inject BigqueryFactory bigqueryFactory;
|
||||||
@Inject UpdateSnapshotViewAction() {}
|
@Inject UpdateSnapshotViewAction() {}
|
||||||
|
|
||||||
|
@ -62,9 +63,9 @@ public class UpdateSnapshotViewAction implements Runnable {
|
||||||
String datasetId, String tableId, String kindName) {
|
String datasetId, String tableId, String kindName) {
|
||||||
return TaskOptions.Builder.withUrl(PATH)
|
return TaskOptions.Builder.withUrl(PATH)
|
||||||
.method(Method.POST)
|
.method(Method.POST)
|
||||||
.param(SNAPSHOT_DATASET_ID_PARAM, datasetId)
|
.param(UPDATE_SNAPSHOT_DATASET_ID_PARAM, datasetId)
|
||||||
.param(SNAPSHOT_TABLE_ID_PARAM, tableId)
|
.param(UPDATE_SNAPSHOT_TABLE_ID_PARAM, tableId)
|
||||||
.param(SNAPSHOT_KIND_PARAM, kindName);
|
.param(UPDATE_SNAPSHOT_KIND_PARAM, kindName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -79,14 +80,12 @@ public class UpdateSnapshotViewAction implements Runnable {
|
||||||
|
|
||||||
private void updateSnapshotView(String datasetId, String tableId, String kindName)
|
private void updateSnapshotView(String datasetId, String tableId, String kindName)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
String projectId = ENVIRONMENT.config().getProjectId();
|
Bigquery bigquery = bigqueryFactory.create(projectId, LATEST_SNAPSHOT_DATASET);
|
||||||
Bigquery bigquery =
|
|
||||||
bigqueryFactory.create(projectId, ENVIRONMENT.config().getLatestSnapshotDataset());
|
|
||||||
|
|
||||||
updateTable(bigquery, new Table()
|
updateTable(bigquery, new Table()
|
||||||
.setTableReference(new TableReference()
|
.setTableReference(new TableReference()
|
||||||
.setProjectId(projectId)
|
.setProjectId(projectId)
|
||||||
.setDatasetId(ENVIRONMENT.config().getLatestSnapshotDataset())
|
.setDatasetId(LATEST_SNAPSHOT_DATASET)
|
||||||
.setTableId(kindName))
|
.setTableId(kindName))
|
||||||
.setView(new ViewDefinition().setQuery(
|
.setView(new ViewDefinition().setQuery(
|
||||||
SqlTemplate.create("SELECT * FROM [%DATASET%.%TABLE%]")
|
SqlTemplate.create("SELECT * FROM [%DATASET%.%TABLE%]")
|
||||||
|
@ -94,10 +93,12 @@ public class UpdateSnapshotViewAction implements Runnable {
|
||||||
.put("TABLE", tableId)
|
.put("TABLE", tableId)
|
||||||
.build())));
|
.build())));
|
||||||
|
|
||||||
String message = String.format(
|
logger.infofmt(
|
||||||
"Updated view %s:%s to point at snapshot table %s:%s.",
|
"Updated view %s:%s to point at snapshot table %s:%s.",
|
||||||
ENVIRONMENT.config().getLatestSnapshotDataset(), kindName, datasetId, tableId);
|
LATEST_SNAPSHOT_DATASET,
|
||||||
logger.info(message);
|
kindName,
|
||||||
|
datasetId,
|
||||||
|
tableId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void updateTable(Bigquery bigquery, Table table) throws IOException {
|
private static void updateTable(Bigquery bigquery, Table table) throws IOException {
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.google.domain.registry.export.BigqueryPollJobAction;
|
||||||
import com.google.domain.registry.export.ExportDomainListsAction;
|
import com.google.domain.registry.export.ExportDomainListsAction;
|
||||||
import com.google.domain.registry.export.ExportRequestModule;
|
import com.google.domain.registry.export.ExportRequestModule;
|
||||||
import com.google.domain.registry.export.ExportReservedTermsAction;
|
import com.google.domain.registry.export.ExportReservedTermsAction;
|
||||||
|
import com.google.domain.registry.export.LoadSnapshotAction;
|
||||||
import com.google.domain.registry.export.SyncGroupMembersAction;
|
import com.google.domain.registry.export.SyncGroupMembersAction;
|
||||||
import com.google.domain.registry.export.UpdateSnapshotViewAction;
|
import com.google.domain.registry.export.UpdateSnapshotViewAction;
|
||||||
import com.google.domain.registry.export.sheet.SheetModule;
|
import com.google.domain.registry.export.sheet.SheetModule;
|
||||||
|
@ -89,6 +90,7 @@ interface BackendRequestComponent {
|
||||||
ExportCommitLogDiffAction exportCommitLogDiffAction();
|
ExportCommitLogDiffAction exportCommitLogDiffAction();
|
||||||
ExportDomainListsAction exportDomainListsAction();
|
ExportDomainListsAction exportDomainListsAction();
|
||||||
ExportReservedTermsAction exportReservedTermsAction();
|
ExportReservedTermsAction exportReservedTermsAction();
|
||||||
|
LoadSnapshotAction loadSnapshotAction();
|
||||||
MetricsExportAction metricsExportAction();
|
MetricsExportAction metricsExportAction();
|
||||||
NordnUploadAction nordnUploadAction();
|
NordnUploadAction nordnUploadAction();
|
||||||
NordnVerifyAction nordnVerifyAction();
|
NordnVerifyAction nordnVerifyAction();
|
||||||
|
|
|
@ -17,9 +17,9 @@ package com.google.domain.registry.request;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
import static com.google.common.base.Strings.nullToEmpty;
|
import static com.google.common.base.Strings.nullToEmpty;
|
||||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||||
|
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||||
import static com.google.domain.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
|
import static com.google.domain.registry.security.XsrfTokenManager.X_CSRF_TOKEN;
|
||||||
import static com.google.domain.registry.security.XsrfTokenManager.validateToken;
|
import static com.google.domain.registry.security.XsrfTokenManager.validateToken;
|
||||||
import static com.google.domain.registry.util.HttpServletUtils.sendOk;
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
|
import static javax.servlet.http.HttpServletResponse.SC_METHOD_NOT_ALLOWED;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
||||||
|
@ -149,7 +149,8 @@ public final class RequestHandler<C> {
|
||||||
try {
|
try {
|
||||||
route.get().instantiator().apply(component).run();
|
route.get().instantiator().apply(component).run();
|
||||||
if (route.get().action().automaticallyPrintOk()) {
|
if (route.get().action().automaticallyPrintOk()) {
|
||||||
sendOk(rsp);
|
rsp.setContentType(PLAIN_TEXT_UTF_8.toString());
|
||||||
|
rsp.getWriter().write("OK\n");
|
||||||
}
|
}
|
||||||
} catch (HttpException e) {
|
} catch (HttpException e) {
|
||||||
e.send(rsp);
|
e.send(rsp);
|
||||||
|
|
|
@ -1,48 +0,0 @@
|
||||||
// Copyright 2016 The Domain Registry Authors. All Rights Reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
package com.google.domain.registry.util;
|
|
||||||
|
|
||||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
|
||||||
import static com.google.domain.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServlet;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/** Utility methods for working with {@link HttpServlet}-related classes. */
|
|
||||||
public final class HttpServletUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the given request's first {@code name} parameter, or throws
|
|
||||||
* {@code IllegalArgumentException} if the parameter is not present.
|
|
||||||
*
|
|
||||||
* @deprecated in favor of <code>RequestParameters.extractRequiredParameter</code>
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static String getRequiredParameterValue(HttpServletRequest req, String name) {
|
|
||||||
return checkArgumentNotNull(req.getParameter(name), "Missing required parameter: %s", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the content type on an HttpServletResponse to UTF-8, returns 200 OK status, and sends
|
|
||||||
* "OK".
|
|
||||||
*/
|
|
||||||
public static void sendOk(HttpServletResponse rsp) throws IOException {
|
|
||||||
rsp.setContentType(PLAIN_TEXT_UTF_8.toString());
|
|
||||||
rsp.getWriter().write("OK\n");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -15,6 +15,9 @@
|
||||||
package com.google.domain.registry.export;
|
package com.google.domain.registry.export;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.domain.registry.export.CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM;
|
||||||
|
import static com.google.domain.registry.export.CheckSnapshotServlet.SNAPSHOT_NAME_PARAM;
|
||||||
|
import static com.google.domain.registry.testing.TaskQueueHelper.assertNoTasksEnqueued;
|
||||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
import static javax.servlet.http.HttpServletResponse.SC_ACCEPTED;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||||
|
@ -22,7 +25,6 @@ import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
|
@ -76,9 +78,6 @@ public class CheckSnapshotServletTest {
|
||||||
@Mock
|
@Mock
|
||||||
private DatastoreBackupService backupService;
|
private DatastoreBackupService backupService;
|
||||||
|
|
||||||
@Mock
|
|
||||||
private LoadSnapshotServlet loadSnapshotServlet;
|
|
||||||
|
|
||||||
private final FakeClock clock = new FakeClock(COMPLETE_TIME.plusMillis(1000));
|
private final FakeClock clock = new FakeClock(COMPLETE_TIME.plusMillis(1000));
|
||||||
private final StringWriter httpOutput = new StringWriter();
|
private final StringWriter httpOutput = new StringWriter();
|
||||||
private final CheckSnapshotServlet servlet = new CheckSnapshotServlet();
|
private final CheckSnapshotServlet servlet = new CheckSnapshotServlet();
|
||||||
|
@ -86,7 +85,6 @@ public class CheckSnapshotServletTest {
|
||||||
@Before
|
@Before
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
inject.setStaticField(CheckSnapshotServlet.class, "backupService", backupService);
|
inject.setStaticField(CheckSnapshotServlet.class, "backupService", backupService);
|
||||||
inject.setStaticField(CheckSnapshotServlet.class, "loadSnapshotServlet", loadSnapshotServlet);
|
|
||||||
inject.setStaticField(DatastoreBackupInfo.class, "clock", clock);
|
inject.setStaticField(DatastoreBackupInfo.class, "clock", clock);
|
||||||
|
|
||||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
||||||
|
@ -111,21 +109,34 @@ public class CheckSnapshotServletTest {
|
||||||
backupInfo.getGcsFilename());
|
backupInfo.getGcsFilename());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void assertLoadTaskEnqueued(String id, String file, String kinds)
|
||||||
|
throws Exception {
|
||||||
|
assertTasksEnqueued(
|
||||||
|
"export-snapshot",
|
||||||
|
new TaskMatcher()
|
||||||
|
.url("/_dr/task/loadSnapshot")
|
||||||
|
.method("POST")
|
||||||
|
.param("id", id)
|
||||||
|
.param("file", file)
|
||||||
|
.param("kinds", kinds));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_enqueuePollTask() throws Exception {
|
public void testSuccess_enqueuePollTask() throws Exception {
|
||||||
servlet.enqueuePollTask("some_snapshot_name", ImmutableSet.of("one", "two", "three"));
|
servlet.enqueuePollTask("some_snapshot_name", ImmutableSet.of("one", "two", "three"));
|
||||||
assertTasksEnqueued(CheckSnapshotServlet.QUEUE,
|
assertTasksEnqueued(CheckSnapshotServlet.QUEUE,
|
||||||
new TaskMatcher()
|
new TaskMatcher()
|
||||||
.url(CheckSnapshotServlet.PATH)
|
.url(CheckSnapshotServlet.PATH)
|
||||||
.param(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM, "some_snapshot_name")
|
.param(SNAPSHOT_NAME_PARAM, "some_snapshot_name")
|
||||||
.param(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM, "one,two,three")
|
.param(SNAPSHOT_KINDS_TO_LOAD_PARAM, "one,two,three")
|
||||||
.method("POST"));
|
.method("POST"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forPendingBackup_returnsNotModified() throws Exception {
|
public void testPost_forPendingBackup_returnsNotModified() throws Exception {
|
||||||
setPendingBackup();
|
setPendingBackup();
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
|
@ -135,7 +146,8 @@ public class CheckSnapshotServletTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forStalePendingBackupBackup_returnsAccepted() throws Exception {
|
public void testPost_forStalePendingBackupBackup_returnsAccepted() throws Exception {
|
||||||
setPendingBackup();
|
setPendingBackup();
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||||
clock.setTo(START_TIME
|
clock.setTo(START_TIME
|
||||||
.plus(Duration.standardHours(20))
|
.plus(Duration.standardHours(20))
|
||||||
|
@ -150,76 +162,57 @@ public class CheckSnapshotServletTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forCompleteBackup_enqueuesLoadTask() throws Exception {
|
public void testPost_forCompleteBackup_enqueuesLoadTask() throws Exception {
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).setStatus(SC_OK);
|
verify(rsp).setStatus(SC_OK);
|
||||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
assertLoadTaskEnqueued(
|
||||||
"20140801_010203",
|
"20140801_010203", "gs://somebucket/some_backup_20140801.backup_info", "one,two");
|
||||||
"gs://somebucket/some_backup_20140801.backup_info",
|
|
||||||
ImmutableSet.of("one", "two"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forCompleteAutoBackup_enqueuesLoadTask_usingBackupName() throws Exception {
|
public void testPost_forCompleteAutoBackup_enqueuesLoadTask_usingBackupName() throws Exception {
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM))
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("auto_snapshot_somestring");
|
||||||
.thenReturn("auto_snapshot_somestring");
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
|
||||||
when(backupService.findByName("auto_snapshot_somestring")).thenReturn(backupInfo);
|
when(backupService.findByName("auto_snapshot_somestring")).thenReturn(backupInfo);
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).setStatus(SC_OK);
|
verify(rsp).setStatus(SC_OK);
|
||||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
assertLoadTaskEnqueued(
|
||||||
"somestring",
|
"somestring", "gs://somebucket/some_backup_20140801.backup_info", "one,two");
|
||||||
"gs://somebucket/some_backup_20140801.backup_info",
|
|
||||||
ImmutableSet.of("one", "two"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPost_forCompleteBackup_missingKindsToLoad_enqueuesLoadTask() throws Exception {
|
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
|
||||||
verify(rsp).setStatus(SC_OK);
|
|
||||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
|
||||||
"20140801_010203",
|
|
||||||
"gs://somebucket/some_backup_20140801.backup_info",
|
|
||||||
ImmutableSet.of("one", "two", "three"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forCompleteBackup_withExtraKindsToLoad_enqueuesLoadTask() throws Exception {
|
public void testPost_forCompleteBackup_withExtraKindsToLoad_enqueuesLoadTask() throws Exception {
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,foo");
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,foo");
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).setStatus(SC_OK);
|
verify(rsp).setStatus(SC_OK);
|
||||||
verify(loadSnapshotServlet).enqueueLoadTask(
|
assertLoadTaskEnqueued(
|
||||||
"20140801_010203",
|
"20140801_010203", "gs://somebucket/some_backup_20140801.backup_info", "one");
|
||||||
"gs://somebucket/some_backup_20140801.backup_info",
|
|
||||||
ImmutableSet.of("one"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forCompleteBackup_withEmptyKindsToLoad_skipsLoadTask() throws Exception {
|
public void testPost_forCompleteBackup_withEmptyKindsToLoad_skipsLoadTask() throws Exception {
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("");
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("");
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).setStatus(SC_OK);
|
verify(rsp).setStatus(SC_OK);
|
||||||
verifyZeroInteractions(loadSnapshotServlet);
|
assertNoTasksEnqueued("export-snapshot");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPost_forBadBackup_returnsBadRequest() throws Exception {
|
public void testPost_forBadBackup_returnsBadRequest() throws Exception {
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
when(backupService.findByName("some_backup")).thenThrow(
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||||
new IllegalArgumentException("No backup found"));
|
when(backupService.findByName("some_backup"))
|
||||||
|
.thenThrow(new IllegalArgumentException("No backup found"));
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "Bad backup name some_backup: No backup found");
|
verify(rsp).sendError(SC_BAD_REQUEST, "Bad backup name some_backup: No backup found");
|
||||||
|
@ -228,14 +221,16 @@ public class CheckSnapshotServletTest {
|
||||||
@Test
|
@Test
|
||||||
public void testPost_noBackupSpecified_returnsError() throws Exception {
|
public void testPost_noBackupSpecified_returnsError() throws Exception {
|
||||||
when(req.getMethod()).thenReturn("POST");
|
when(req.getMethod()).thenReturn("POST");
|
||||||
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn(null);
|
||||||
|
when(req.getParameter(SNAPSHOT_KINDS_TO_LOAD_PARAM)).thenReturn("one,two");
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: name");
|
verify(rsp).sendError(SC_BAD_REQUEST, "Missing parameter: name");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGet_returnsInformation() throws Exception {
|
public void testGet_returnsInformation() throws Exception {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
when(backupService.findByName("some_backup")).thenReturn(backupInfo);
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
|
@ -254,7 +249,7 @@ public class CheckSnapshotServletTest {
|
||||||
@Test
|
@Test
|
||||||
public void testGet_forBadBackup_returnsError() throws Exception {
|
public void testGet_forBadBackup_returnsError() throws Exception {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
when(req.getParameter(CheckSnapshotServlet.SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
when(req.getParameter(SNAPSHOT_NAME_PARAM)).thenReturn("some_backup");
|
||||||
when(backupService.findByName("some_backup")).thenThrow(
|
when(backupService.findByName("some_backup")).thenThrow(
|
||||||
new IllegalArgumentException("No backup found"));
|
new IllegalArgumentException("No backup found"));
|
||||||
|
|
||||||
|
@ -266,6 +261,6 @@ public class CheckSnapshotServletTest {
|
||||||
public void testGet_noBackupSpecified_returnsError() throws Exception {
|
public void testGet_noBackupSpecified_returnsError() throws Exception {
|
||||||
when(req.getMethod()).thenReturn("GET");
|
when(req.getMethod()).thenReturn("GET");
|
||||||
servlet.service(req, rsp);
|
servlet.service(req, rsp);
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: name");
|
verify(rsp).sendError(SC_BAD_REQUEST, "Missing parameter: name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,21 +16,20 @@ package com.google.domain.registry.export;
|
||||||
|
|
||||||
import static com.google.common.collect.Iterables.transform;
|
import static com.google.common.collect.Iterables.transform;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static com.google.domain.registry.export.LoadSnapshotAction.LOAD_SNAPSHOT_FILE_PARAM;
|
||||||
|
import static com.google.domain.registry.export.LoadSnapshotAction.LOAD_SNAPSHOT_ID_PARAM;
|
||||||
|
import static com.google.domain.registry.export.LoadSnapshotAction.LOAD_SNAPSHOT_KINDS_PARAM;
|
||||||
|
import static com.google.domain.registry.export.LoadSnapshotAction.PATH;
|
||||||
|
import static com.google.domain.registry.export.LoadSnapshotAction.QUEUE;
|
||||||
|
import static com.google.domain.registry.export.LoadSnapshotAction.enqueueLoadSnapshotTask;
|
||||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
|
||||||
import static org.joda.time.DateTimeZone.UTC;
|
import static org.joda.time.DateTimeZone.UTC;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyString;
|
|
||||||
import static org.mockito.Matchers.eq;
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.times;
|
import static org.mockito.Mockito.times;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.api.client.http.HttpRequestInitializer;
|
|
||||||
import com.google.api.client.http.HttpTransport;
|
|
||||||
import com.google.api.client.json.JsonFactory;
|
|
||||||
import com.google.api.services.bigquery.Bigquery;
|
import com.google.api.services.bigquery.Bigquery;
|
||||||
import com.google.api.services.bigquery.model.Dataset;
|
import com.google.api.services.bigquery.model.Dataset;
|
||||||
import com.google.api.services.bigquery.model.Job;
|
import com.google.api.services.bigquery.model.Job;
|
||||||
|
@ -41,12 +40,12 @@ import com.google.common.base.Function;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.domain.registry.bigquery.BigqueryFactory;
|
import com.google.domain.registry.bigquery.BigqueryFactory;
|
||||||
import com.google.domain.registry.config.TestRegistryConfig;
|
|
||||||
import com.google.domain.registry.export.BigqueryPollJobAction.BigqueryPollJobEnqueuer;
|
import com.google.domain.registry.export.BigqueryPollJobAction.BigqueryPollJobEnqueuer;
|
||||||
|
import com.google.domain.registry.request.HttpException.BadRequestException;
|
||||||
|
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
||||||
import com.google.domain.registry.testing.AppEngineRule;
|
import com.google.domain.registry.testing.AppEngineRule;
|
||||||
|
import com.google.domain.registry.testing.ExceptionRule;
|
||||||
import com.google.domain.registry.testing.FakeClock;
|
import com.google.domain.registry.testing.FakeClock;
|
||||||
import com.google.domain.registry.testing.InjectRule;
|
|
||||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
|
||||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||||
|
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
@ -58,20 +57,12 @@ import org.mockito.ArgumentCaptor;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.runners.MockitoJUnitRunner;
|
import org.mockito.runners.MockitoJUnitRunner;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.IOException;
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
/** Unit tests for {@link LoadSnapshotAction}. */
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
|
|
||||||
/** Unit tests for {@link LoadSnapshotServlet}. */
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class LoadSnapshotServletTest {
|
public class LoadSnapshotActionTest {
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final InjectRule inject = new InjectRule();
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
public final AppEngineRule appEngine = AppEngineRule.builder()
|
||||||
|
@ -79,21 +70,7 @@ public class LoadSnapshotServletTest {
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final RegistryConfigRule configRule = new RegistryConfigRule(new TestRegistryConfig() {
|
public final ExceptionRule thrown = new ExceptionRule();
|
||||||
@Override public String getProjectId() {
|
|
||||||
return "Project-Id";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String getSnapshotsDataset() {
|
|
||||||
return "testdataset";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private HttpServletRequest req;
|
|
||||||
|
|
||||||
@Mock
|
|
||||||
private HttpServletResponse rsp;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private BigqueryFactory bigqueryFactory;
|
private BigqueryFactory bigqueryFactory;
|
||||||
|
@ -116,70 +93,48 @@ public class LoadSnapshotServletTest {
|
||||||
@Mock
|
@Mock
|
||||||
private BigqueryPollJobEnqueuer bigqueryPollEnqueuer;
|
private BigqueryPollJobEnqueuer bigqueryPollEnqueuer;
|
||||||
|
|
||||||
private static final DateTime NOW = new DateTime(1391096117045L, UTC);
|
private FakeClock clock = new FakeClock(new DateTime(1391096117045L, UTC));
|
||||||
|
private LoadSnapshotAction action;
|
||||||
private FakeClock clock = new FakeClock();
|
|
||||||
private final StringWriter httpOutput = new StringWriter();
|
|
||||||
private final LoadSnapshotServlet servlet = new LoadSnapshotServlet();
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
clock.setTo(NOW);
|
when(bigqueryFactory.create("Project-Id", "snapshots")).thenReturn(bigquery);
|
||||||
inject.setStaticField(LoadSnapshotServlet.class, "clock", clock);
|
|
||||||
inject.setStaticField(LoadSnapshotServlet.class, "bigqueryFactory", bigqueryFactory);
|
|
||||||
inject.setStaticField(LoadSnapshotServlet.class, "bigqueryPollEnqueuer", bigqueryPollEnqueuer);
|
|
||||||
|
|
||||||
when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput));
|
|
||||||
|
|
||||||
when(bigqueryFactory.create(
|
|
||||||
anyString(),
|
|
||||||
any(HttpTransport.class),
|
|
||||||
any(JsonFactory.class),
|
|
||||||
any(HttpRequestInitializer.class)))
|
|
||||||
.thenReturn(bigquery);
|
|
||||||
|
|
||||||
when(bigquery.jobs()).thenReturn(bigqueryJobs);
|
when(bigquery.jobs()).thenReturn(bigqueryJobs);
|
||||||
when(bigqueryJobs.insert(eq("Project-Id"), any(Job.class))).thenReturn(bigqueryJobsInsert);
|
when(bigqueryJobs.insert(eq("Project-Id"), any(Job.class))).thenReturn(bigqueryJobsInsert);
|
||||||
|
|
||||||
when(bigquery.datasets()).thenReturn(bigqueryDatasets);
|
when(bigquery.datasets()).thenReturn(bigqueryDatasets);
|
||||||
when(bigqueryDatasets.insert(eq("Project-Id"), any(Dataset.class)))
|
when(bigqueryDatasets.insert(eq("Project-Id"), any(Dataset.class)))
|
||||||
.thenReturn(bigqueryDatasetsInsert);
|
.thenReturn(bigqueryDatasetsInsert);
|
||||||
|
action = new LoadSnapshotAction();
|
||||||
servlet.init(mock(ServletConfig.class));
|
action.bigqueryFactory = bigqueryFactory;
|
||||||
when(req.getMethod()).thenReturn("POST");
|
action.bigqueryPollEnqueuer = bigqueryPollEnqueuer;
|
||||||
|
action.clock = clock;
|
||||||
|
action.projectId = "Project-Id";
|
||||||
|
action.snapshotFile = "gs://bucket/snapshot.backup_info";
|
||||||
|
action.snapshotId = "id12345";
|
||||||
|
action.snapshotKinds = "one,two,three";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_enqueueLoadTask() throws Exception {
|
public void testSuccess_enqueueLoadTask() throws Exception {
|
||||||
servlet.enqueueLoadTask(
|
enqueueLoadSnapshotTask(
|
||||||
"id12345", "gs://bucket/snapshot.backup_info", ImmutableSet.of("one", "two", "three"));
|
"id12345", "gs://bucket/snapshot.backup_info", ImmutableSet.of("one", "two", "three"));
|
||||||
assertTasksEnqueued(LoadSnapshotServlet.QUEUE,
|
assertTasksEnqueued(
|
||||||
|
QUEUE,
|
||||||
new TaskMatcher()
|
new TaskMatcher()
|
||||||
.url(LoadSnapshotServlet.PATH)
|
.url(PATH)
|
||||||
.method("POST")
|
.method("POST")
|
||||||
.param(LoadSnapshotServlet.SNAPSHOT_ID_PARAM, "id12345")
|
.param(LOAD_SNAPSHOT_ID_PARAM, "id12345")
|
||||||
.param(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM, "gs://bucket/snapshot.backup_info")
|
.param(LOAD_SNAPSHOT_FILE_PARAM, "gs://bucket/snapshot.backup_info")
|
||||||
.param(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM, "one,two,three"));
|
.param(LOAD_SNAPSHOT_KINDS_PARAM, "one,two,three"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_doPost() throws Exception {
|
public void testSuccess_doPost() throws Exception {
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
action.run();
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
|
||||||
.thenReturn("gs://bucket/snapshot.backup_info");
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
|
||||||
.thenReturn("one,two,three");
|
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
// Verify that bigqueryFactory was called in a way that would create the dataset if it didn't
|
||||||
|
// already exist.
|
||||||
// Check that we attempted to create the snapshots dataset.
|
verify(bigqueryFactory).create("Project-Id", "snapshots");
|
||||||
ArgumentCaptor<Dataset> datasetArgument = ArgumentCaptor.forClass(Dataset.class);
|
|
||||||
verify(bigqueryDatasets).insert(eq("Project-Id"), datasetArgument.capture());
|
|
||||||
assertThat(datasetArgument.getValue().getDatasetReference().getProjectId())
|
|
||||||
.isEqualTo("Project-Id");
|
|
||||||
assertThat(datasetArgument.getValue().getDatasetReference().getDatasetId())
|
|
||||||
.isEqualTo("testdataset");
|
|
||||||
verify(bigqueryDatasetsInsert).execute();
|
|
||||||
|
|
||||||
// Capture the load jobs we inserted to do additional checking on them.
|
// Capture the load jobs we inserted to do additional checking on them.
|
||||||
ArgumentCaptor<Job> jobArgument = ArgumentCaptor.forClass(Job.class);
|
ArgumentCaptor<Job> jobArgument = ArgumentCaptor.forClass(Job.class);
|
||||||
|
@ -193,7 +148,7 @@ public class LoadSnapshotServletTest {
|
||||||
JobConfigurationLoad config = job.getConfiguration().getLoad();
|
JobConfigurationLoad config = job.getConfiguration().getLoad();
|
||||||
assertThat(config.getSourceFormat()).isEqualTo("DATASTORE_BACKUP");
|
assertThat(config.getSourceFormat()).isEqualTo("DATASTORE_BACKUP");
|
||||||
assertThat(config.getDestinationTable().getProjectId()).isEqualTo("Project-Id");
|
assertThat(config.getDestinationTable().getProjectId()).isEqualTo("Project-Id");
|
||||||
assertThat(config.getDestinationTable().getDatasetId()).isEqualTo("testdataset");
|
assertThat(config.getDestinationTable().getDatasetId()).isEqualTo("snapshots");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the job IDs for each load job.
|
// Check the job IDs for each load job.
|
||||||
|
@ -231,64 +186,37 @@ public class LoadSnapshotServletTest {
|
||||||
new JobReference()
|
new JobReference()
|
||||||
.setProjectId("Project-Id")
|
.setProjectId("Project-Id")
|
||||||
.setJobId("load-snapshot-id12345-one-1391096117045"),
|
.setJobId("load-snapshot-id12345-one-1391096117045"),
|
||||||
UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_one", "one"),
|
UpdateSnapshotViewAction.createViewUpdateTask("snapshots", "id12345_one", "one"),
|
||||||
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
||||||
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
||||||
new JobReference()
|
new JobReference()
|
||||||
.setProjectId("Project-Id")
|
.setProjectId("Project-Id")
|
||||||
.setJobId("load-snapshot-id12345-two-1391096117045"),
|
.setJobId("load-snapshot-id12345-two-1391096117045"),
|
||||||
UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_two", "two"),
|
UpdateSnapshotViewAction.createViewUpdateTask("snapshots", "id12345_two", "two"),
|
||||||
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
||||||
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
verify(bigqueryPollEnqueuer).enqueuePollTask(
|
||||||
new JobReference()
|
new JobReference()
|
||||||
.setProjectId("Project-Id")
|
.setProjectId("Project-Id")
|
||||||
.setJobId("load-snapshot-id12345-three-1391096117045"),
|
.setJobId("load-snapshot-id12345-three-1391096117045"),
|
||||||
UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_three", "three"),
|
UpdateSnapshotViewAction.createViewUpdateTask("snapshots", "id12345_three", "three"),
|
||||||
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
|
||||||
|
|
||||||
verify(rsp).setStatus(SC_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFailure_doPost_missingIdHeader() throws Exception {
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
|
||||||
.thenReturn("gs://bucket/snapshot.backup_info");
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
|
||||||
.thenReturn("one,two,three");
|
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: id");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFailure_doPost_missingFileHeader() throws Exception {
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
|
||||||
.thenReturn("one,two,three");
|
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: file");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testFailure_doPost_missingKindHeader() throws Exception {
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
|
||||||
.thenReturn("gs://bucket/snapshot.backup_info");
|
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: kinds");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFailure_doPost_badGcsFilename() throws Exception {
|
public void testFailure_doPost_badGcsFilename() throws Exception {
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_ID_PARAM)).thenReturn("id12345");
|
action.snapshotFile = "gs://bucket/snapshot";
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_FILE_PARAM))
|
thrown.expect(
|
||||||
.thenReturn("gs://bucket/snapshot");
|
BadRequestException.class,
|
||||||
when(req.getParameter(LoadSnapshotServlet.SNAPSHOT_KINDS_PARAM))
|
"Error calling load snapshot: backup info file extension missing");
|
||||||
.thenReturn("one,two,three");
|
action.run();
|
||||||
|
}
|
||||||
|
|
||||||
servlet.service(req, rsp);
|
@Test
|
||||||
verify(rsp).sendError(SC_BAD_REQUEST, "backup info file extension missing");
|
public void testFailure_doPost_bigqueryThrowsException() throws Exception {
|
||||||
|
when(bigqueryJobsInsert.execute()).thenThrow(new IOException("The Internet has gone missing"));
|
||||||
|
thrown.expect(
|
||||||
|
InternalServerErrorException.class,
|
||||||
|
"Error loading snapshot: The Internet has gone missing");
|
||||||
|
action.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,9 +15,9 @@
|
||||||
package com.google.domain.registry.export;
|
package com.google.domain.registry.export;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_DATASET_ID_PARAM;
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.UPDATE_SNAPSHOT_DATASET_ID_PARAM;
|
||||||
import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_KIND_PARAM;
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.UPDATE_SNAPSHOT_KIND_PARAM;
|
||||||
import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_TABLE_ID_PARAM;
|
import static com.google.domain.registry.export.UpdateSnapshotViewAction.UPDATE_SNAPSHOT_TABLE_ID_PARAM;
|
||||||
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
import static com.google.domain.registry.testing.TaskQueueHelper.assertTasksEnqueued;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Matchers.anyString;
|
import static org.mockito.Matchers.anyString;
|
||||||
|
@ -30,11 +30,9 @@ import com.google.api.services.bigquery.model.Dataset;
|
||||||
import com.google.api.services.bigquery.model.Table;
|
import com.google.api.services.bigquery.model.Table;
|
||||||
import com.google.appengine.api.taskqueue.QueueFactory;
|
import com.google.appengine.api.taskqueue.QueueFactory;
|
||||||
import com.google.domain.registry.bigquery.BigqueryFactory;
|
import com.google.domain.registry.bigquery.BigqueryFactory;
|
||||||
import com.google.domain.registry.config.TestRegistryConfig;
|
|
||||||
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
import com.google.domain.registry.request.HttpException.InternalServerErrorException;
|
||||||
import com.google.domain.registry.testing.AppEngineRule;
|
import com.google.domain.registry.testing.AppEngineRule;
|
||||||
import com.google.domain.registry.testing.ExceptionRule;
|
import com.google.domain.registry.testing.ExceptionRule;
|
||||||
import com.google.domain.registry.testing.RegistryConfigRule;
|
|
||||||
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -59,17 +57,6 @@ public class UpdateSnapshotViewActionTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final ExceptionRule thrown = new ExceptionRule();
|
public final ExceptionRule thrown = new ExceptionRule();
|
||||||
|
|
||||||
@Rule
|
|
||||||
public final RegistryConfigRule configRule = new RegistryConfigRule(new TestRegistryConfig() {
|
|
||||||
@Override public String getProjectId() {
|
|
||||||
return "Project-Id";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public String getLatestSnapshotDataset() {
|
|
||||||
return "testdataset";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private BigqueryFactory bigqueryFactory;
|
private BigqueryFactory bigqueryFactory;
|
||||||
|
|
||||||
|
@ -104,8 +91,9 @@ public class UpdateSnapshotViewActionTest {
|
||||||
action = new UpdateSnapshotViewAction();
|
action = new UpdateSnapshotViewAction();
|
||||||
action.bigqueryFactory = bigqueryFactory;
|
action.bigqueryFactory = bigqueryFactory;
|
||||||
action.datasetId = "some_dataset";
|
action.datasetId = "some_dataset";
|
||||||
action.tableId = "12345_fookind";
|
|
||||||
action.kindName = "fookind";
|
action.kindName = "fookind";
|
||||||
|
action.projectId = "Project-Id";
|
||||||
|
action.tableId = "12345_fookind";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -116,9 +104,9 @@ public class UpdateSnapshotViewActionTest {
|
||||||
new TaskMatcher()
|
new TaskMatcher()
|
||||||
.url(UpdateSnapshotViewAction.PATH)
|
.url(UpdateSnapshotViewAction.PATH)
|
||||||
.method("POST")
|
.method("POST")
|
||||||
.param(SNAPSHOT_DATASET_ID_PARAM, "some_dataset")
|
.param(UPDATE_SNAPSHOT_DATASET_ID_PARAM, "some_dataset")
|
||||||
.param(SNAPSHOT_TABLE_ID_PARAM, "12345_fookind")
|
.param(UPDATE_SNAPSHOT_TABLE_ID_PARAM, "12345_fookind")
|
||||||
.param(SNAPSHOT_KIND_PARAM, "fookind"));
|
.param(UPDATE_SNAPSHOT_KIND_PARAM, "fookind"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -128,7 +116,7 @@ public class UpdateSnapshotViewActionTest {
|
||||||
// Check that we updated the view.
|
// Check that we updated the view.
|
||||||
ArgumentCaptor<Table> tableArg = ArgumentCaptor.forClass(Table.class);
|
ArgumentCaptor<Table> tableArg = ArgumentCaptor.forClass(Table.class);
|
||||||
verify(bigqueryTables).update(
|
verify(bigqueryTables).update(
|
||||||
eq("Project-Id"), eq("testdataset"), eq("fookind"), tableArg.capture());
|
eq("Project-Id"), eq("latest_snapshot"), eq("fookind"), tableArg.capture());
|
||||||
assertThat(tableArg.getValue().getView().getQuery())
|
assertThat(tableArg.getValue().getView().getQuery())
|
||||||
.isEqualTo("SELECT * FROM [some_dataset.12345_fookind]");
|
.isEqualTo("SELECT * FROM [some_dataset.12345_fookind]");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue