package com.sixsq.slipstream.module;
/*
* +=================================================================+
* SlipStream Server (WAR)
* =====
* Copyright (C) 2013 SixSq Sarl (sixsq.com)
* =====
* 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.
* -=================================================================-
*/
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONObject;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Preference;
import org.restlet.data.Status;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;
import com.sixsq.slipstream.exceptions.ConfigurationException;
import com.sixsq.slipstream.exceptions.SlipStreamClientException;
import com.sixsq.slipstream.exceptions.ValidationException;
import com.sixsq.slipstream.persistence.Authz;
import com.sixsq.slipstream.persistence.ImageModule;
import com.sixsq.slipstream.persistence.Module;
import com.sixsq.slipstream.persistence.ModuleCategory;
import com.sixsq.slipstream.persistence.ProjectModule;
import com.sixsq.slipstream.persistence.User;
import com.sixsq.slipstream.persistence.UserTest;
import com.sixsq.slipstream.util.ResourceTestBase;
import com.sixsq.slipstream.util.SerializationUtil;
import com.sixsq.slipstream.util.XmlUtil;
public class ModuleResourceTest extends ResourceTestBase {
private static User anotherUser;
@BeforeClass
public static void setupClass() throws ValidationException,
ConfigurationException, InstantiationException,
IllegalAccessException, InvocationTargetException,
NoSuchMethodException, ClassNotFoundException {
resetAndLoadConnector(com.sixsq.slipstream.connector.local.LocalConnector.class);
user = UserTest.createUser("userModuleResourceTest", "password");
user.setDefaultCloudServiceName(cloudServiceName);
user = UserTest.storeUser(user);
anotherUser = new User("anotherUser");
anotherUser.setDefaultCloudServiceName(cloudServiceName);
anotherUser = UserTest.storeUser(anotherUser);
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
try {
user.remove();
} catch (Exception ex) {
// ok
}
try {
anotherUser.remove();
} catch (Exception ex) {
// ok
}
}
@Test
public void getModuleProject() throws ConfigurationException,
SlipStreamClientException {
String projectName = "getModuleProject";
createAndStoreProject(projectName);
Request request = createGetRequest(projectName, user);
// XML
Response response = executeRequest(request);
assertEquals(Status.SUCCESS_OK, response.getStatus());
String externalFormatXml = response.getEntityAsText();
String internalFormatXml = XmlUtil.denormalize(externalFormatXml);
Module project = (Module) SerializationUtil.fromXml(internalFormatXml,
ProjectModule.class);
assertEquals(projectName, project.getName());
// JSON
response = executeRequest(request, MediaType.APPLICATION_JSON);
assertEquals(Status.SUCCESS_OK, response.getStatus());
String externalFormatJson = response.getEntityAsText();
JSONObject obj = new JSONObject(externalFormatJson);
assertNotNull(obj);
assertEquals("Project", obj.getJSONObject("projectModule").getString("category"));
assertEquals(projectName, obj.getJSONObject("projectModule").getString("shortName"));
project.remove();
}
@Test
public void putModuleProjectAsForm() throws ConfigurationException,
SlipStreamClientException, IOException {
String projectName = "putModuleProjectAsForm";
String description = "a description";
Response response = putModuleAsForm(projectName, description);
Module persistedProject = null;
try {
assertEquals(Status.SUCCESS_CREATED, response.getStatus());
persistedProject = (Module) ProjectModule.load(Module
.constructResourceUri(projectName));
assertEquals(projectName, persistedProject.getName());
assertEquals(description, persistedProject.getDescription());
} finally {
try {
persistedProject.remove();
} catch (NullPointerException ex) {
}
}
}
private Response putModuleAsForm(String projectName, String description)
throws ConfigurationException, ValidationException {
ModuleCategory category = ModuleCategory.Project;
Form form = createForm(projectName, category);
form.add("description", description);
Request request = createPutRequest(projectName,
form.getWebRepresentation(), user);
return executeRequest(request);
}
@Test
public void putExistingModuleWithCircularReference() throws ValidationException {
String moduleName = "examples/imageCircularRef";
Module image = new ImageModule(moduleName);
image.setAuthz(new Authz(user.getName(), image));
image.store();
ModuleCategory category = ModuleCategory.Image;
Form form = createForm(moduleName, category);
form.add("moduleReference", moduleName);
Request request = createPutRequest(moduleName, form.getWebRepresentation(), user);
Response response = executeRequest(request);
assertThat(response.getStatus(), is(Status.CLIENT_ERROR_BAD_REQUEST));
image.remove();
}
@Test
public void putExistingModuleWithoutPutRightIsForbiden()
throws ValidationException {
String projectName = "existingProject";
Module project = createAndStoreProject(projectName);
ModuleCategory category = ModuleCategory.Project;
Form form = createForm(projectName, category);
Request request = createPutRequest(projectName,
form.getWebRepresentation(), anotherUser);
Response response = executeRequest(request);
System.err.println("DEBUG: " + request.toString());
System.err.println("DEBUG: " + request.getEntityAsText());
assertThat(response.getStatus(), is(Status.CLIENT_ERROR_FORBIDDEN));
project.remove();
}
@Test
public void putNewModuleOnExistingModule() throws ValidationException {
String projectName = "existingProject";
Module project = createAndStoreProject(projectName);
ModuleCategory category = ModuleCategory.Project;
Form form = createForm(projectName, category);
Request request = createPutRequest("existingProject",
form.getWebRepresentation(), user);
Response response = executeRequest(request);
System.err.println("DEBUG: " + request.toString());
System.err.println("DEBUG: " + request.getEntityAsText());
assertThat(response.getStatus(), is(Status.SUCCESS_OK));
project.remove();
}
@Test
public void putNewModuleOnExistingModuleIsForbiden()
throws ValidationException {
String projectName = "existingProject";
Module project = createAndStoreProject(projectName);
ModuleCategory category = ModuleCategory.Project;
Form form = createForm(projectName, category);
Request request = createPutRequest("existingProject",
form.getWebRepresentation(), user, TEST_REQUEST_NAME
+ "?new=true");
Response response = executeRequest(request);
System.err.println("DEBUG: " + request.toString());
System.err.println("DEBUG: " + request.getEntityAsText());
assertThat(response.getStatus(), is(Status.CLIENT_ERROR_FORBIDDEN));
project.remove();
}
@Test
public void putSubProjectProject() throws ConfigurationException,
SlipStreamClientException, IOException {
Module parentProject = createAndStoreProject("putSubProjectProject-Parent");
String projectName = "p/putSubProjectProject";
Module project = new ProjectModule(projectName);
ModuleCategory category = ModuleCategory.Project;
Form form = createForm(projectName, category);
Request request = createPutRequest(projectName,
form.getWebRepresentation(), user);
Response response = executeRequest(request);
assertEquals(Status.SUCCESS_CREATED, response.getStatus());
project = ProjectModule.load(project.getResourceUri());
project.remove();
parentProject.remove();
}
private Form createForm(String projectName, ModuleCategory category) {
Form form = new Form();
form.add("name", projectName);
form.add("category", category.toString());
return form;
}
@Test
@Ignore
public void putModuleProjectAsXml() throws ConfigurationException,
SlipStreamClientException {
String projectName = "putModuleProjectAsXml";
Module project = new ProjectModule(projectName);
String content = SerializationUtil.toXmlString(project);
StringRepresentation stringRepresentation = new StringRepresentation(
content, MediaType.APPLICATION_XML);
Request request = createPutRequest(projectName, stringRepresentation,
user);
Response response = executeRequest(request);
assertEquals(Status.SUCCESS_OK, response.getStatus());
Module persistedProject = (Module) ProjectModule.load("module/"
+ projectName);
assertEquals(projectName, persistedProject.getName());
persistedProject.remove();
}
@Test
public void getNewProjectToRetrieveTemplate()
throws ConfigurationException, ValidationException {
Map<String, Object> attributes = createAttributes("category",
ModuleCategory.Project.toString());
Request request = createGetRequest("new", user, attributes);
Response response = executeRequest(request);
assertThat(response.getStatus(), is(Status.SUCCESS_OK));
}
@Test
public void getNewMachineImageToRetrieveTemplate()
throws ConfigurationException, ValidationException {
Map<String, Object> attributes = createAttributes("category",
ModuleCategory.Image.toString());
Request request = createGetRequest("examples/new", user, attributes);
Response response = executeRequest(request);
assertThat(response.getStatus(), is(Status.SUCCESS_OK));
}
@Test
public void invalideCategory() throws ConfigurationException,
ValidationException {
Map<String, Object> attributes = createAttributes("category",
"UnknownCategory");
Request request = createGetRequest("new", user, attributes);
Response response = executeRequest(request);
assertThat(response.getStatus(), is(Status.CLIENT_ERROR_BAD_REQUEST));
}
@Test
public void deleteRedirectsToParentResourceIfAllGone()
throws ValidationException, ConfigurationException {
String projectName = "deleteRedirectsToParentResourceIfAllGoneParent";
String moduleName = projectName
+ "/deleteRedirectsToParentResourceIfAllGoneModule";
Module[] modules = createProjectAndImageModules(projectName, moduleName);
Request request = createDeleteRequest(moduleName);
try {
Response response = executeRequest(request);
assertThat(response.getStatus(), is(Status.SUCCESS_NO_CONTENT));
assertThat(response.getLocationRef().getPath(),
is("/" + Module.constructResourceUri(projectName)));
} finally {
try {
for (Module module : modules) {
module.remove();
}
} catch (NullPointerException ex) {
}
}
}
@Test
public void deleteRedirectsToLatestResourceIfPreviousVersionsExists()
throws ValidationException, ConfigurationException {
String projectName = "deleteRedirectsToParentResourceIfAllGoneParent";
String moduleName = projectName
+ "/deleteRedirectsToParentResourceIfAllGoneModule";
Module[] modules = createProjectAndImageModules(projectName, moduleName);
// Create and store again to create a second version
ImageModule image = new ImageModule(moduleName);
image.setAuthz(new Authz(user.getName(), image));
image = image.store();
Module project = (Module) modules[1];
Request request = createDeleteRequest(moduleName);
try {
Response response = executeRequest(request);
assertThat(response.getStatus(), is(Status.SUCCESS_NO_CONTENT));
assertThat(response.getLocationRef().getPath(), startsWith("/"
+ Module.constructResourceUri(image.getName())));
} finally {
try {
ImageModule.loadLatest(image.getResourceUri()).remove();
project.remove();
} catch (NullPointerException ex) {
}
}
}
private Module[] createProjectAndImageModules(String projectName,
String moduleName) throws ValidationException {
Module parent = new ProjectModule(projectName);
parent.setAuthz(new Authz(user.getName(), parent));
parent = parent.store();
ImageModule image = new ImageModule(moduleName);
image.setAuthz(new Authz(user.getName(), image));
image = image.store();
Module[] modules = { image, parent };
return modules;
}
private Request createGetRequest(String module, User user,
Map<String, Object> attributes) throws ConfigurationException,
ValidationException {
attributes.putAll(createModuleAttributes(module));
Request request = createGetRequest(attributes);
addUserToRequest(user, request);
return request;
}
protected Response executeRequest(Request request) {
// FIXME: Without an explicit list of accepted representations, restlet
// appears to choose from the available types randomly. There doesn't
// seem to be a way of telling it to prefer one representation over
// another. This fixes the unit tests, but may not work in the field
// unless all of our clients explicitly request XML.
return executeRequest(request, MediaType.APPLICATION_XML);
}
protected Response executeRequest(Request request, MediaType mediaType) {
List<Preference<MediaType>> accepts = request.getClientInfo().getAcceptedMediaTypes();
accepts.clear();
if (mediaType != null) {
accepts.add(new Preference<>(mediaType));
}
ServerResource resource = new ModuleResource();
Response response = new Response(request);
resource.init(null, request, response);
if (response.getStatus().isSuccess()) {
resource.handle();
}
return resource.getResponse();
}
protected Request createDeleteRequest(String module)
throws ConfigurationException, ValidationException {
return createDeleteRequest(createRequestAttributes(module), user);
}
protected Map<String, Object> createRequestAttributes(String module) {
Map<String, Object> attributes = new HashMap<String, Object>();
attributes.put("module", module);
return attributes;
}
}