mirror of https://github.com/apache/cloudstack.git
395 lines
16 KiB
Java
395 lines
16 KiB
Java
//
|
|
// 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 com.cloud.utils.rest;
|
|
|
|
import static org.junit.Assert.assertTrue;
|
|
import static org.mockito.Matchers.any;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.times;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
import java.io.IOException;
|
|
import java.util.Collections;
|
|
|
|
import org.apache.commons.httpclient.Header;
|
|
import org.apache.commons.httpclient.HttpClient;
|
|
import org.apache.commons.httpclient.HttpException;
|
|
import org.apache.commons.httpclient.HttpMethod;
|
|
import org.apache.commons.httpclient.methods.DeleteMethod;
|
|
import org.apache.commons.httpclient.methods.GetMethod;
|
|
import org.apache.commons.httpclient.methods.PostMethod;
|
|
import org.apache.commons.httpclient.methods.PutMethod;
|
|
import org.apache.commons.httpclient.params.HttpClientParams;
|
|
import org.apache.http.HttpStatus;
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
|
|
public class RESTServiceConnectorTest {
|
|
protected static final String UUID = "aaaa";
|
|
protected static final String UUID_JSON_RESPONSE = "{\"uuid\" : \"aaaa\"}";
|
|
|
|
RESTServiceConnector connector;
|
|
HttpClient client = mock(HttpClient.class);
|
|
HttpMethod method;
|
|
String type;
|
|
String uri;
|
|
|
|
@Before
|
|
public void setUp() {
|
|
final HttpClientParams hmp = mock(HttpClientParams.class);
|
|
when(client.getParams()).thenReturn(hmp);
|
|
connector = new RESTServiceConnector(null) {
|
|
@Override
|
|
public HttpClient createHttpClient() {
|
|
return client;
|
|
}
|
|
|
|
@Override
|
|
public HttpMethod createMethod(final String newType, final String newUri) {
|
|
type = newType;
|
|
uri = newUri;
|
|
return method;
|
|
}
|
|
};
|
|
|
|
connector.validation = new RESTValidationStrategy();
|
|
connector.setAdminCredentials("admin", "adminpass");
|
|
connector.setControllerAddress("localhost");
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteLoginWithoutHostname() throws CloudstackRESTException {
|
|
connector.setControllerAddress(null);
|
|
connector.validation.login(RESTServiceConnector.protocol, client);
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteLoginWithoutCredentials() throws CloudstackRESTException {
|
|
method = mock(PutMethod.class);
|
|
connector.setAdminCredentials(null, null);
|
|
connector.validation.login(RESTServiceConnector.protocol, client);
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteUpdateObjectWithoutHostname() throws CloudstackRESTException {
|
|
method = mock(PutMethod.class);
|
|
connector.setControllerAddress(null);
|
|
connector.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteUpdateObjectWithoutCredentials() throws CloudstackRESTException {
|
|
method = mock(PutMethod.class);
|
|
connector.setAdminCredentials(null, null);
|
|
connector.executeUpdateObject(new String(), "/", Collections.<String, String> emptyMap());
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteCreateObjectWithoutHostname() throws CloudstackRESTException {
|
|
method = mock(PostMethod.class);
|
|
connector.setControllerAddress(null);
|
|
connector.executeCreateObject(new String(), String.class, "/", Collections.<String, String> emptyMap());
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteCreateObjectWithoutCredentials() throws CloudstackRESTException {
|
|
method = mock(PostMethod.class);
|
|
connector.setAdminCredentials(null, null);
|
|
connector.executeCreateObject(new String(), String.class, "/", Collections.<String, String> emptyMap());
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteDeleteObjectWithoutHostname() throws CloudstackRESTException {
|
|
method = mock(DeleteMethod.class);
|
|
connector.setControllerAddress(null);
|
|
connector.executeDeleteObject("/");
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteDeleteObjectWithoutCredentials() throws CloudstackRESTException {
|
|
method = mock(DeleteMethod.class);
|
|
connector.setAdminCredentials(null, null);
|
|
connector.executeDeleteObject("/");
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteRetrieveObjectWithoutHostname() throws CloudstackRESTException {
|
|
method = mock(GetMethod.class);
|
|
connector.setControllerAddress(null);
|
|
connector.executeRetrieveObject(String.class, "/", Collections.<String, String> emptyMap());
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteRetrieveObjectWithoutCredentials() throws CloudstackRESTException {
|
|
method = mock(GetMethod.class);
|
|
connector.setAdminCredentials(null, null);
|
|
connector.executeRetrieveObject(String.class, "/", Collections.<String, String> emptyMap());
|
|
}
|
|
|
|
@Test
|
|
public void testExecuteMethod() throws CloudstackRESTException {
|
|
final GetMethod gm = mock(GetMethod.class);
|
|
|
|
when(gm.getStatusCode()).thenReturn(HttpStatus.SC_OK);
|
|
connector.executeMethod(gm);
|
|
verify(gm, times(1)).getStatusCode();
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteMethodWithLogin() throws CloudstackRESTException, HttpException, IOException {
|
|
final GetMethod gm = mock(GetMethod.class);
|
|
when(client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
|
|
when(gm.getStatusCode()).thenReturn(HttpStatus.SC_UNAUTHORIZED).thenReturn(HttpStatus.SC_UNAUTHORIZED);
|
|
connector.executeMethod(gm);
|
|
verify(gm, times(1)).getStatusCode();
|
|
}
|
|
|
|
/* Bit of a roundabout way to ensure that login is called after an un authorized result
|
|
* It not possible to properly mock login()
|
|
*/
|
|
public void testExecuteMethodWithLoginSucced2ndAttempt() throws CloudstackRESTException, HttpException, IOException {
|
|
// Prepare
|
|
final GetMethod gm = mock(GetMethod.class);
|
|
when(gm.getStatusCode()).thenReturn(HttpStatus.SC_UNAUTHORIZED).thenReturn(HttpStatus.SC_UNAUTHORIZED);
|
|
|
|
final RESTValidationStrategy previousValidationStrategy = connector.validation;
|
|
connector.validation = new RESTValidationStrategy(){
|
|
@Override
|
|
protected void login(final String protocol, final HttpClient client)
|
|
throws CloudstackRESTException {
|
|
// Do nothing
|
|
}
|
|
};
|
|
connector.setAdminCredentials("admin", "adminpass");
|
|
connector.setControllerAddress("localhost");
|
|
|
|
// Execute
|
|
connector.executeMethod(gm);
|
|
// Leave mock object as is was
|
|
connector.validation = previousValidationStrategy;
|
|
|
|
// Assert/verify
|
|
verify(gm, times(2)).getStatusCode();
|
|
}
|
|
|
|
@Test
|
|
public void testExecuteCreateObject() throws CloudstackRESTException, IOException {
|
|
JsonEntity ls = new JsonEntity();
|
|
method = mock(PostMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_CREATED);
|
|
when(method.getResponseBodyAsString()).thenReturn(UUID_JSON_RESPONSE);
|
|
ls = connector.executeCreateObject(ls, JsonEntity.class, "/", Collections.<String, String> emptyMap());
|
|
assertTrue(UUID.equals(ls.getUuid()));
|
|
verify(method, times(1)).releaseConnection();
|
|
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteCreateObjectFailure() throws CloudstackRESTException, IOException {
|
|
JsonEntity ls = new JsonEntity();
|
|
method = mock(PostMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
|
final Header header = mock(Header.class);
|
|
when(header.getValue()).thenReturn("text/html");
|
|
when(method.getResponseHeader("Content-Type")).thenReturn(header);
|
|
when(method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
|
|
when(method.isRequestSent()).thenReturn(true);
|
|
try {
|
|
ls = connector.executeCreateObject(ls, JsonEntity.class, "/", Collections.<String, String> emptyMap());
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteCreateObjectException() throws CloudstackRESTException, IOException {
|
|
JsonEntity ls = new JsonEntity();
|
|
when(client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
|
|
method = mock(PostMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
|
final Header header = mock(Header.class);
|
|
when(header.getValue()).thenReturn("text/html");
|
|
when(method.getResponseHeader("Content-Type")).thenReturn(header);
|
|
when(method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
|
|
try {
|
|
ls = connector.executeCreateObject(ls, JsonEntity.class, "/", Collections.<String, String> emptyMap());
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testExecuteUpdateObject() throws CloudstackRESTException, IOException {
|
|
final JsonEntity ls = new JsonEntity();
|
|
method = mock(PutMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
|
|
connector.executeUpdateObject(ls, "/", Collections.<String, String> emptyMap());
|
|
verify(method, times(1)).releaseConnection();
|
|
verify(client, times(1)).executeMethod(method);
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteUpdateObjectFailure() throws CloudstackRESTException, IOException {
|
|
final JsonEntity ls = new JsonEntity();
|
|
method = mock(PutMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
|
final Header header = mock(Header.class);
|
|
when(header.getValue()).thenReturn("text/html");
|
|
when(method.getResponseHeader("Content-Type")).thenReturn(header);
|
|
when(method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
|
|
when(method.isRequestSent()).thenReturn(true);
|
|
try {
|
|
connector.executeUpdateObject(ls, "/", Collections.<String, String> emptyMap());
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteUpdateObjectException() throws CloudstackRESTException, IOException {
|
|
final JsonEntity ls = new JsonEntity();
|
|
method = mock(PutMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
|
|
when(client.executeMethod((HttpMethod)any())).thenThrow(new IOException());
|
|
try {
|
|
connector.executeUpdateObject(ls, "/", Collections.<String, String> emptyMap());
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testExecuteDeleteObject() throws CloudstackRESTException, IOException {
|
|
method = mock(DeleteMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_NO_CONTENT);
|
|
connector.executeDeleteObject("/");
|
|
verify(method, times(1)).releaseConnection();
|
|
verify(client, times(1)).executeMethod(method);
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteDeleteObjectFailure() throws CloudstackRESTException, IOException {
|
|
method = mock(DeleteMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
|
final Header header = mock(Header.class);
|
|
when(header.getValue()).thenReturn("text/html");
|
|
when(method.getResponseHeader("Content-Type")).thenReturn(header);
|
|
when(method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
|
|
when(method.isRequestSent()).thenReturn(true);
|
|
try {
|
|
connector.executeDeleteObject("/");
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteDeleteObjectException() throws CloudstackRESTException, IOException {
|
|
method = mock(DeleteMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_NO_CONTENT);
|
|
when(client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
|
|
try {
|
|
connector.executeDeleteObject("/");
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testExecuteRetrieveObject() throws CloudstackRESTException, IOException {
|
|
method = mock(GetMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
|
|
when(method.getResponseBodyAsString()).thenReturn(UUID_JSON_RESPONSE);
|
|
connector.executeRetrieveObject(JsonEntity.class, "/", Collections.<String, String> emptyMap());
|
|
verify(method, times(1)).releaseConnection();
|
|
verify(client, times(1)).executeMethod(method);
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteRetrieveObjectFailure() throws CloudstackRESTException, IOException {
|
|
method = mock(GetMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_INTERNAL_SERVER_ERROR);
|
|
when(method.getResponseBodyAsString()).thenReturn(UUID_JSON_RESPONSE);
|
|
final Header header = mock(Header.class);
|
|
when(header.getValue()).thenReturn("text/html");
|
|
when(method.getResponseHeader("Content-Type")).thenReturn(header);
|
|
when(method.getResponseBodyAsString()).thenReturn("Off to timbuktu, won't be back later.");
|
|
when(method.isRequestSent()).thenReturn(true);
|
|
try {
|
|
connector.executeRetrieveObject(JsonEntity.class, "/", Collections.<String, String> emptyMap());
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
@Test(expected = CloudstackRESTException.class)
|
|
public void testExecuteRetrieveObjectException() throws CloudstackRESTException, IOException {
|
|
method = mock(GetMethod.class);
|
|
when(method.getStatusCode()).thenReturn(HttpStatus.SC_OK);
|
|
when(method.getResponseBodyAsString()).thenReturn(UUID_JSON_RESPONSE);
|
|
when(client.executeMethod((HttpMethod)any())).thenThrow(new HttpException());
|
|
try {
|
|
connector.executeRetrieveObject(JsonEntity.class, "/", Collections.<String, String> emptyMap());
|
|
} finally {
|
|
verify(method, times(1)).releaseConnection();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class JsonEntity {
|
|
private String displayName;
|
|
private String uuid;
|
|
private String href;
|
|
private String schema;
|
|
|
|
public String getDisplayName() {
|
|
return displayName;
|
|
}
|
|
|
|
public void setDisplayName(final String displayName) {
|
|
this.displayName = displayName;
|
|
}
|
|
|
|
public String getUuid() {
|
|
return uuid;
|
|
}
|
|
|
|
public void setUuid(final String uuid) {
|
|
this.uuid = uuid;
|
|
}
|
|
|
|
public String getHref() {
|
|
return href;
|
|
}
|
|
|
|
public void setHref(final String href) {
|
|
this.href = href;
|
|
}
|
|
|
|
public String getSchema() {
|
|
return schema;
|
|
}
|
|
|
|
public void setSchema(final String schema) {
|
|
this.schema = schema;
|
|
}
|
|
} |