Refactor update snapshot view servlet into a Daggerized Action

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=120224051
This commit is contained in:
mcilwain 2016-04-19 06:47:25 -07:00 committed by Justine Tunney
parent 4fbf613955
commit c5d09227c5
8 changed files with 68 additions and 121 deletions

View file

@ -61,7 +61,7 @@ public interface RegistryConfig {
/** /**
* Returns the BigQuery dataset for storing views pointing to the latest datastore snapshot. * 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(); public String getLatestSnapshotDataset();

View file

@ -158,14 +158,9 @@
<url-pattern>/_dr/task/loadSnapshot</url-pattern> <url-pattern>/_dr/task/loadSnapshot</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet> <!-- Updates a view to point at a certain snapshot in BigQuery. -->
<description>Updates a view to point at a certain snapshot in BigQuery.</description>
<display-name>Update snapshot view in BigQuery</display-name>
<servlet-name>updateSnapshotView</servlet-name>
<servlet-class>com.google.domain.registry.export.UpdateSnapshotViewServlet</servlet-class>
</servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>updateSnapshotView</servlet-name> <servlet-name>backend-servlet</servlet-name>
<url-pattern>/_dr/task/updateSnapshotView</url-pattern> <url-pattern>/_dr/task/updateSnapshotView</url-pattern>
</servlet-mapping> </servlet-mapping>

View file

@ -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.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.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 static com.google.domain.registry.request.RequestParameters.extractRequiredHeader;
import com.google.domain.registry.request.Header; import com.google.domain.registry.request.Header;
import com.google.domain.registry.request.Parameter;
import dagger.Module; import dagger.Module;
import dagger.Provides; import dagger.Provides;
@ -29,6 +33,25 @@ import javax.servlet.http.HttpServletRequest;
/** Dagger module for data export tasks. */ /** Dagger module for data export tasks. */
@Module @Module
public final class ExportRequestModule { 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 @Provides
@Header(CHAINED_TASK_QUEUE_HEADER) @Header(CHAINED_TASK_QUEUE_HEADER)
static String provideChainedTaskQueue(HttpServletRequest req) { static String provideChainedTaskQueue(HttpServletRequest req) {

View file

@ -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. // well-known view in BigQuery to point at the newly loaded snapshot table for this kind.
bigqueryPollEnqueuer.enqueuePollTask( bigqueryPollEnqueuer.enqueuePollTask(
jobRef, jobRef,
UpdateSnapshotViewServlet.createViewUpdateTask( UpdateSnapshotViewAction.createViewUpdateTask(
ENVIRONMENT.config().getSnapshotsDataset(), tableId, kindName), ENVIRONMENT.config().getSnapshotsDataset(), tableId, kindName),
QueueFactory.getQueue(UpdateSnapshotViewServlet.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);

View file

@ -13,13 +13,7 @@
// limitations under the License. // limitations under the License.
package com.google.domain.registry.export; package com.google.domain.registry.export;
import static com.google.domain.registry.request.Action.Method.POST;
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 com.google.api.client.googleapis.json.GoogleJsonResponseException; import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.services.bigquery.Bigquery; 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.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.common.net.MediaType;
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.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.FormattingLogger;
import com.google.domain.registry.util.NonFinalForTesting;
import com.google.domain.registry.util.SqlTemplate; import com.google.domain.registry.util.SqlTemplate;
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;
/** Update a well-known view to point at a certain datastore snapshot table in BigQuery. */ /** 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(); private static final RegistryEnvironment ENVIRONMENT = RegistryEnvironment.get();
@ -57,8 +50,11 @@ public class UpdateSnapshotViewServlet extends HttpServlet {
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
@NonFinalForTesting @Inject @Parameter(SNAPSHOT_DATASET_ID_PARAM) String datasetId;
private static BigqueryFactory bigqueryFactory = new BigqueryFactory(); @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. */ /** Create a task for updating a snapshot view. */
public static TaskOptions createViewUpdateTask( public static TaskOptions createViewUpdateTask(
@ -71,26 +67,15 @@ public class UpdateSnapshotViewServlet extends HttpServlet {
} }
@Override @Override
public void doPost(HttpServletRequest req, HttpServletResponse rsp) throws IOException { public void run() {
try { try {
String datasetId = getRequiredParameterValue(req, SNAPSHOT_DATASET_ID_PARAM); updateSnapshotView(datasetId, tableId, kindName);
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);
} catch (Throwable e) { } catch (Throwable e) {
logger.severe(e, e.toString()); throw new RuntimeException("Error in update snapshot view action.", e);
rsp.sendError(
e instanceof IllegalArgumentException ? SC_BAD_REQUEST : SC_INTERNAL_SERVER_ERROR,
htmlEscaper().escape(firstNonNull(e.getMessage(), e.toString())));
} }
} }
private String 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(); String projectId = ENVIRONMENT.config().getProjectId();
Bigquery bigquery = Bigquery bigquery =
@ -111,7 +96,6 @@ public class UpdateSnapshotViewServlet extends HttpServlet {
"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); ENVIRONMENT.config().getLatestSnapshotDataset(), kindName, datasetId, tableId);
logger.info(message); logger.info(message);
return message;
} }
private static void updateTable(Bigquery bigquery, Table table) throws IOException { private static void updateTable(Bigquery bigquery, Table table) throws IOException {

View file

@ -32,6 +32,7 @@ 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.SyncGroupMembersAction; 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.SheetModule;
import com.google.domain.registry.export.sheet.SyncRegistrarsSheetAction; import com.google.domain.registry.export.sheet.SyncRegistrarsSheetAction;
import com.google.domain.registry.flows.async.AsyncFlowsModule; import com.google.domain.registry.flows.async.AsyncFlowsModule;
@ -101,6 +102,7 @@ interface BackendRequestComponent {
TmchCrlAction tmchCrlAction(); TmchCrlAction tmchCrlAction();
TmchDnlAction tmchDnlAction(); TmchDnlAction tmchDnlAction();
TmchSmdrlAction tmchSmdrlAction(); TmchSmdrlAction tmchSmdrlAction();
UpdateSnapshotViewAction updateSnapshotViewAction();
WriteDnsAction writeDnsAction(); WriteDnsAction writeDnsAction();
VerifyEntityIntegrityAction verifyEntityIntegrityAction(); VerifyEntityIntegrityAction verifyEntityIntegrityAction();
} }

View file

@ -231,20 +231,20 @@ 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"),
UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_one", "one"), UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_one", "one"),
QueueFactory.getQueue(UpdateSnapshotViewServlet.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"),
UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_two", "two"), UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_two", "two"),
QueueFactory.getQueue(UpdateSnapshotViewServlet.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"),
UpdateSnapshotViewServlet.createViewUpdateTask("testdataset", "id12345_three", "three"), UpdateSnapshotViewAction.createViewUpdateTask("testdataset", "id12345_three", "three"),
QueueFactory.getQueue(UpdateSnapshotViewServlet.QUEUE)); QueueFactory.getQueue(UpdateSnapshotViewAction.QUEUE));
verify(rsp).setStatus(SC_OK); verify(rsp).setStatus(SC_OK);
} }

View file

@ -15,13 +15,13 @@
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.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 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.any;
import static org.mockito.Matchers.anyString; 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.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; 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.bigquery.BigqueryFactory;
import com.google.domain.registry.config.TestRegistryConfig; import com.google.domain.registry.config.TestRegistryConfig;
import com.google.domain.registry.testing.AppEngineRule; 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.RegistryConfigRule;
import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher; import com.google.domain.registry.testing.TaskQueueHelper.TaskMatcher;
@ -44,19 +43,9 @@ 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; /** Unit tests for {@link UpdateSnapshotViewAction}. */
import java.io.StringWriter;
import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/** Unit tests for {@link UpdateSnapshotViewServlet}. */
@RunWith(MockitoJUnitRunner.class) @RunWith(MockitoJUnitRunner.class)
public class UpdateSnapshotViewServletTest { public class UpdateSnapshotViewActionTest {
@Rule
public final InjectRule inject = new InjectRule();
@Rule @Rule
public final AppEngineRule appEngine = AppEngineRule.builder() public final AppEngineRule appEngine = AppEngineRule.builder()
@ -74,12 +63,6 @@ public class UpdateSnapshotViewServletTest {
} }
}); });
@Mock
private HttpServletRequest req;
@Mock
private HttpServletResponse rsp;
@Mock @Mock
private BigqueryFactory bigqueryFactory; private BigqueryFactory bigqueryFactory;
@ -98,52 +81,42 @@ public class UpdateSnapshotViewServletTest {
@Mock @Mock
private Bigquery.Tables.Update bigqueryTablesUpdate; private Bigquery.Tables.Update bigqueryTablesUpdate;
private final StringWriter httpOutput = new StringWriter(); private UpdateSnapshotViewAction action;
private final UpdateSnapshotViewServlet servlet = new UpdateSnapshotViewServlet();
@Before @Before
public void before() throws Exception { public void before() throws Exception {
inject.setStaticField(UpdateSnapshotViewServlet.class, "bigqueryFactory", bigqueryFactory);
when(bigqueryFactory.create(anyString(), anyString())).thenReturn(bigquery); 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(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);
when(bigquery.tables()).thenReturn(bigqueryTables); when(bigquery.tables()).thenReturn(bigqueryTables);
when(bigqueryTables.update( when(bigqueryTables.update(
eq("Project-Id"), any(String.class), any(String.class), any(Table.class))) eq("Project-Id"), any(String.class), any(String.class), any(Table.class)))
.thenReturn(bigqueryTablesUpdate); .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 @Test
public void testSuccess_createViewUpdateTask() throws Exception { public void testSuccess_createViewUpdateTask() throws Exception {
QueueFactory.getDefaultQueue().add( QueueFactory.getDefaultQueue().add(
UpdateSnapshotViewServlet.createViewUpdateTask("some_dataset", "12345_fookind", "fookind")); UpdateSnapshotViewAction.createViewUpdateTask("some_dataset", "12345_fookind", "fookind"));
assertTasksEnqueued("default", assertTasksEnqueued("default",
new TaskMatcher() new TaskMatcher()
.url(UpdateSnapshotViewServlet.PATH) .url(UpdateSnapshotViewAction.PATH)
.method("POST") .method("POST")
.param(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM, "some_dataset") .param(SNAPSHOT_DATASET_ID_PARAM, "some_dataset")
.param(UpdateSnapshotViewServlet.SNAPSHOT_TABLE_ID_PARAM, "12345_fookind") .param(SNAPSHOT_TABLE_ID_PARAM, "12345_fookind")
.param(UpdateSnapshotViewServlet.SNAPSHOT_KIND_PARAM, "fookind")); .param(SNAPSHOT_KIND_PARAM, "fookind"));
} }
@Test @Test
public void testSuccess_doPost() throws Exception { public void testSuccess_doPost() throws Exception {
when(req.getParameter(UpdateSnapshotViewServlet.SNAPSHOT_DATASET_ID_PARAM)) action.run();
.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);
// 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);
@ -151,35 +124,5 @@ public class UpdateSnapshotViewServletTest {
eq("Project-Id"), eq("testdataset"), eq("fookind"), tableArg.capture()); eq("Project-Id"), eq("testdataset"), 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]");
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");
} }
} }