diff --git a/java/com/google/domain/registry/config/RegistryConfig.java b/java/com/google/domain/registry/config/RegistryConfig.java index 5c7649412..639ea71df 100644 --- a/java/com/google/domain/registry/config/RegistryConfig.java +++ b/java/com/google/domain/registry/config/RegistryConfig.java @@ -61,7 +61,7 @@ public interface RegistryConfig { /** * Returns the BigQuery dataset for storing views pointing to the latest datastore snapshot. * - * @see com.google.domain.registry.export.UpdateSnapshotViewServlet + * @see com.google.domain.registry.export.UpdateSnapshotViewAction */ public String getLatestSnapshotDataset(); diff --git a/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml b/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml index 179562033..937f65f5b 100644 --- a/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml +++ b/java/com/google/domain/registry/env/common/backend/WEB-INF/web.xml @@ -158,14 +158,9 @@ /_dr/task/loadSnapshot - - Updates a view to point at a certain snapshot in BigQuery. - Update snapshot view in BigQuery - updateSnapshotView - com.google.domain.registry.export.UpdateSnapshotViewServlet - + - updateSnapshotView + backend-servlet /_dr/task/updateSnapshotView diff --git a/java/com/google/domain/registry/export/ExportRequestModule.java b/java/com/google/domain/registry/export/ExportRequestModule.java index 7b3bd32d6..12f87e5c5 100644 --- a/java/com/google/domain/registry/export/ExportRequestModule.java +++ b/java/com/google/domain/registry/export/ExportRequestModule.java @@ -17,9 +17,13 @@ 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.JOB_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.UpdateSnapshotViewAction.SNAPSHOT_KIND_PARAM; +import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_TABLE_ID_PARAM; import static com.google.domain.registry.request.RequestParameters.extractRequiredHeader; import com.google.domain.registry.request.Header; +import com.google.domain.registry.request.Parameter; import dagger.Module; import dagger.Provides; @@ -29,6 +33,25 @@ import javax.servlet.http.HttpServletRequest; /** Dagger module for data export tasks. */ @Module public final class ExportRequestModule { + + @Provides + @Parameter(SNAPSHOT_DATASET_ID_PARAM) + static String provideDatasetId(HttpServletRequest req) { + return extractRequiredHeader(req, SNAPSHOT_DATASET_ID_PARAM); + } + + @Provides + @Parameter(SNAPSHOT_TABLE_ID_PARAM) + static String provideTableId(HttpServletRequest req) { + return extractRequiredHeader(req, SNAPSHOT_TABLE_ID_PARAM); + } + + @Provides + @Parameter(SNAPSHOT_KIND_PARAM) + static String provideKind(HttpServletRequest req) { + return extractRequiredHeader(req, SNAPSHOT_KIND_PARAM); + } + @Provides @Header(CHAINED_TASK_QUEUE_HEADER) static String provideChainedTaskQueue(HttpServletRequest req) { diff --git a/java/com/google/domain/registry/export/LoadSnapshotServlet.java b/java/com/google/domain/registry/export/LoadSnapshotServlet.java index 1a72adeec..0f30c0d47 100644 --- a/java/com/google/domain/registry/export/LoadSnapshotServlet.java +++ b/java/com/google/domain/registry/export/LoadSnapshotServlet.java @@ -155,9 +155,9 @@ public class LoadSnapshotServlet extends HttpServlet { // well-known view in BigQuery to point at the newly loaded snapshot table for this kind. bigqueryPollEnqueuer.enqueuePollTask( jobRef, - UpdateSnapshotViewServlet.createViewUpdateTask( + UpdateSnapshotViewAction.createViewUpdateTask( ENVIRONMENT.config().getSnapshotsDataset(), tableId, kindName), - QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE)); + QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE)); builder.append(String.format(" - %s:%s\n", projectId, jobId)); logger.infofmt("Submitted load job %s:%s", projectId, jobId); diff --git a/java/com/google/domain/registry/export/UpdateSnapshotViewServlet.java b/java/com/google/domain/registry/export/UpdateSnapshotViewAction.java similarity index 69% rename from java/com/google/domain/registry/export/UpdateSnapshotViewServlet.java rename to java/com/google/domain/registry/export/UpdateSnapshotViewAction.java index bcfff7df7..0c52f3990 100644 --- a/java/com/google/domain/registry/export/UpdateSnapshotViewServlet.java +++ b/java/com/google/domain/registry/export/UpdateSnapshotViewAction.java @@ -13,13 +13,7 @@ // limitations under the License. package com.google.domain.registry.export; - -import static com.google.common.base.MoreObjects.firstNonNull; -import static com.google.common.html.HtmlEscapers.htmlEscaper; -import static com.google.domain.registry.util.HttpServletUtils.getRequiredParameterValue; -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_OK; +import static com.google.domain.registry.request.Action.Method.POST; import com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.services.bigquery.Bigquery; @@ -28,21 +22,20 @@ import com.google.api.services.bigquery.model.TableReference; import com.google.api.services.bigquery.model.ViewDefinition; import com.google.appengine.api.taskqueue.TaskOptions; import com.google.appengine.api.taskqueue.TaskOptions.Method; -import com.google.common.net.MediaType; import com.google.domain.registry.bigquery.BigqueryFactory; import com.google.domain.registry.config.RegistryEnvironment; +import com.google.domain.registry.request.Action; +import com.google.domain.registry.request.Parameter; import com.google.domain.registry.util.FormattingLogger; -import com.google.domain.registry.util.NonFinalForTesting; import com.google.domain.registry.util.SqlTemplate; import java.io.IOException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import javax.inject.Inject; /** Update a well-known view to point at a certain datastore snapshot table in BigQuery. */ -public class UpdateSnapshotViewServlet extends HttpServlet { +@Action(path = UpdateSnapshotViewAction.PATH, method = POST) +public class UpdateSnapshotViewAction implements Runnable { private static final RegistryEnvironment ENVIRONMENT = RegistryEnvironment.get(); @@ -57,8 +50,11 @@ public class UpdateSnapshotViewServlet extends HttpServlet { private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); - @NonFinalForTesting - private static BigqueryFactory bigqueryFactory = new BigqueryFactory(); + @Inject @Parameter(SNAPSHOT_DATASET_ID_PARAM) String datasetId; + @Inject @Parameter(SNAPSHOT_TABLE_ID_PARAM) String tableId; + @Inject @Parameter(SNAPSHOT_KIND_PARAM) String kindName; + @Inject BigqueryFactory bigqueryFactory; + @Inject UpdateSnapshotViewAction() {} /** Create a task for updating a snapshot view. */ public static TaskOptions createViewUpdateTask( @@ -71,26 +67,15 @@ public class UpdateSnapshotViewServlet extends HttpServlet { } @Override - public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws IOException { + public void run() { try { - String datasetId = getRequiredParameterValue(req, SNAPSHOT_DATASET_ID_PARAM); - String tableId = getRequiredParameterValue(req, SNAPSHOT_TABLE_ID_PARAM); - String kindName = getRequiredParameterValue(req, SNAPSHOT_KIND_PARAM); - - String message = updateSnapshotView(datasetId, tableId, kindName); - - rsp.setStatus(SC_OK); - rsp.setContentType(MediaType.PLAIN_TEXT_UTF_8.toString()); - rsp.getWriter().write("OK\n\n" + message); + updateSnapshotView(datasetId, tableId, kindName); } catch (Throwable e) { - logger.severe(e, e.toString()); - rsp.sendError( - e instanceof IllegalArgumentException ? SC_BAD_REQUEST : SC_INTERNAL_SERVER_ERROR, - htmlEscaper().escape(firstNonNull(e.getMessage(), e.toString()))); + throw new RuntimeException("Error in update snapshot view action.", e); } } - private String updateSnapshotView(String datasetId, String tableId, String kindName) + private void updateSnapshotView(String datasetId, String tableId, String kindName) throws IOException { String projectId = ENVIRONMENT.config().getProjectId(); Bigquery bigquery = @@ -111,7 +96,6 @@ public class UpdateSnapshotViewServlet extends HttpServlet { "Updated view %s:%s to point at snapshot table %s:%s.", ENVIRONMENT.config().getLatestSnapshotDataset(), kindName, datasetId, tableId); logger.info(message); - return message; } private static void updateTable(Bigquery bigquery, Table table) throws IOException { diff --git a/java/com/google/domain/registry/module/backend/BackendRequestComponent.java b/java/com/google/domain/registry/module/backend/BackendRequestComponent.java index a99a94884..82b29bd3d 100644 --- a/java/com/google/domain/registry/module/backend/BackendRequestComponent.java +++ b/java/com/google/domain/registry/module/backend/BackendRequestComponent.java @@ -32,6 +32,7 @@ import com.google.domain.registry.export.ExportDomainListsAction; import com.google.domain.registry.export.ExportRequestModule; import com.google.domain.registry.export.ExportReservedTermsAction; import com.google.domain.registry.export.SyncGroupMembersAction; +import com.google.domain.registry.export.UpdateSnapshotViewAction; import com.google.domain.registry.export.sheet.SheetModule; import com.google.domain.registry.export.sheet.SyncRegistrarsSheetAction; import com.google.domain.registry.flows.async.AsyncFlowsModule; @@ -101,6 +102,7 @@ interface BackendRequestComponent { TmchCrlAction tmchCrlAction(); TmchDnlAction tmchDnlAction(); TmchSmdrlAction tmchSmdrlAction(); + UpdateSnapshotViewAction updateSnapshotViewAction(); WriteDnsAction writeDnsAction(); VerifyEntityIntegrityAction verifyEntityIntegrityAction(); } diff --git a/javatests/com/google/domain/registry/export/LoadSnapshotServletTest.java b/javatests/com/google/domain/registry/export/LoadSnapshotServletTest.java index 9e2fcadce..f5721597e 100644 --- a/javatests/com/google/domain/registry/export/LoadSnapshotServletTest.java +++ b/javatests/com/google/domain/registry/export/LoadSnapshotServletTest.java @@ -231,20 +231,20 @@ public class LoadSnapshotServletTest { new JobReference() .setProjectId("Project-Id") .setJobId("load-snapshot-id12345-one-1391096117045"), - UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_one", "one"), - QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE)); + UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_one", "one"), + QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE)); verify(bigqueryPollEnqueuer).enqueuePollTask( new JobReference() .setProjectId("Project-Id") .setJobId("load-snapshot-id12345-two-1391096117045"), - UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_two", "two"), - QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE)); + UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_two", "two"), + QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE)); verify(bigqueryPollEnqueuer).enqueuePollTask( new JobReference() .setProjectId("Project-Id") .setJobId("load-snapshot-id12345-three-1391096117045"), - UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_three", "three"), - QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE)); + UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_three", "three"), + QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE)); verify(rsp).setStatus(SC_OK); } diff --git a/javatests/com/google/domain/registry/export/UpdateSnapshotViewServletTest.java b/javatests/com/google/domain/registry/export/UpdateSnapshotViewActionTest.java similarity index 54% rename from javatests/com/google/domain/registry/export/UpdateSnapshotViewServletTest.java rename to javatests/com/google/domain/registry/export/UpdateSnapshotViewActionTest.java index 2f2133967..10e654b1c 100644 --- a/javatests/com/google/domain/registry/export/UpdateSnapshotViewServletTest.java +++ b/javatests/com/google/domain/registry/export/UpdateSnapshotViewActionTest.java @@ -15,13 +15,13 @@ package com.google.domain.registry.export; 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.SNAPSHOT_KIND_PARAM; +import static com.google.domain.registry.export.UpdateSnapshotViewAction.SNAPSHOT_TABLE_ID_PARAM; 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.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,7 +32,6 @@ import com.google.appengine.api.taskqueue.QueueFactory; import com.google.domain.registry.bigquery.BigqueryFactory; import com.google.domain.registry.config.TestRegistryConfig; import com.google.domain.registry.testing.AppEngineRule; -import com.google.domain.registry.testing.InjectRule; import com.google.domain.registry.testing.RegistryConfigRule; import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher; @@ -44,19 +43,9 @@ import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; -import java.io.PrintWriter; -import java.io.StringWriter; - -import javax.servlet.ServletConfig; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -/** Unit tests for {@link UpdateSnapshotViewServlet}. */ +/** Unit tests for {@link UpdateSnapshotViewAction}. */ @RunWith(MockitoJUnitRunner.class) -public class UpdateSnapshotViewServletTest { - - @Rule - public final InjectRule inject = new InjectRule(); +public class UpdateSnapshotViewActionTest { @Rule public final AppEngineRule appEngine = AppEngineRule.builder() @@ -74,12 +63,6 @@ public class UpdateSnapshotViewServletTest { } }); - @Mock - private HttpServletRequest req; - - @Mock - private HttpServletResponse rsp; - @Mock private BigqueryFactory bigqueryFactory; @@ -98,52 +81,42 @@ public class UpdateSnapshotViewServletTest { @Mock private Bigquery.Tables.Update bigqueryTablesUpdate; - private final StringWriter httpOutput = new StringWriter(); - private final UpdateSnapshotViewServlet servlet = new UpdateSnapshotViewServlet(); + private UpdateSnapshotViewAction action; @Before public void before() throws Exception { - inject.setStaticField(UpdateSnapshotViewServlet.class, "bigqueryFactory", bigqueryFactory); when(bigqueryFactory.create(anyString(), anyString())).thenReturn(bigquery); - - when(req.getMethod()).thenReturn("POST"); - when(rsp.getWriter()).thenReturn(new PrintWriter(httpOutput)); - when(bigquery.datasets()).thenReturn(bigqueryDatasets); when(bigqueryDatasets.insert(eq("Project-Id"), any(Dataset.class))) .thenReturn(bigqueryDatasetsInsert); - when(bigquery.tables()).thenReturn(bigqueryTables); when(bigqueryTables.update( eq("Project-Id"), any(String.class), any(String.class), any(Table.class))) .thenReturn(bigqueryTablesUpdate); - servlet.init(mock(ServletConfig.class)); + action = new UpdateSnapshotViewAction(); + action.bigqueryFactory = bigqueryFactory; + action.datasetId = "some_dataset"; + action.tableId = "12345_fookind"; + action.kindName = "fookind"; } @Test public void testSuccess_createViewUpdateTask() throws Exception { QueueFactory.getDefaultQueue().add( - UpdateSnapshotViewServlet.createViewUpdateTask("some_dataset", "12345_fookind", "fookind")); + UpdateSnapshotViewAction.createViewUpdateTask("some_dataset", "12345_fookind", "fookind")); assertTasksEnqueued("default", new TaskMatcher() - .url(UpdateSnapshotViewServlet.PATH) + .url(UpdateSnapshotViewAction.PATH) .method("POST") - .param(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM, "some_dataset") - .param(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM, "12345_fookind") - .param(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM, "fookind")); + .param(SNAPSHOT_DATASET_ID_PARAM, "some_dataset") + .param(SNAPSHOT_TABLE_ID_PARAM, "12345_fookind") + .param(SNAPSHOT_KIND_PARAM, "fookind")); } @Test public void testSuccess_doPost() throws Exception { - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM)) - .thenReturn("some_dataset"); - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM)) - .thenReturn("12345_fookind"); - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM)) - .thenReturn("fookind"); - - servlet.service(req, rsp); + action.run(); // Check that we updated the view. ArgumentCaptor tableArg = ArgumentCaptor.forClass(Table.class); @@ -151,35 +124,5 @@ public class UpdateSnapshotViewServletTest { eq("Project-Id"), eq("testdataset"), eq("fookind"), tableArg.capture()); assertThat(tableArg.getValue().getView().getQuery()) .isEqualTo("SELECT * FROM [some_dataset.12345_fookind]"); - - verify(rsp).setStatus(SC_OK); - } - - @Test - public void testFailure_doPost_missingDatasetIdHeader() throws Exception { - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM)) - .thenReturn("12345_fookind"); - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM)).thenReturn("fookind"); - servlet.service(req, rsp); - verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: dataset"); - } - - @Test - public void testFailure_doPost_missingTableIdHeader() throws Exception { - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM)) - .thenReturn("some_dataset"); - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM)).thenReturn("fookind"); - servlet.service(req, rsp); - verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: table"); - } - - @Test - public void testFailure_doPost_missingKindHeader() throws Exception { - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM)) - .thenReturn("some_dataset"); - when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM)) - .thenReturn("12345_fookind"); - servlet.service(req, rsp); - verify(rsp).sendError(SC_BAD_REQUEST, "Missing required parameter: kind"); } }