api: Discover tags field on superclass of API responses (#3005)

Updated ApiServiceDiscoveryImpl to check superclasses of API responses for fields.

Fixes: #3002
This commit is contained in:
Craig Squire 2018-12-04 02:29:48 -06:00 committed by Rohit Yadav
parent 89c567add8
commit 290df5f423
4 changed files with 90 additions and 54 deletions

View File

@ -16,15 +16,13 @@
// under the License.
package org.apache.cloudstack.api.response;
import java.util.HashSet;
import java.util.Set;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import java.util.HashSet;
import java.util.Set;
@SuppressWarnings("unused")
public class ApiDiscoveryResponse extends BaseResponse {
@ -121,4 +119,8 @@ public class ApiDiscoveryResponse extends BaseResponse {
public void addApiResponse(ApiResponseResponse apiResponse) {
this.apiResponse.add(apiResponse);
}
public Set<ApiResponseResponse> getApiResponse() {
return apiResponse;
}
}

View File

@ -16,15 +16,13 @@
// under the License.
package org.apache.cloudstack.api.response;
import java.util.HashSet;
import java.util.Set;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import com.cloud.serializer.Param;
import java.util.HashSet;
import java.util.Set;
public class ApiResponseResponse extends BaseResponse {
@SerializedName(ApiConstants.NAME)
@ -61,4 +59,20 @@ public class ApiResponseResponse extends BaseResponse {
}
this.apiResponse.add(childApiResponse);
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public String getType() {
return type;
}
public Set<ApiResponseResponse> getApiResponse() {
return apiResponse;
}
}

View File

@ -16,21 +16,13 @@
// under the License.
package org.apache.cloudstack.discovery;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.inject.Inject;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.serializer.Param;
import com.cloud.user.User;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentLifecycleBase;
import com.cloud.utils.component.PluggableService;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseAsyncCmd;
@ -43,13 +35,18 @@ import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
import org.apache.cloudstack.api.response.ApiParameterResponse;
import org.apache.cloudstack.api.response.ApiResponseResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.log4j.Logger;
import org.reflections.ReflectionUtils;
import org.springframework.stereotype.Component;
import com.cloud.serializer.Param;
import com.cloud.user.User;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentLifecycleBase;
import com.cloud.utils.component.PluggableService;
import javax.inject.Inject;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Component
public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements ApiDiscoveryService {
@ -100,7 +97,8 @@ public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements A
}
ApiDiscoveryResponse response = getCmdRequestMap(cmdClass, apiCmdAnnotation);
String responseName = apiCmdAnnotation.responseObject().getName();
Class<? extends BaseResponse> responseClass = apiCmdAnnotation.responseObject();
String responseName = responseClass.getName();
if (!responseName.contains("SuccessResponse")) {
if (!responseApiNameListMap.containsKey(responseName)) {
responseApiNameListMap.put(responseName, new ArrayList<String>());
@ -109,7 +107,7 @@ public class ApiDiscoveryServiceImpl extends ComponentLifecycleBase implements A
}
response.setRelated(responseName);
Field[] responseFields = apiCmdAnnotation.responseObject().getDeclaredFields();
Set<Field> responseFields = ReflectionUtils.getAllFields(responseClass);
for (Field responseField : responseFields) {
ApiResponseResponse responseResponse = getFieldResponseMap(responseField);
response.addApiResponse(responseResponse);

View File

@ -16,34 +16,36 @@
// under the License.
package org.apache.cloudstack.discovery;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.utils.component.PluggableService;
import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.command.user.discovery.ListApisCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
import org.apache.cloudstack.api.response.ApiResponseResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.commons.lang.StringUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import javax.naming.ConfigurationException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.naming.ConfigurationException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cloudstack.acl.APIChecker;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.command.user.discovery.ListApisCmd;
import org.apache.cloudstack.api.response.ApiDiscoveryResponse;
import org.apache.cloudstack.api.response.ListResponse;
import com.cloud.user.User;
import com.cloud.user.UserVO;
import com.cloud.utils.component.PluggableService;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class ApiDiscoveryTest {
private static APIChecker s_apiChecker = mock(APIChecker.class);
@ -51,14 +53,19 @@ public class ApiDiscoveryTest {
private static ApiDiscoveryServiceImpl s_discoveryService = new ApiDiscoveryServiceImpl();
private static Class<?> testCmdClass = ListApisCmd.class;
private static Class<?> listVMsCmdClass = ListVMsCmd.class;
private static User testUser;
private static String testApiName;
private static String listVmsCmdName;
private static String testApiDescription;
private static String testApiSince;
private static boolean testApiAsync;
@BeforeClass
public static void setUp() throws ConfigurationException {
listVmsCmdName = listVMsCmdClass.getAnnotation(APICommand.class).name();
testApiName = testCmdClass.getAnnotation(APICommand.class).name();
testApiDescription = testCmdClass.getAnnotation(APICommand.class).description();
testApiSince = testCmdClass.getAnnotation(APICommand.class).since();
@ -75,6 +82,7 @@ public class ApiDiscoveryTest {
Set<Class<?>> cmdClasses = new HashSet<Class<?>>();
cmdClasses.add(ListApisCmd.class);
cmdClasses.add(ListVMsCmd.class);
s_discoveryService.start();
s_discoveryService.cacheResponseMap(cmdClasses);
}
@ -82,6 +90,7 @@ public class ApiDiscoveryTest {
@Test
public void verifyListSingleApi() throws Exception {
ListResponse<ApiDiscoveryResponse> responses = (ListResponse<ApiDiscoveryResponse>)s_discoveryService.listApis(testUser, testApiName);
assertNotNull("Responses should not be null", responses);
if (responses != null) {
ApiDiscoveryResponse response = responses.getResponses().get(0);
assertTrue("No. of response items should be one", responses.getCount() == 1);
@ -95,12 +104,25 @@ public class ApiDiscoveryTest {
@Test
public void verifyListApis() throws Exception {
ListResponse<ApiDiscoveryResponse> responses = (ListResponse<ApiDiscoveryResponse>)s_discoveryService.listApis(testUser, null);
assertNotNull("Responses should not be null", responses);
if (responses != null) {
assertTrue("No. of response items > 1", responses.getCount().intValue() == 1);
assertTrue("No. of response items > 2", responses.getCount().intValue() == 2);
for (ApiDiscoveryResponse response : responses.getResponses()) {
assertFalse("API name is empty", response.getName().isEmpty());
assertFalse("API description is empty", response.getDescription().isEmpty());
}
}
}
@Test
public void verifyListVirtualMachinesTagsField() throws Exception {
ListResponse<ApiDiscoveryResponse> responses = (ListResponse<ApiDiscoveryResponse>)s_discoveryService.listApis(testUser, listVmsCmdName);
assertNotNull("Response should not be null", responses);
if (responses != null) {
assertEquals("No. of response items should be one", 1, (int) responses.getCount());
ApiDiscoveryResponse response = responses.getResponses().get(0);
List<ApiResponseResponse> tagsResponse = response.getApiResponse().stream().filter(resp -> StringUtils.equals(resp.getName(), "tags")).collect(Collectors.toList());
assertEquals("Tags field should be present in listVirtualMachines response fields", tagsResponse.size(), 1);
}
}
}