Repository: incubator-zeppelin Updated Branches: refs/heads/master c5c92ed1f -> 664a13a2f
Add job operation API This PR is related to https://issues.apache.org/jira/browse/ZEPPELIN-137. I added some notebook job operations. Here is the examples. * Get notebook job status. ``` ]# curl -XGET http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA {"status":"OK","body":[{"id":"20151121-212654_766735423","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:39 KST 2015"},{"id":"20151121-212657_730976687","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"},{"id":"20151121-235508_752057578","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"},{"id":"20151121-235900_1491052248","status":"FINISHED","finished":"Tue Nov 24 14:21:41 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"},{"id":"20151121-235909_1520022794","status":"RUNNING","finished":"Tue Nov 24 02:53:51 KST 2015","started":"Tue Nov 24 14:21:41 KST 2015"}]} ``` * Run notebook job. ``` ]# curl -XDELETE http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA {"status":"ACCEPTED"} ``` * Stop(Delete) notebook job. ``` ]# curl -XDELETE http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA {"status":"ACCEPTED"} ``` * Run requested paragraph job. ``` ]# curl -XPOST http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA/20151121-212654_766735423 {"status":"ACCEPTED"} ``` * Stop(Delete) requested paragraph job. ``` ]# curl -XDELETE http://121.156.59.2:8080/api/notebook/job/2B3Z5BXJA/20151121-212654_766735423 {"status":"ACCEPTED"} ``` Author: astroshim <[email protected]> Author: root <root@ktadm002.(none)> Closes #465 from astroshim/improve/addApis and squashes the following commits: c668ed9 [astroshim] update REST API docs a83289e [astroshim] fix restapi testcase(status code). d0afd18 [astroshim] fix http status code. 775e7c8 [astroshim] update testcase. fe8d5eb [astroshim] check if note config null. dbd2d03 [astroshim] update note.java to find error. 861f652 [astroshim] fix indent error. 2989096 [astroshim] add generateParagraphsInfo method to Note.java cb99391 [astroshim] merge with master 8002cd5 [astroshim] change restapi testcase to find build problem. 5bb2c5e [astroshim] fix getCronJob response code. 73f3b2b [astroshim] add cron job api's 3e2ea3d [astroshim] update testcase. 722f05b [astroshim] merge seperated job testcase. 2bff6c9 [root] add job run and stop testcase. 6103c42 [astroshim] fix LineLength build error. e5f7103 [astroshim] fix whitespace build error. 7a7f993 [astroshim] fix indentation build error. 6c1acf3 [astroshim] fix result message. 1255674 [astroshim] add job operation api Project: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/commit/664a13a2 Tree: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/tree/664a13a2 Diff: http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/diff/664a13a2 Branch: refs/heads/master Commit: 664a13a2f69498fdd4ce4c1a29d970d9fb40f882 Parents: c5c92ed Author: astroshim <[email protected]> Authored: Thu Dec 10 00:19:49 2015 +0900 Committer: Alexander Bezzubov <[email protected]> Committed: Thu Dec 10 20:35:03 2015 +0900 ---------------------------------------------------------------------- docs/rest-api/rest-notebook.md | 256 +++++++++++++++++++ .../apache/zeppelin/rest/NotebookRestApi.java | 196 +++++++++++++- .../zeppelin/rest/message/CronRequest.java | 38 +++ .../zeppelin/rest/AbstractTestRestApi.java | 4 + .../zeppelin/rest/ZeppelinRestApiTest.java | 106 +++++++- .../java/org/apache/zeppelin/notebook/Note.java | 15 ++ 6 files changed, 613 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/docs/rest-api/rest-notebook.md ---------------------------------------------------------------------- diff --git a/docs/rest-api/rest-notebook.md b/docs/rest-api/rest-notebook.md index ffee95a..1bb0e53 100644 --- a/docs/rest-api/rest-notebook.md +++ b/docs/rest-api/rest-notebook.md @@ -169,3 +169,259 @@ limitations under the License. </tr> </table> +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Run notebook job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```POST``` method run all paragraph in the given notebook id. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK"}</pre></td> + </tr> + </table> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Stop notebook job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```DELETE``` method stop all paragraph in the given notebook id. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK"}</pre></td> + </tr> + </table> + +<br/> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Get notebook job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```GET``` method get all paragraph status by the given notebook id. + The body field of the returned JSON contains of the array that compose of the paragraph id, paragraph status, paragraph finish date, paragraph started date. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK","body":[{"id":"20151121-212654_766735423","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:39 KST 2015"},{"id":"20151121-212657_730976687","status":"FINISHED","finished":"Tue Nov 24 14:21:40 KST 2015","started":"Tue Nov 24 14:21:40 KST 2015"}]}</pre></td> + </tr> + </table> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Run paragraph job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```POST``` method run the paragraph by given notebook and paragraph id. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]/[paragraphId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK"}</pre></td> + </tr> + </table> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Stop paragraph job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```DELETE``` method stop the paragraph by given notebook and paragraph id. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/job/[notebookId]/[paragraphId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK"}</pre></td> + </tr> + </table> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Add cron job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```POST``` method add cron job by the given notebook id. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[notebookId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON input </td> + <td><pre>{"cron": "cron expression of notebook"}</pre></td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK"}</pre></td> + </tr> + </table> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Remove cron job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```DELETE``` method remove cron job by the given notebook id. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[notebookId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK"}</pre></td> + </tr> + </table> + +<br/> + + <table class="table-configuration"> + <col width="200"> + <tr> + <th>Get clone job</th> + <th></th> + </tr> + <tr> + <td>Description</td> + <td>This ```GET``` method get cron job expression of given notebook id. + The body field of the returned JSON contain the cron expression. + </td> + </tr> + <tr> + <td>URL</td> + <td>```http://[zeppelin-server]:[zeppelin-port]/api/notebook/cron/[notebookId]```</td> + </tr> + <tr> + <td>Success code</td> + <td>200</td> + </tr> + <tr> + <td> Fail code</td> + <td> 500 </td> + </tr> + <tr> + <td> sample JSON response </td> + <td><pre>{"status":"OK","body":"* * * * * ?"}</pre></td> + </tr> + </table> + http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java index 2b98633..b3f912e 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java @@ -29,12 +29,15 @@ import javax.ws.rs.core.Response.Status; import org.apache.zeppelin.interpreter.InterpreterSetting; import org.apache.zeppelin.notebook.Note; import org.apache.zeppelin.notebook.Notebook; +import org.apache.zeppelin.notebook.Paragraph; +import org.apache.zeppelin.rest.message.CronRequest; import org.apache.zeppelin.rest.message.InterpreterSettingListForNoteBind; import org.apache.zeppelin.rest.message.NewInterpreterSettingRequest; import org.apache.zeppelin.rest.message.NewNotebookRequest; import org.apache.zeppelin.server.JsonResponse; import org.apache.zeppelin.server.ZeppelinServer; import org.apache.zeppelin.socket.NotebookServer; +import org.quartz.CronExpression; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -166,11 +169,12 @@ public class NotebookRestApi { notebookServer.broadcastNoteList(); return new JsonResponse(Status.OK, "").build(); } + /** * Clone note REST API * @param * @return JSON with status.CREATED - * @throws IOException + * @throws IOException, CloneNotSupportedException, IllegalArgumentException */ @POST @Path("{notebookId}") @@ -185,4 +189,194 @@ public class NotebookRestApi { notebookServer.broadcastNoteList(); return new JsonResponse(Status.CREATED, "", newNote.getId()).build(); } + + /** + * Run notebook jobs REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @POST + @Path("job/{notebookId}") + public Response runNoteJobs(@PathParam("notebookId") String notebookId) throws + IOException, IllegalArgumentException { + logger.info("run notebook jobs {} ", notebookId); + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + note.runAll(); + return new JsonResponse(Status.OK).build(); + } + + /** + * Stop(delete) notebook jobs REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @DELETE + @Path("job/{notebookId}") + public Response stopNoteJobs(@PathParam("notebookId") String notebookId) throws + IOException, IllegalArgumentException { + logger.info("stop notebook jobs {} ", notebookId); + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + for (Paragraph p : note.getParagraphs()) { + if (!p.isTerminated()) { + p.abort(); + } + } + return new JsonResponse(Status.OK).build(); + } + + /** + * Get notebook job status REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @GET + @Path("job/{notebookId}") + public Response getNoteJobStatus(@PathParam("notebookId") String notebookId) throws + IOException, IllegalArgumentException { + logger.info("get notebook job status."); + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + return new JsonResponse(Status.OK, null, note.generateParagraphsInfo()).build(); + } + + /** + * Run paragraph job REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @POST + @Path("job/{notebookId}/{paragraphId}") + public Response runParagraph(@PathParam("notebookId") String notebookId, + @PathParam("paragraphId") String paragraphId) throws + IOException, IllegalArgumentException { + logger.info("run paragraph job {} {} ", notebookId, paragraphId); + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + if (note.getParagraph(paragraphId) == null) { + return new JsonResponse(Status.NOT_FOUND, "paragraph not found.").build(); + } + + note.run(paragraphId); + return new JsonResponse(Status.OK).build(); + } + + /** + * Stop(delete) paragraph job REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @DELETE + @Path("job/{notebookId}/{paragraphId}") + public Response stopParagraph(@PathParam("notebookId") String notebookId, + @PathParam("paragraphId") String paragraphId) throws + IOException, IllegalArgumentException { + logger.info("stop paragraph job {} ", notebookId); + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + Paragraph p = note.getParagraph(paragraphId); + if (p == null) { + return new JsonResponse(Status.NOT_FOUND, "paragraph not found.").build(); + } + p.abort(); + return new JsonResponse(Status.OK).build(); + } + + /** + * Register cron job REST API + * @param message - JSON with cron expressions. + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @POST + @Path("cron/{notebookId}") + public Response registerCronJob(@PathParam("notebookId") String notebookId, String message) throws + IOException, IllegalArgumentException { + logger.info("Register cron job note={} request cron msg={}", notebookId, message); + + CronRequest request = gson.fromJson(message, + CronRequest.class); + + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + if (!CronExpression.isValidExpression(request.getCronString())) { + return new JsonResponse(Status.BAD_REQUEST, "wrong cron expressions.").build(); + } + + Map<String, Object> config = note.getConfig(); + config.put("cron", request.getCronString()); + note.setConfig(config); + notebook.refreshCron(note.id()); + + return new JsonResponse(Status.OK).build(); + } + + /** + * Remove cron job REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @DELETE + @Path("cron/{notebookId}") + public Response removeCronJob(@PathParam("notebookId") String notebookId) throws + IOException, IllegalArgumentException { + logger.info("Remove cron job note {}", notebookId); + + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + Map<String, Object> config = note.getConfig(); + config.put("cron", null); + note.setConfig(config); + notebook.refreshCron(note.id()); + + return new JsonResponse(Status.OK).build(); + } + + /** + * Get cron job REST API + * @param + * @return JSON with status.OK + * @throws IOException, IllegalArgumentException + */ + @GET + @Path("cron/{notebookId}") + public Response getCronJob(@PathParam("notebookId") String notebookId) throws + IOException, IllegalArgumentException { + logger.info("Get cron job note {}", notebookId); + + Note note = notebook.getNote(notebookId); + if (note == null) { + return new JsonResponse(Status.NOT_FOUND, "note not found.").build(); + } + + return new JsonResponse(Status.OK, note.getConfig().get("cron")).build(); + } } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java new file mode 100644 index 0000000..5a33931 --- /dev/null +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/message/CronRequest.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.zeppelin.rest.message; + +import java.util.Map; + +import org.apache.zeppelin.interpreter.InterpreterOption; + +/** + * CronRequest rest api request message + * + */ +public class CronRequest { + String cron; + + public CronRequest (){ + + } + + public String getCronString() { + return cron; + } +} http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java index 1895e16..db7affe 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/AbstractTestRestApi.java @@ -393,6 +393,10 @@ public abstract class AbstractTestRestApi { protected Matcher<? super HttpMethodBase> isCreated() { return responsesWith(201); } + protected Matcher<? super HttpMethodBase> isBadRequest() { return responsesWith(400); } + + protected Matcher<? super HttpMethodBase> isNotFound() { return responsesWith(404); } + protected Matcher<? super HttpMethodBase> isNotAllowed() { return responsesWith(405); } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java index 8468de2..0a58fb0 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java @@ -264,7 +264,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { LOG.info("testCloneNotebook"); // Create note to clone Note note = ZeppelinServer.notebook.createNote(); - assertNotNull("cant create new note", note); + assertNotNull("can't create new note", note); note.setName("source note for clone"); Paragraph paragraph = note.addParagraph(); Map config = paragraph.getConfig(); @@ -308,5 +308,109 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { get.releaseConnection(); } + @Test + public void testNoteJobs() throws IOException, InterruptedException { + LOG.info("testNoteJobs"); + // Create note to run test. + Note note = ZeppelinServer.notebook.createNote(); + assertNotNull("can't create new note", note); + note.setName("note for run test"); + Paragraph paragraph = note.addParagraph(); + + Map config = paragraph.getConfig(); + config.put("enabled", true); + paragraph.setConfig(config); + + paragraph.setText("%md This is test paragraph."); + note.persist(); + String noteID = note.getId(); + + note.runAll(); + // wait until job is finished or timeout. + int timeout = 1; + while (!paragraph.isTerminated()) { + Thread.sleep(1000); + if (timeout++ > 10) { + LOG.info("testNoteJobs timeout job."); + break; + } + } + + // Call Run Notebook Jobs REST API + PostMethod postNoteJobs = httpPost("/notebook/job/" + noteID, ""); + assertThat("test notebook jobs run:", postNoteJobs, isAllowed()); + postNoteJobs.releaseConnection(); + + // Call Stop Notebook Jobs REST API + DeleteMethod deleteNoteJobs = httpDelete("/notebook/job/" + noteID); + assertThat("test notebook stop:", deleteNoteJobs, isAllowed()); + deleteNoteJobs.releaseConnection(); + Thread.sleep(1000); + + // Call Run paragraph REST API + PostMethod postParagraph = httpPost("/notebook/job/" + noteID + "/" + paragraph.getId(), ""); + assertThat("test paragraph run:", postParagraph, isAllowed()); + postParagraph.releaseConnection(); + Thread.sleep(1000); + + // Call Stop paragraph REST API + DeleteMethod deleteParagraph = httpDelete("/notebook/job/" + noteID + "/" + paragraph.getId()); + assertThat("test paragraph stop:", deleteParagraph, isAllowed()); + deleteParagraph.releaseConnection(); + Thread.sleep(1000); + + //cleanup + ZeppelinServer.notebook.removeNote(note.getId()); + } + + @Test + public void testCronJobs() throws InterruptedException, IOException{ + // create a note and a paragraph + Note note = ZeppelinServer.notebook.createNote(); + + note.setName("note for run test"); + Paragraph paragraph = note.addParagraph(); + paragraph.setText("%md This is test paragraph."); + + Map config = paragraph.getConfig(); + config.put("enabled", true); + paragraph.setConfig(config); + + note.runAll(); + // wait until job is finished or timeout. + int timeout = 1; + while (!paragraph.isTerminated()) { + Thread.sleep(1000); + if (timeout++ > 10) { + LOG.info("testNoteJobs timeout job."); + break; + } + } + + String jsonRequest = "{\"cron\":\"* * * * * ?\" }"; + // right cron expression but not exist note. + PostMethod postCron = httpPost("/notebook/cron/notexistnote", jsonRequest); + assertThat("", postCron, isNotFound()); + postCron.releaseConnection(); + + // right cron expression. + postCron = httpPost("/notebook/cron/" + note.getId(), jsonRequest); + assertThat("", postCron, isAllowed()); + postCron.releaseConnection(); + Thread.sleep(1000); + + // wrong cron expression. + jsonRequest = "{\"cron\":\"a * * * * ?\" }"; + postCron = httpPost("/notebook/cron/" + note.getId(), jsonRequest); + assertThat("", postCron, isBadRequest()); + postCron.releaseConnection(); + Thread.sleep(1000); + + // remove cron job. + DeleteMethod deleteCron = httpDelete("/notebook/cron/" + note.getId()); + assertThat("", deleteCron, isAllowed()); + deleteCron.releaseConnection(); + ZeppelinServer.notebook.removeNote(note.getId()); + } } http://git-wip-us.apache.org/repos/asf/incubator-zeppelin/blob/664a13a2/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java index 66a63c8..93dcec5 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/notebook/Note.java @@ -293,6 +293,21 @@ public class Note implements Serializable, JobListener { return paragraphs.get(paragraphs.size() - 1); } } + + public List<Map<String, String>> generateParagraphsInfo (){ + List<Map<String, String>> paragraphsInfo = new LinkedList<>(); + synchronized (paragraphs) { + for (Paragraph p : paragraphs) { + Map<String, String> info = new HashMap<>(); + info.put("id", p.getId()); + info.put("status", p.getStatus().toString()); + info.put("started", p.getDateStarted().toString()); + info.put("finished", p.getDateFinished().toString()); + paragraphsInfo.add(info); + } + } + return paragraphsInfo; + } /** * Run all paragraphs sequentially.
