AMBARI-21545 Stack Advisor support for LDAP configuration (benyoka)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/9f9d2391 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/9f9d2391 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/9f9d2391 Branch: refs/heads/feature-branch-AMBARI-21307 Commit: 9f9d23914ec284572ad42b66ad19e3be102ffdd0 Parents: 8465f45 Author: Balazs Bence Sari <beny...@apache.org> Authored: Tue Aug 8 20:17:14 2017 +0200 Committer: lpuskas <lpus...@apache.org> Committed: Tue Sep 12 12:07:34 2017 +0200 ---------------------------------------------------------------------- .../services/AmbariConfigurationService.java | 4 +- .../stackadvisor/StackAdvisorRequest.java | 12 ++ .../commands/StackAdvisorCommand.java | 54 +++++ .../commands/StackAdvisorCommandTest.java | 212 +++++++++++++++++++ .../StackAdvisorResourceProviderTest.java | 97 ++++----- 5 files changed, 324 insertions(+), 55 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/9f9d2391/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java index 0632361..927e518 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/AmbariConfigurationService.java @@ -56,9 +56,9 @@ import io.swagger.annotations.ApiResponses; * "data": [ * { * "authentication.ldap.primaryUrl": "localhost:33389" - "authentication.ldap.secondaryUrl": "localhost:333" + * "authentication.ldap.secondaryUrl": "localhost:333" * "authentication.ldap.baseDn": "dc=ambari,dc=apache,dc=org" - * // ...... + * // ...... * ] * } * </pre> http://git-wip-us.apache.org/repos/asf/ambari/blob/9f9d2391/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java index 3a2b488..cd26c56 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/StackAdvisorRequest.java @@ -31,6 +31,8 @@ import org.apache.ambari.server.api.services.stackadvisor.recommendations.Recomm import org.apache.ambari.server.state.ChangedConfigInfo; import org.apache.commons.lang.StringUtils; +import com.google.common.base.Preconditions; + /** * Stack advisor request. */ @@ -48,6 +50,7 @@ public class StackAdvisorRequest { private List<ChangedConfigInfo> changedConfigurations = new LinkedList<>(); private Set<RecommendationResponse.ConfigGroup> configGroups; private Map<String, String> userContext = new HashMap<>(); + private Map<String, Object> ldapConfig = new HashMap<>(); public String getStackName() { return stackName; @@ -93,6 +96,8 @@ public class StackAdvisorRequest { return configurations; } + public Map<String, Object> getLdapConfig() { return ldapConfig; } + public List<ChangedConfigInfo> getChangedConfigurations() { return changedConfigurations; } @@ -189,6 +194,13 @@ public class StackAdvisorRequest { return this; } + public StackAdvisorRequestBuilder withLdapConfig(Map<String, Object> ldapConfig) { + Preconditions.checkNotNull(ldapConfig); + this.instance.ldapConfig = ldapConfig; + return this; + } + + public StackAdvisorRequest build() { return this.instance; } http://git-wip-us.apache.org/repos/asf/ambari/blob/9f9d2391/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java index 356754d..2dc45de 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommand.java @@ -84,6 +84,7 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend + ",services/configurations/dependencies/StackConfigurationDependency/dependency_name" + ",services/configurations/dependencies/StackConfigurationDependency/dependency_type,services/configurations/StackConfigurations/type" + "&services/StackServices/service_name.in(%s)"; + private static final String GET_LDAP_CONFIG_URI = "/api/v1/configurations?AmbariConfiguration/type=ldap&fields=AmbariConfiguration/*"; private static final String SERVICES_PROPERTY = "services"; private static final String SERVICES_COMPONENTS_PROPERTY = "components"; private static final String CONFIG_GROUPS_PROPERTY = "config-groups"; @@ -95,6 +96,7 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend private static final String CHANGED_CONFIGURATIONS_PROPERTY = "changed-configurations"; private static final String USER_CONTEXT_PROPERTY = "user-context"; private static final String AMBARI_SERVER_CONFIGURATIONS_PROPERTY = "ambari-server-properties"; + protected static final String LDAP_CONFIGURATION_PROPERTY = "ldap-configuration"; private File recommendationsDir; private String recommendationsArtifactsLifetime; @@ -160,6 +162,7 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend populateConfigurations(root, request); populateConfigGroups(root, request); populateAmbariServerInfo(root); + populateLdapConfiguration(root); data.servicesJSON = mapper.writeValueAsString(root); } catch (Exception e) { // should not happen @@ -171,6 +174,52 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend return data; } + /** + * Retrieves the LDAP configuration if exists and adds it to services.json + * @param root The JSON document that will become service.json when passed to the stack advisor engine + * @throws StackAdvisorException + * @throws IOException + */ + protected void populateLdapConfiguration(ObjectNode root) throws StackAdvisorException, IOException { + Response response = handleRequest(null, null, new LocalUriInfo(GET_LDAP_CONFIG_URI), Request.Type.GET, + createConfigResource()); + + if (response.getStatus() != Status.OK.getStatusCode()) { + String message = String.format( + "Error occured during retrieving ldap configuration, status=%s, response=%s", + response.getStatus(), (String) response.getEntity()); + LOG.warn(message); + throw new StackAdvisorException(message); + } + + String ldapConfigJSON = (String) response.getEntity(); + if (LOG.isDebugEnabled()) { + LOG.debug("LDAP configuration: {}", ldapConfigJSON); + } + + JsonNode ldapConfigRoot = mapper.readTree(ldapConfigJSON); + ArrayNode ldapConfigs = ((ArrayNode)ldapConfigRoot.get("items")); + int numConfigs = ldapConfigs.size(); + // Zero or one config may exist + switch (numConfigs) { + case 0: + LOG.debug("No LDAP config is stored in the DB"); + break; + case 1: + ArrayNode ldapConfigData = (ArrayNode)ldapConfigs.get(0).get("AmbariConfiguration").get("data"); + if (ldapConfigData.size() == 0) { + throw new StackAdvisorException("No configuration data for LDAP configuration."); + } + if (ldapConfigData.size() > 1) { + throw new StackAdvisorException("Ambigous configuration data for LDAP configuration."); + } + root.put(LDAP_CONFIGURATION_PROPERTY, ldapConfigData.get(0)); + break; + default: + throw new StackAdvisorException(String.format("Multiple (%s) LDAP configs are found in the DB.", numConfigs)); + } + } + protected void populateAmbariServerInfo(ObjectNode root) throws StackAdvisorException { Map<String, String> serverProperties = metaInfo.getAmbariServerProperties(); @@ -437,6 +486,11 @@ public abstract class StackAdvisorCommand<T extends StackAdvisorResponse> extend return createResource(Resource.Type.Host, mapIds); } + protected ResourceInstance createConfigResource() { + return createResource(Resource.Type.AmbariConfiguration, new HashMap<>()); + } + + private ResourceInstance createStackVersionResource(String stackName, String stackVersion) { Map<Resource.Type, String> mapIds = new HashMap<>(); mapIds.put(Resource.Type.Stack, stackName); http://git-wip-us.apache.org/repos/asf/ambari/blob/9f9d2391/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java index eaa4716..959db15 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/stackadvisor/commands/StackAdvisorCommandTest.java @@ -18,6 +18,7 @@ package org.apache.ambari.server.api.services.stackadvisor.commands; +import static org.apache.ambari.server.api.services.stackadvisor.commands.StackAdvisorCommand.LDAP_CONFIGURATION_PROPERTY; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -33,12 +34,21 @@ import java.io.File; import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.Iterator; +import java.util.List; import java.util.Map; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.HttpHeaders; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; +import org.apache.ambari.server.api.resources.ResourceInstance; import org.apache.ambari.server.api.services.AmbariMetaInfo; +import org.apache.ambari.server.api.services.Request; +import org.apache.ambari.server.api.services.ResultStatus; import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorException; import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest; import org.apache.ambari.server.api.services.stackadvisor.StackAdvisorRequest.StackAdvisorRequestBuilder; @@ -50,6 +60,7 @@ import org.apache.ambari.server.state.ServiceInfo; import org.apache.commons.io.FileUtils; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.node.ArrayNode; import org.codehaus.jackson.node.ObjectNode; import org.junit.After; @@ -59,6 +70,8 @@ import org.junit.rules.TemporaryFolder; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import com.google.common.collect.Lists; + /** * StackAdvisorCommand unit tests. */ @@ -265,6 +278,197 @@ public class StackAdvisorCommandTest { assertEquals(0, stackVersions.size()); } + @Test + public void testPopulateLdapConfig() throws Exception { + File recommendationsDir = temp.newFolder("recommendationDir"); + String recommendationsArtifactsLifetime = "1w"; + int requestId = 0; + StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class); + AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class); + doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString()); + TestStackAdvisorCommand command = spy(new TestStackAdvisorCommand(recommendationsDir, recommendationsArtifactsLifetime, + ServiceInfo.ServiceAdvisorType.PYTHON, requestId, saRunner, metaInfo)); + + StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion").build(); + + Map<String, Object> ldapConfigData = map( + "authentication.ldap.primaryUrl", "localhost:33389", + "authentication.ldap.secondaryUrl", "localhost:333", + "authentication.ldap.baseDn", "c=ambari,dc=apache,dc=org" + ); + + Map<String, Object> storedLdapConfigResult = map( + "items", + list( + map( + "AmbariConfiguration", + map( + "data", list(ldapConfigData) + ) + ) + ) + ); + + Response response = + Response.status(ResultStatus.STATUS.OK.getStatus()).entity(jsonString(storedLdapConfigResult)).build(); + + doReturn(response).when(command).handleRequest(any(), any(), any(), any(), any(), any()); + + JsonNode servicesRootNode = json("{}"); + command.populateLdapConfiguration((ObjectNode)servicesRootNode); + + JsonNode expectedLdapConfig = json( + map(LDAP_CONFIGURATION_PROPERTY, ldapConfigData) + ); + + assertEquals(expectedLdapConfig, servicesRootNode); + } + + @Test + public void testPopulateLdapConfig_NoConfigs() throws Exception { + File recommendationsDir = temp.newFolder("recommendationDir"); + String recommendationsArtifactsLifetime = "1w"; + int requestId = 0; + StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class); + AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class); + doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString()); + TestStackAdvisorCommand command = spy(new TestStackAdvisorCommand(recommendationsDir, recommendationsArtifactsLifetime, + ServiceInfo.ServiceAdvisorType.PYTHON, requestId, saRunner, metaInfo)); + + StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion").build(); + + Map<String, Object> storedLdapConfigResult = map( + "items", list() + ); + + Response response = + Response.status(ResultStatus.STATUS.OK.getStatus()).entity(jsonString(storedLdapConfigResult)).build(); + + doReturn(response).when(command).handleRequest(any(), any(), any(), any(), any(), any()); + + JsonNode servicesRootNode = json("{}"); + command.populateLdapConfiguration((ObjectNode)servicesRootNode); + + JsonNode expectedLdapConfig = json("{}"); + + assertEquals(expectedLdapConfig, servicesRootNode); + } + + /** + * An ambigous ldap config that has two items in its data[] array should result in exception + */ + @Test(expected = StackAdvisorException.class) + public void testPopulateLdapConfig_multipleConfigs() throws Exception { + File recommendationsDir = temp.newFolder("recommendationDir"); + String recommendationsArtifactsLifetime = "1w"; + int requestId = 0; + StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class); + AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class); + doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString()); + TestStackAdvisorCommand command = spy(new TestStackAdvisorCommand(recommendationsDir, recommendationsArtifactsLifetime, + ServiceInfo.ServiceAdvisorType.PYTHON, requestId, saRunner, metaInfo)); + + StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion").build(); + + Map<String, Object> ldapConfigData = map( + "authentication.ldap.primaryUrl", "localhost:33389", + "authentication.ldap.secondaryUrl", "localhost:333", + "authentication.ldap.baseDn", "c=ambari,dc=apache,dc=org" + ); + + Map<String, Object> storedLdapConfigResult = map( + "items", + list( + map( + "AmbariConfiguration", + map( + "data", + list(ldapConfigData, ldapConfigData) + ) + ) + ) + ); + + Response response = + Response.status(ResultStatus.STATUS.OK.getStatus()).entity(jsonString(storedLdapConfigResult)).build(); + + doReturn(response).when(command).handleRequest(any(), any(), any(), any(), any(), any()); + + JsonNode servicesRootNode = json("{}"); + command.populateLdapConfiguration((ObjectNode)servicesRootNode); + } + + /** + * An if multiple ambari configurations are stored with 'ldap-config' type, an + * exception should be thrown + */ + @Test(expected = StackAdvisorException.class) + public void testPopulateLdapConfig_multipleResults() throws Exception { + File recommendationsDir = temp.newFolder("recommendationDir"); + String recommendationsArtifactsLifetime = "1w"; + int requestId = 0; + StackAdvisorRunner saRunner = mock(StackAdvisorRunner.class); + AmbariMetaInfo metaInfo = mock(AmbariMetaInfo.class); + doReturn(Collections.emptyList()).when(metaInfo).getStackParentVersions(anyString(), anyString()); + TestStackAdvisorCommand command = spy(new TestStackAdvisorCommand(recommendationsDir, recommendationsArtifactsLifetime, + ServiceInfo.ServiceAdvisorType.PYTHON, requestId, saRunner, metaInfo)); + + StackAdvisorRequest request = StackAdvisorRequestBuilder.forStack("stackName", "stackVersion") + .build(); + + Map<String, Object> ldapConfig = map( + "AmbariConfiguration", + map( + "data", + list( + map( + "authentication.ldap.primaryUrl", "localhost:33389", + "authentication.ldap.secondaryUrl", "localhost:333", + "authentication.ldap.baseDn", "c=ambari,dc=apache,dc=org" + ) + ) + ) + ); + + Map<String, Object> storedLdapConfigResult = map( + "items", + list(ldapConfig, ldapConfig) + ); + + Response response = + Response.status(ResultStatus.STATUS.OK.getStatus()).entity(jsonString(storedLdapConfigResult)).build(); + + doReturn(response).when(command).handleRequest(any(), any(), any(), any(), any(), any()); + + JsonNode servicesRootNode = json("{}"); + command.populateLdapConfiguration((ObjectNode)servicesRootNode); + } + + private static String jsonString(Object obj) throws IOException { + return new ObjectMapper().writeValueAsString(obj); + } + + private static JsonNode json(Object obj) throws IOException { + return new ObjectMapper().convertValue(obj, JsonNode.class); + } + + private static JsonNode json(String jsonString) throws IOException { + return new ObjectMapper().readTree(jsonString); + } + + private static List<Object> list(Object... items) { + return Lists.newArrayList(items); + } + + private static Map<String, Object> map(Object... keysAndValues) { + Map<String, Object> map = new HashMap<>(); + Iterator<Object> iterator = Arrays.asList(keysAndValues).iterator(); + while (iterator.hasNext()) { + map.put(iterator.next().toString(), iterator.next()); + } + return map; + } + class TestStackAdvisorCommand extends StackAdvisorCommand<TestResource> { public TestStackAdvisorCommand(File recommendationsDir, String recommendationsArtifactsLifetime, ServiceInfo.ServiceAdvisorType serviceAdvisorType, int requestId, StackAdvisorRunner saRunner, AmbariMetaInfo metaInfo) { @@ -290,6 +494,14 @@ public class StackAdvisorCommandTest { protected TestResource updateResponse(StackAdvisorRequest request, TestResource response) { return response; } + + // Overridden to ensure visiblity in tests + @Override + public javax.ws.rs.core.Response handleRequest(HttpHeaders headers, String body, + UriInfo uriInfo, Request.Type requestType, + MediaType mediaType, ResourceInstance resource) { + return super.handleRequest(headers, body, uriInfo, requestType, mediaType, resource); + } } public static class TestResource extends StackAdvisorResponse { http://git-wip-us.apache.org/repos/asf/ambari/blob/9f9d2391/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackAdvisorResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackAdvisorResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackAdvisorResourceProviderTest.java index ab60948..05232ea 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackAdvisorResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/StackAdvisorResourceProviderTest.java @@ -27,43 +27,35 @@ import static org.junit.Assert.assertNotNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; -import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.Nonnull; + import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.spi.Request; import org.apache.ambari.server.controller.spi.Resource; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import com.google.common.collect.Lists; + public class StackAdvisorResourceProviderTest { + private RecommendationResourceProvider provider; + @Test public void testCalculateConfigurations() throws Exception { - - Map<Resource.Type, String> keyPropertyIds = Collections.emptyMap(); - Set<String> propertyIds = Collections.emptySet(); - AmbariManagementController ambariManagementController = mock(AmbariManagementController.class); - RecommendationResourceProvider provider = new RecommendationResourceProvider(propertyIds, - keyPropertyIds, ambariManagementController); - - Request request = mock(Request.class); - Set<Map<String, Object>> propertiesSet = new HashSet<>(); - Map<String, Object> propertiesMap = new HashMap<>(); - propertiesMap.put(CONFIGURATIONS_PROPERTY_ID + "site/properties/string_prop", "string"); - List<Object> array = new ArrayList<>(); - array.add("array1"); - array.add("array2"); - propertiesMap.put(CONFIGURATIONS_PROPERTY_ID + "site/properties/array_prop", array); - propertiesSet.add(propertiesMap); - - doReturn(propertiesSet).when(request).getProperties(); + Request request = createMockRequest( + CONFIGURATIONS_PROPERTY_ID + "site/properties/string_prop", "string", + CONFIGURATIONS_PROPERTY_ID + "site/properties/array_prop", Lists.newArrayList("array1", "array2")); Map<String, Map<String, Map<String, String>>> calculatedConfigurations = provider.calculateConfigurations(request); @@ -79,27 +71,37 @@ public class StackAdvisorResourceProviderTest { assertEquals("[array1, array2]", properties.get("array_prop")); } - @Test - public void testReadUserContext() throws Exception { - + @Nonnull + private RecommendationResourceProvider createRecommendationResourceProvider() { Map<Resource.Type, String> keyPropertyIds = Collections.emptyMap(); Set<String> propertyIds = Collections.emptySet(); AmbariManagementController ambariManagementController = mock(AmbariManagementController.class); - RecommendationResourceProvider provider = new RecommendationResourceProvider(propertyIds, - keyPropertyIds, ambariManagementController); + return new RecommendationResourceProvider(propertyIds, + keyPropertyIds, ambariManagementController); + } + @Nonnull + private Request createMockRequest(Object... propertyKeysAndValues) { Request request = mock(Request.class); Set<Map<String, Object>> propertiesSet = new HashSet<>(); Map<String, Object> propertiesMap = new HashMap<>(); - propertiesMap.put(CONFIGURATIONS_PROPERTY_ID + "site/properties/string_prop", "string"); - List<Object> array = new ArrayList<>(); - array.add("array1"); - array.add("array2"); - propertiesMap.put(USER_CONTEXT_OPERATION_PROPERTY, "op1"); - propertiesMap.put(USER_CONTEXT_OPERATION_DETAILS_PROPERTY, "op_det"); + Iterator<Object> it = Arrays.asList(propertyKeysAndValues).iterator(); + while(it.hasNext()) { + String key = (String)it.next(); + Object value = it.next(); + propertiesMap.put(key, value); + } propertiesSet.add(propertiesMap); - doReturn(propertiesSet).when(request).getProperties(); + return request; + } + + @Test + public void testReadUserContext() throws Exception { + Request request = createMockRequest( + CONFIGURATIONS_PROPERTY_ID + "site/properties/string_prop", "string", + USER_CONTEXT_OPERATION_PROPERTY, "op1", + USER_CONTEXT_OPERATION_DETAILS_PROPERTY, "op_det"); Map<String, String> userContext = provider.readUserContext(request); @@ -111,24 +113,9 @@ public class StackAdvisorResourceProviderTest { @Test public void testCalculateConfigurationsWithNullPropertyValues() throws Exception { - - Map<Resource.Type, String> keyPropertyIds = Collections.emptyMap(); - Set<String> propertyIds = Collections.emptySet(); - AmbariManagementController ambariManagementController = mock(AmbariManagementController.class); - RecommendationResourceProvider provider = new RecommendationResourceProvider(propertyIds, - keyPropertyIds, ambariManagementController); - - Request request = mock(Request.class); - Set<Map<String, Object>> propertiesSet = new HashSet<>(); - Map<String, Object> propertiesMap = new HashMap<>(); - propertiesMap.put(CONFIGURATIONS_PROPERTY_ID + "site/properties/string_prop", null); //null value means no value specified for the property - List<Object> array = new ArrayList<>(); - array.add("array1"); - array.add("array2"); - propertiesMap.put(CONFIGURATIONS_PROPERTY_ID + "site/properties/array_prop", array); - propertiesSet.add(propertiesMap); - - doReturn(propertiesSet).when(request).getProperties(); + Request request = createMockRequest( + CONFIGURATIONS_PROPERTY_ID + "site/properties/string_prop", null, + CONFIGURATIONS_PROPERTY_ID + "site/properties/array_prop", Lists.newArrayList("array1", "array2")); Map<String, Map<String, Map<String, String>>> calculatedConfigurations = provider.calculateConfigurations(request); @@ -142,19 +129,18 @@ public class StackAdvisorResourceProviderTest { assertEquals("[array1, array2]", properties.get("array_prop")); - // config properties with null values should be ignored assertFalse(properties.containsKey("string_prop")); - } + @Test public void testStackAdvisorWithEmptyHosts() { Map<Resource.Type, String> keyPropertyIds = Collections.emptyMap(); Set<String> propertyIds = Collections.emptySet(); AmbariManagementController ambariManagementController = mock(AmbariManagementController.class); RecommendationResourceProvider provider = new RecommendationResourceProvider(propertyIds, - keyPropertyIds, ambariManagementController); + keyPropertyIds, ambariManagementController); Request request = mock(Request.class); Set<Map<String, Object>> propertiesSet = new HashSet<>(); @@ -170,4 +156,9 @@ public class StackAdvisorResourceProviderTest { } catch (Exception e) { } } + + @Before + public void init() { + provider = createRecommendationResourceProvider(); + } }