Repository: ambari
Updated Branches:
  refs/heads/feature-branch-AMBARI-21307 12c50a909 -> 3fd19fe70


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/3fd19fe7
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/3fd19fe7
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/3fd19fe7

Branch: refs/heads/feature-branch-AMBARI-21307
Commit: 3fd19fe7096f6227a769a21d6374a1c051b50fb0
Parents: 12c50a9
Author: Balazs Bence Sari <beny...@apache.org>
Authored: Tue Aug 8 20:17:14 2017 +0200
Committer: Balazs Bence Sari <beny...@apache.org>
Committed: Tue Aug 8 20:17:14 2017 +0200

----------------------------------------------------------------------
 .../services/AmbariConfigurationService.java    |   4 +-
 .../stackadvisor/StackAdvisorRequest.java       |  12 ++
 .../commands/StackAdvisorCommand.java           |  54 +++++
 .../commands/StackAdvisorCommandTest.java       | 212 +++++++++++++++++++
 .../StackAdvisorResourceProviderTest.java       |  92 ++++----
 5 files changed, 321 insertions(+), 53 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/3fd19fe7/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/3fd19fe7/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 7ba1b18..b90eae6 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
@@ -30,6 +30,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.
  */
@@ -47,6 +49,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;
@@ -92,6 +95,8 @@ public class StackAdvisorRequest {
     return configurations;
   }
 
+  public Map<String, Object> getLdapConfig() { return ldapConfig; }
+
   public List<ChangedConfigInfo> getChangedConfigurations() {
     return changedConfigurations;
   }
@@ -188,6 +193,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/3fd19fe7/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/3fd19fe7/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/3fd19fe7/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 6df8b8b..09eb13f 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,41 +27,33 @@ 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.List;
+import java.util.Iterator;
 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.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);
 
@@ -77,27 +69,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);
 
@@ -109,24 +111,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);
 
@@ -140,9 +127,12 @@ public class StackAdvisorResourceProviderTest {
 
     assertEquals("[array1, array2]", properties.get("array_prop"));
 
-
     // config properties with null values should be ignored
     assertFalse(properties.containsKey("string_prop"));
+  }
 
+  @Before
+  public void init() {
+    provider = createRecommendationResourceProvider();
   }
 }

Reply via email to