/*
* RHQ Management Platform
* Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.modules.integrationTests.restApi;
import java.util.List;
import java.util.Map;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.path.json.JsonPath;
import com.jayway.restassured.response.Response;
import org.junit.Before;
import org.junit.Test;
import org.rhq.modules.integrationTests.restApi.d.Link;
import org.rhq.modules.integrationTests.restApi.d.Operation;
import static com.jayway.restassured.RestAssured.expect;
import static com.jayway.restassured.RestAssured.get;
import static com.jayway.restassured.RestAssured.given;
import static org.hamcrest.core.Is.is;
/**
* Test the operations part of the rest api
* @author Heiko W. Rupp
*/
public class OperationsTest extends AbstractBase {
private int discoveryDefinitionId;
private int viewPLDefinitionId;
@Before
public void setUp() throws Exception {
super.setUp();
Response r =
given()
.header(acceptJson)
.queryParam("resourceId",_platformId)
.expect()
.statusCode(200)
.log().ifError()
.when()
.get("/operation/definitions");
discoveryDefinitionId = -1;
List<Map<String,Object>> list = r.as(List.class);
for (Map<String,Object> map : list) {
String name = (String) map.get("name");
Integer id = (Integer) map.get("id");
if (name.equals("discovery")) {
discoveryDefinitionId = id;
}
if (name.equals("viewProcessList")) {
viewPLDefinitionId = id;
}
}
assert discoveryDefinitionId !=-1 : "No discovery operation found";
}
@Test
public void testGetDefinitionById() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.pathParam("did", discoveryDefinitionId)
.expect()
.statusCode(200)
.body("name",is("discovery"))
.when()
.get("/operation/definition/{did}");
}
@Test
public void testGetDefinitionByUnknownId() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.pathParam("did", -42)
.expect()
.statusCode(404)
.when()
.get("/operation/definition/{did}");
}
@Test
public void testGetDefinitionsForUnknownResource() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.queryParam("resourceId", 42)
.expect()
.statusCode(404)
.when()
.get("/operation/definitions");
}
@Test
public void testGetDefinitionsForMissingResourceId() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.expect()
.statusCode(406)
.when()
.get("/operation/definitions");
}
@Test
public void testCreateScheduleByUnknownDefinitionId() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.pathParam("did", -42)
.expect()
.statusCode(406)
.when()
.post("/operation/definition/{did}");
}
@Test
public void testCreateScheduleForUnknownResource() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.queryParam("resourceId", 42)
.pathParam("definitionId", discoveryDefinitionId)
.expect()
.statusCode(404)
.when()
.post("/operation/definition/{definitionId}");
}
@Test
public void testCreateScheduleForMissingResourceId() throws Exception {
// Now retrieve that definition by id
given()
.header(acceptJson)
.pathParam("definitionId", discoveryDefinitionId)
.expect()
.statusCode(406)
.when()
.post("/operation/definition/{definitionId}");
}
@Test
public void testCreateDraftOperation() throws Exception {
Operation draft = getADraftOperation(_platformId, discoveryDefinitionId);
int draftId = draft.getId();
// check if we can retrieve one single draft
Operation op = get("/operation/" + draftId).as(Operation.class);
assert op !=null;
assert op.equals(draft);
}
@Test
public void testCreateAndUpdateDraftOperation() throws Exception {
Operation draft = getADraftOperation(_platformId, discoveryDefinitionId);
int draftId = draft.getId();
draft.getParams().put("detailedDiscovery",true);
try {
given()
.contentType(ContentType.JSON)
.pathParam("id", draftId)
.body(draft)
.log().everything()
.expect()
.statusCode(200)
.log().ifError()
.when()
.put("/operation/{id}");
} finally {
// delete the draft again
expect()
.statusCode(204)
.when()
.delete("/operation/" + draftId);
}
}
@Test
public void testCatchBadLinkSerialization() throws Exception {
// Test that when we get Links back in bad format, we
// correctly bail out.
Operation draft = getADraftOperation(_platformId, discoveryDefinitionId);
int draftId = draft.getId();
draft.getParams().put("detailedDiscovery",true);
String jsonWithBadLinkSer = //
"{\n" +
" \"id\": " + draftId + ",\n" +
" \"name\": \"discovery\",\n" +
" \"readyToSubmit\": false,\n" +
" \"resourceId\": " + _platformId + ",\n" +
" \"definitionId\": " + discoveryDefinitionId + ",\n" +
" \"params\": {\n" +
" \"detailedDiscovery\": true\n" +
" },\n" +
" \"links\": [\n" +
" {\n" +
" \"rel\": \"edit\",\n" +
" \"href\": \"http://localhost:7080/rest/operation/" + draftId + "\"\n" +
" }\n" +
" ]\n" +
"}";
try {
given()
.contentType(ContentType.JSON)
.pathParam("id", draftId)
.body(jsonWithBadLinkSer)
.log().everything()
.expect()
.statusCode(503)
.log().ifError()
.when()
.put("/operation/{id}");
} finally {
// delete the draft again
expect()
.statusCode(204)
.when()
.delete("/operation/" + draftId);
}
}
@Test
public void testCreateDraftOperationAndScheduleExecution() throws Exception {
int platformId = findIdOfARealPlatform();
Operation draft = getADraftOperation(platformId, discoveryDefinitionId);
int draftId = draft.getId();
draft.setReadyToSubmit(true);
draft.getParams().put("detailedDiscovery", false);
// update to schedule
Operation scheduled =
given()
.contentType(ContentType.JSON)
.pathParam("id",draftId)
.body(draft)
.expect()
.statusCode(200)
.log().ifError()
.when()
.put("/operation/{id}")
.as(Operation.class);
System.out.println(scheduled.getId());
String history = findHistoryItem(scheduled);
String historyId = history.substring(history.lastIndexOf("/")+1);
try {
waitAndCheckStatus(platformId, historyId);
} finally {
// Wait until the operation has finished and then delete
waitForTerminationAndDelete(historyId);
}
}
@Test
public void testCreateDraftOperationNoParamsAndScheduleExecution() throws Exception {
int platformId = findIdOfARealPlatform();
Operation draft = getADraftOperation(platformId, viewPLDefinitionId);
int draftId = draft.getId();
draft.setReadyToSubmit(true);
// update to schedule
Operation scheduled =
given()
.contentType(ContentType.JSON)
.pathParam("id",draftId)
.body(draft)
.expect()
.statusCode(200)
.log().ifError()
.when()
.put("/operation/{id}")
.as(Operation.class);
System.out.println(scheduled.getId());
String history = findHistoryItem(scheduled);
String historyId = history.substring(history.lastIndexOf("/")+1);
try {
waitAndCheckStatus(platformId, historyId);
} finally {
// Wait until the operation has finished and then delete
waitForTerminationAndDelete(historyId);
}
}
private Operation getADraftOperation(int platformId, int definitionId) {
Operation draft =
given()
.header(acceptJson)
.pathParam("definitionId", definitionId)
.queryParam("resourceId",platformId)
.expect()
.statusCode(200)
.log().ifError()
.when()
.post("/operation/definition/{definitionId}")
.as(Operation.class);
assert draft != null;
assert draft.getDefinitionId() == definitionId;
System.out.println("--- Draft created --");
System.out.flush();
return draft;
}
private String findHistoryItem(Operation scheduled) {
String history = null;
List<Link> links = scheduled.getLinks();
for (Link link : links) {
if (link.getRel().equals("history")) {
history = link.getHref();
}
}
assert history != null;
return history;
}
private void waitAndCheckStatus(int platformId, String historyId) throws InterruptedException {
// Thread.sleep(15000); // we need to wait a little as the execution may take time
given()
.pathParam("hid", historyId)
.expect()
.statusCode(200)
.log().everything()
.when()
.get("/operation/history/{hid}");
// See if we also find it when we are looking for histories on the resource
Response response =
given()
.queryParam("resourceId", platformId)
.header(acceptJson)
.expect()
.statusCode(200)
.log().everything()
.when()
.get("/operation/history");
// compare
List<Map<String,Object>> list = response.as(List.class);
boolean found = false;
for (Map<String,Object> map : list) {
if (map.get("jobId").equals(historyId)) {
found = true;
}
}
assert found;
}
private void waitForTerminationAndDelete(String historyId) throws InterruptedException {
boolean done = false;
int count = 0;
String status = "bla";
JsonPath jsonPath = null;
while (!done) {
Response response =
given()
.header(acceptJson)
.pathParam("hid", historyId)
.expect()
.log().everything()
.when()
.get("/operation/history/{hid}");
jsonPath = response.jsonPath();
status = jsonPath.getString("status");
int code = response.statusCode();
if (code==200 && (status.equals("Success") || status.equals("Failed"))) {
done = true;
} else {
Thread.sleep(2000);
}
count ++;
assert count < 10 :"Waited for 20sec -- something is wrong";
}
if (done && status.equals("Success")) {
Object result = jsonPath.get("result"); // Can not test on result.operationResult, as not every op has this.
assert result != null;
String errorMessage = jsonPath.getString("errorMessage");
assert errorMessage == null;
}
// Delete the history item
given()
.pathParam("hid", historyId)
.expect()
.statusCode(204)
.log().ifError()
.when()
.delete("/operation/history/{hid}");
}
@Test
public void testOpsScheduleMissingRequiredParam() throws Exception {
int platformId = findIdOfARealPlatform();
Operation draft = getADraftOperation(platformId, discoveryDefinitionId);
int draftId = draft.getId();
// explicitly remove the param from the draft for
// the test
Map<String, Object> params = draft.getParams();
if (params.containsKey("detailedDiscovery")) {
params.remove("detailedDiscovery");
}
// Update to put the new version in the server
// We don't want to submit, so the server does not
// validate and we should get a 200 back
draft.setReadyToSubmit(false);
given()
.contentType(ContentType.JSON)
.pathParam("id",draftId)
.body(draft)
.expect()
.statusCode(200)
.log().ifError()
.when()
.put("/operation/{id}");
// update to schedule, lacking the required param
draft.setReadyToSubmit(true);
given()
.contentType(ContentType.JSON)
.pathParam("id",draftId)
.body(draft)
.expect()
.statusCode(406)
.log().ifError()
.when()
.put("/operation/{id}");
}
@Test
public void testOpsScheduleRequiredParamWrongDataType() throws Exception {
int platformId = findIdOfARealPlatform();
Operation draft = getADraftOperation(platformId, discoveryDefinitionId);
int draftId = draft.getId();
draft.getParams().put("detailedDiscovery", 42);
draft.setReadyToSubmit(true);
// update to schedule
given()
.contentType(ContentType.JSON)
.pathParam("id",draftId)
.body(draft)
.expect()
.statusCode(406)
.log().ifError()
.when()
.put("/operation/{id}");
}
@Test
public void testDeleteBadOperationHistory() throws Exception {
given()
.pathParam("id","bla-44-15")
.expect()
.statusCode(406)
.when()
.delete("/operation/history/{id}");
}
@Test
public void testDeleteUnknownOperationHistory() throws Exception {
given()
.pathParam("id","bla_=_44_=_15")
.expect()
.statusCode(204)
.when()
.delete("/operation/history/{id}");
}
@Test
public void testDeleteUnknownOperationHistoryWithValidate() throws Exception {
given()
.pathParam("id","bla_=_44_=_15")
.queryParam("validate",true)
.expect()
.statusCode(404)
.when()
.delete("/operation/history/{id}");
}
}