Repository: ambari Updated Branches: refs/heads/trunk b2f392d8f -> ee4e786a4
AMBARI-9410. Allow cluster and service artifacts to be updated and deleted Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ee4e786a Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ee4e786a Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ee4e786a Branch: refs/heads/trunk Commit: ee4e786a4daf639da34ea81a7ff1a11f3dad378f Parents: b2f392d Author: John Speidel <jspei...@hortonworks.com> Authored: Thu Jan 29 17:27:14 2015 -0500 Committer: John Speidel <jspei...@hortonworks.com> Committed: Fri Jan 30 11:54:39 2015 -0500 ---------------------------------------------------------------------- .../server/api/services/ClusterService.java | 124 ++++++++-- .../server/api/services/ServiceService.java | 92 ++++++++ .../internal/ArtifactResourceProvider.java | 84 ++++++- .../ambari/server/orm/dao/ArtifactDAO.java | 22 +- .../server/api/services/ClusterServiceTest.java | 50 +++- .../server/api/services/ServiceServiceTest.java | 59 +++++ .../internal/ArtifactResourceProviderTest.java | 235 ++++++++++++++++--- 7 files changed, 607 insertions(+), 59 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java index 5f44b2f..a794693 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ClusterService.java @@ -185,10 +185,10 @@ public class ClusterService extends BaseService { @GET @Path("{clusterName}/artifacts") @Produces("text/plain") - public Response getClusterArtifacts(String body, - @Context HttpHeaders headers, - @Context UriInfo ui, - @PathParam("clusterName") String clusterName) { + public Response getArtifacts(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName) { hasPermission(Request.Type.GET, clusterName); return handleRequest(headers, body, ui, Request.Type.GET, @@ -210,11 +210,11 @@ public class ClusterService extends BaseService { @GET @Path("{clusterName}/artifacts/{artifactName}") @Produces("text/plain") - public Response getClusterArtifact(String body, - @Context HttpHeaders headers, - @Context UriInfo ui, - @PathParam("clusterName") String clusterName, - @PathParam("artifactName") String artifactName) { + public Response getArtifact(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName, + @PathParam("artifactName") String artifactName) { hasPermission(Request.Type.GET, clusterName); return handleRequest(headers, body, ui, Request.Type.GET, @@ -235,11 +235,11 @@ public class ClusterService extends BaseService { @POST @Path("{clusterName}/artifacts/{artifactName}") @Produces("text/plain") - public Response createClusterArtifact(String body, - @Context HttpHeaders headers, - @Context UriInfo ui, - @PathParam("clusterName") String clusterName, - @PathParam("artifactName") String artifactName) { + public Response createArtifact(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName, + @PathParam("artifactName") String artifactName) { hasPermission(Request.Type.POST, clusterName); return handleRequest(headers, body, ui, Request.Type.POST, @@ -247,6 +247,102 @@ public class ClusterService extends BaseService { } /** + * Handles: PUT /clusters/{clusterID}/artifacts + * Update all artifacts matching the provided predicate. + * + * @param headers http headers + * @param ui uri info + * @param clusterName cluster name + * + * @return information regarding the updated artifacts + */ + @PUT + @Path("{clusterName}/artifacts") + @Produces("text/plain") + public Response updateArtifacts(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName) { + + hasPermission(Request.Type.PUT, clusterName); + return handleRequest(headers, body, ui, Request.Type.PUT, + createArtifactResource(clusterName, null)); + } + + /** + * Handles: PUT /clusters/{clusterID}/artifacts/{artifactName} + * Update a specific artifact. + * + * @param headers http headers + * @param ui uri info + * @param clusterName cluster name + * @param artifactName artifactName + * + * @return information regarding the updated artifact + */ + @PUT + @Path("{clusterName}/artifacts/{artifactName}") + @Produces("text/plain") + public Response updateArtifact(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName, + @PathParam("artifactName") String artifactName) { + + hasPermission(Request.Type.PUT, clusterName); + return handleRequest(headers, body, ui, Request.Type.PUT, + createArtifactResource(clusterName, artifactName)); + } + + /** + * Handles: DELETE /clusters/{clusterID}/artifacts/{artifactName} + * Delete a specific artifact. + * + * @param headers http headers + * @param ui uri info + * @param clusterName cluster name + * @param artifactName artifactName + * + * @return information regarding the deleted artifact + */ + @DELETE + @Path("{clusterName}/artifacts/{artifactName}") + @Produces("text/plain") + public Response deleteArtifact(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName, + @PathParam("artifactName") String artifactName) { + + hasPermission(Request.Type.DELETE, clusterName); + return handleRequest(headers, body, ui, Request.Type.DELETE, + createArtifactResource(clusterName, artifactName)); + } + + /** + * Handles: DELETE /clusters/{clusterID}/artifacts + * Delete all artifacts matching the provided predicate. + * + * @param headers http headers + * @param ui uri info + * @param clusterName cluster name + * + * @return information regarding the deleted artifacts + */ + @DELETE + @Path("{clusterName}/artifacts") + @Produces("text/plain") + public Response deleteArtifacts(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("clusterName") String clusterName) { + + hasPermission(Request.Type.DELETE, clusterName); + return handleRequest(headers, body, ui, Request.Type.DELETE, + createArtifactResource(clusterName, null)); + } + + /** * Get the hosts sub-resource * * @param request the request http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java index 8a2642b..ad6d68c 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/api/services/ServiceService.java @@ -273,6 +273,98 @@ public class ServiceService extends BaseService { } /** + * Handles: PUT /clusters/{clusterID}/services/{serviceName}/artifacts + * Update all artifacts matching the provided predicate. + * + * @param headers http headers + * @param ui uri info + * @param serviceName service name + * + * @return information regarding the updated artifacts + */ + @PUT + @Path("{serviceName}/artifacts") + @Produces("text/plain") + public Response updateArtifacts(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("serviceName") String serviceName) { + + return handleRequest(headers, body, ui, Request.Type.PUT, + createArtifactResource(m_clusterName, serviceName, null)); + } + + /** + * Handles: PUT /clusters/{clusterID}/services/{serviceName}/artifacts/{artifactName} + * Update a specific artifact. + * + * @param headers http headers + * @param ui uri info + * @param serviceName service name + * @param artifactName artifact name + * + * @return information regarding the updated artifact + */ + @PUT + @Path("{serviceName}/artifacts/{artifactName}") + @Produces("text/plain") + public Response updateArtifact(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("serviceName") String serviceName, + @PathParam("artifactName") String artifactName) { + + return handleRequest(headers, body, ui, Request.Type.PUT, + createArtifactResource(m_clusterName, serviceName, artifactName)); + } + + /** + * Handles: DELETE /clusters/{clusterID}/services/{serviceName}/artifacts + * Delete all artifacts matching the provided predicate. + * + * @param headers http headers + * @param ui uri info + * @param serviceName service name + * + * @return information regarding the deleted artifacts + */ + @DELETE + @Path("{serviceName}/artifacts") + @Produces("text/plain") + public Response deleteArtifacts(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("serviceName") String serviceName) { + + return handleRequest(headers, body, ui, Request.Type.DELETE, + createArtifactResource(m_clusterName, serviceName, null)); + } + + /** + * Handles: DELETE /clusters/{clusterID}/services/{serviceName}/artifacts/{artifactName} + * Delete a specific artifact. + * + * @param headers http headers + * @param ui uri info + * @param serviceName service name + * @param artifactName artifact name + * + * @return information regarding the deleted artifact + */ + @DELETE + @Path("{serviceName}/artifacts/{artifactName}") + @Produces("text/plain") + public Response deleteArtifact(String body, + @Context HttpHeaders headers, + @Context UriInfo ui, + @PathParam("serviceName") String serviceName, + @PathParam("artifactName") String artifactName) { + + return handleRequest(headers, body, ui, Request.Type.DELETE, + createArtifactResource(m_clusterName, serviceName, artifactName)); + } + + /** * Gets the alert history service * * @param request http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java index e476f62..680f9b8 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ArtifactResourceProvider.java @@ -216,13 +216,18 @@ public class ArtifactResourceProvider extends AbstractResourceProvider { } @Override - public RequestStatus updateResources(Request request, Predicate predicate) + public RequestStatus updateResources(final Request request, Predicate predicate) throws SystemException, UnsupportedPropertyException, NoSuchResourceException, NoSuchParentResourceException { - throw new UnsupportedOperationException("Update not currently supported for Artifact resources"); + for (Resource resource : getResources(request, predicate)) { + modifyResources(getUpdateCommand(request, resource)); + } + + notifyUpdate(Resource.Type.Artifact, request, predicate); + return getRequestStatus(null); } @Override @@ -232,11 +237,20 @@ public class ArtifactResourceProvider extends AbstractResourceProvider { NoSuchResourceException, NoSuchParentResourceException { - throw new UnsupportedOperationException("Delete not currently supported for Artifact resources"); + // get resources to update + Set<Resource> setResources = getResources( + new RequestImpl(null, null, null, null), predicate); + + for (final Resource resource : setResources) { + modifyResources(getDeleteCommand(resource)); + } + + notifyDelete(Resource.Type.Artifact, predicate); + return getRequestStatus(null); } /** - * Create a command to create the resource. + * Create a command to create a resource. * * @param properties request properties * @param requestInfoProps request info properties @@ -314,6 +328,65 @@ public class ArtifactResourceProvider extends AbstractResourceProvider { } /** + * Create a command to update a resource. + * + * @param request update request + * @param resource resource to update + * + * @return a update resource command + */ + private Command<Void> getUpdateCommand(final Request request, final Resource resource) { + return new Command<Void>() { + @Override + public Void invoke() throws AmbariException { + Map<String, Object> entityUpdateProperties = + new HashMap<String, Object>(request.getProperties().iterator().next()); + + // ensure name is set. It won't be in case of query + entityUpdateProperties.put(ARTIFACT_NAME_PROPERTY, + String.valueOf(resource.getPropertyValue(ARTIFACT_NAME_PROPERTY))); + + artifactDAO.merge(toEntity(entityUpdateProperties, + request.getRequestInfoProperties().get(Request.REQUEST_INFO_BODY_PROPERTY))); + + return null; + } + }; + } + + /** + * Create a command to delete a resource. + * + * @param resource the resource to delete + * + * @return a delete resource command + */ + private Command<Void> getDeleteCommand(final Resource resource) { + return new Command<Void>() { + @Override + public Void invoke() throws AmbariException { + Map<String, Object> keyProperties = new HashMap<String, Object>(); + + // flatten out key properties as is expected by createForeignKeyMap() + for (Map.Entry<String, Object> entry : resource.getPropertiesMap().get("Artifacts").entrySet()) { + keyProperties.put(String.format("Artifacts/%s", entry.getKey()), entry.getValue()); + } + + // create entity and set properties + final ArtifactEntity entity = new ArtifactEntity(); + entity.setArtifactName(String.valueOf(resource.getPropertyValue(ARTIFACT_NAME_PROPERTY))); + entity.setForeignKeys(createForeignKeyMap(keyProperties)); + + LOG.info("Deleting Artifact, name = {}, foreign keys = {}", + entity.getArtifactName(), entity.getForeignKeys()); + + artifactDAO.remove(entity); + return null; + } + }; + } + + /** * Validate that parent resources exist. * * @param properties request properties @@ -394,6 +467,9 @@ public class ArtifactResourceProvider extends AbstractResourceProvider { rawRequestBody, Map.class); Object artifactData = rawBodyMap.get(ARTIFACT_DATA_PROPERTY); + if (artifactData == null) { + throw new IllegalArgumentException("artifact_data property must be provided"); + } if (! (artifactData instanceof Map)) { throw new IllegalArgumentException("artifact_data property must be a map"); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ArtifactDAO.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ArtifactDAO.java b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ArtifactDAO.java index 4b7cf25..27346dd 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ArtifactDAO.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/orm/dao/ArtifactDAO.java @@ -30,7 +30,6 @@ import javax.persistence.EntityManager; import javax.persistence.NoResultException; import javax.persistence.TypedQuery; import java.util.List; -import java.util.Map; import java.util.TreeMap; @@ -106,4 +105,25 @@ public class ArtifactDAO { public void create(ArtifactEntity entity) { entityManagerProvider.get().persist(entity); } + + /** + * Merge the state of the given entity into the current persistence context. + * + * @param artifactEntity entity to merge + * @return the merged entity + */ + @Transactional + public ArtifactEntity merge(ArtifactEntity artifactEntity) { + return entityManagerProvider.get().merge(artifactEntity); + } + + /** + * Remove the entity instance. + * + * @param artifactEntity entity to remove + */ + @Transactional + public void remove(ArtifactEntity artifactEntity) { + entityManagerProvider.get().remove(merge(artifactEntity)); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java index c8f020e..c36f5fe 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ClusterServiceTest.java @@ -66,7 +66,7 @@ public class ClusterServiceTest extends BaseServiceTest { args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName"}; listInvocations.add(new ServiceTestInvocation(Request.Type.POST, clusterService, m, args, "body")); - //createCluster + //updateCluster clusterService = new TestClusterService(clusters, "clusterName"); m = clusterService.getClass().getMethod("updateCluster", String.class, HttpHeaders.class, UriInfo.class, String.class); args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName"}; @@ -78,6 +78,48 @@ public class ClusterServiceTest extends BaseServiceTest { args = new Object[] {getHttpHeaders(), getUriInfo(), "clusterName"}; listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, clusterService, m, args, null)); + //createArtifact + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("createArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.POST, clusterService, m, args, "body")); + + //getArtifact + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("getArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName", "artifact_name"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.GET, clusterService, m, args, "body")); + + //getArtifacts + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("getArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.GET, clusterService, m, args, "body")); + + //updateArtifact + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("updateArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.PUT, clusterService, m, args, "body")); + + //updateArtifacts + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("updateArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.PUT, clusterService, m, args, "body")); + + //deleteArtifact + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("deleteArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, clusterService, m, args, "body")); + + //deleteArtifacts + clusterService = new TestClusterService(clusters, "clusterName"); + m = clusterService.getClass().getMethod("deleteArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "clusterName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, clusterService, m, args, "body")); + return listInvocations; } @@ -97,6 +139,12 @@ public class ClusterServiceTest extends BaseServiceTest { } @Override + ResourceInstance createArtifactResource(String clusterName, String artifactName) { + assertEquals(m_clusterId, clusterName); + return getTestResource(); + } + + @Override RequestFactory getRequestFactory() { return getTestRequestFactory(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java index 5ca3fb3..5c3e3a7 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/api/services/ServiceServiceTest.java @@ -81,12 +81,56 @@ public class ServiceServiceTest extends BaseServiceTest { args = new Object[] {getHttpHeaders(), getUriInfo(), "serviceName"}; listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, service, m, args, null)); + //createArtifact + service = new TestServiceService("clusterName", "serviceName", "artifactName"); + m = service.getClass().getMethod("createArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.POST, service, m, args, "body")); + + //getArtifact + service = new TestServiceService("clusterName", "serviceName", "artifactName"); + m = service.getClass().getMethod("getArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, "body")); + + //getArtifacts + service = new TestServiceService("clusterName", "serviceName"); + m = service.getClass().getMethod("getArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.GET, service, m, args, "body")); + + //updateArtifact + service = new TestServiceService("clusterName", "serviceName", "artifactName"); + m = service.getClass().getMethod("updateArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.PUT, service, m, args, "body")); + + //updateArtifacts + service = new TestServiceService("clusterName", "serviceName"); + m = service.getClass().getMethod("updateArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.PUT, service, m, args, "body")); + + //deleteArtifact + service = new TestServiceService("clusterName", "serviceName", "artifactName"); + m = service.getClass().getMethod("deleteArtifact", String.class, HttpHeaders.class, UriInfo.class, String.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName", "artifactName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, service, m, args, "body")); + + //deleteArtifacts + service = new TestServiceService("clusterName", "serviceName"); + m = service.getClass().getMethod("deleteArtifacts", String.class, HttpHeaders.class, UriInfo.class, String.class); + args = new Object[] {"body", getHttpHeaders(), getUriInfo(), "serviceName"}; + listInvocations.add(new ServiceTestInvocation(Request.Type.DELETE, service, m, args, "body")); + + return listInvocations; } private class TestServiceService extends ServiceService { private String m_clusterId; private String m_serviceId; + private String m_artifact_id; private TestServiceService(String clusterId, String serviceId) { super(clusterId); @@ -94,6 +138,13 @@ public class ServiceServiceTest extends BaseServiceTest { m_serviceId = serviceId; } + private TestServiceService(String clusterId, String serviceId, String artifactId) { + super(clusterId); + m_clusterId = clusterId; + m_serviceId = serviceId; + m_artifact_id = artifactId; + } + @Override ResourceInstance createServiceResource(String clusterName, String serviceName) { assertEquals(m_clusterId, clusterName); @@ -102,6 +153,14 @@ public class ServiceServiceTest extends BaseServiceTest { } @Override + ResourceInstance createArtifactResource(String clusterName, String serviceName, String artifactName) { + assertEquals(m_clusterId, clusterName); + assertEquals(m_serviceId, serviceName); + assertEquals(m_artifact_id, artifactName); + return getTestResource(); + } + + @Override RequestFactory getRequestFactory() { return getTestRequestFactory(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ee4e786a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java index 046c5d8..789fb54 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ArtifactResourceProviderTest.java @@ -18,9 +18,11 @@ package org.apache.ambari.server.controller.internal; +import com.google.gson.Gson; import org.apache.ambari.server.controller.AmbariManagementController; import org.apache.ambari.server.controller.spi.Predicate; import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.RequestStatus; import org.apache.ambari.server.controller.spi.Resource; import org.apache.ambari.server.controller.utilities.PredicateBuilder; import org.apache.ambari.server.orm.dao.ArtifactDAO; @@ -51,6 +53,7 @@ import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; +import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -58,14 +61,15 @@ import static org.junit.Assert.fail; /** * ArtifactResourceProvider unit tests. */ +@SuppressWarnings("unchecked") public class ArtifactResourceProviderTest { private ArtifactDAO dao = createStrictMock(ArtifactDAO.class); private EntityManager em = createStrictMock(EntityManager.class); private AmbariManagementController controller = createStrictMock(AmbariManagementController.class); private Request request = createMock(Request.class); - private Clusters clusters = createStrictMock(Clusters.class); - private Cluster cluster = createStrictMock(Cluster.class); + private Clusters clusters = createMock(Clusters.class); + private Cluster cluster = createMock(Cluster.class); private ArtifactEntity entity = createMock(ArtifactEntity.class); private ArtifactEntity entity2 = createMock(ArtifactEntity.class); @@ -231,43 +235,6 @@ public class ArtifactResourceProviderTest { TreeMap<String, String> foreignKeys = new TreeMap<String, String>(); foreignKeys.put("cluster", "500"); - - String bodyJson = - "{ " + - " \"artifact_data\" : {" + - " \"foo\" : \"bar\"," + - " \"child\" : {" + - " \"childKey\" : \"childValue\"," + - " \"child2\" : {" + - " \"child2Key\" : \"child2Value\"," + - " \"child3\" : {" + - " \"child4\" : {" + - " \"child4Key\" : \"child4Value\"" + - " }" + - " }" + - " }" + - " }," + - " \"collection\" : [" + - " {" + - " \"child\" : {" + - " \"childKey\" : \"childValue\"," + - " \"child2\" : {" + - " \"child2Key\" : \"child2Value\"," + - " \"child3\" : {" + - " \"child4\" : {" + - " \"child4Key\" : \"child4Value\"" + - " }" + - " }" + - " }" + - " }" + - " }," + - " {" + - " \"child4Key\" : \"child4Value\"" + - " } " + - " ]" + - " }" + - "}"; - Map<String, String> requestInfoProps = new HashMap<String, String>(); requestInfoProps.put(Request.REQUEST_INFO_BODY_PROPERTY, bodyJson); @@ -329,6 +296,160 @@ public class ArtifactResourceProviderTest { assertEquals(foreignKeys, createEntity.getForeignKeys()); } + @Test + public void testUpdateResources() throws Exception { + Map<String, String> requestInfoProps = new HashMap<String, String>(); + requestInfoProps.put(Request.REQUEST_INFO_BODY_PROPERTY, bodyJson); + + Capture<ArtifactEntity> updateEntityCapture = new Capture<ArtifactEntity>(); + Capture<ArtifactEntity> updateEntityCapture2 = new Capture<ArtifactEntity>(); + Set<String> propertyIds = new HashSet<String>(); + TreeMap<String, String> foreignKeys = new TreeMap<String, String>(); + foreignKeys.put("cluster", "500"); + + List<ArtifactEntity> entities = new ArrayList<ArtifactEntity>(); + entities.add(entity); + entities.add(entity2); + + Map<String, Object> artifact_data = Collections.<String, Object>singletonMap("foo", "bar"); + Map<String, Object> artifact_data2 = Collections.<String, Object>singletonMap("foo2", "bar2"); + + Map<String, String> responseForeignKeys = new HashMap<String, String>(); + responseForeignKeys.put("cluster", "500"); + + // map with flattened properties + Map<String, Object> properties = new HashMap<String, Object>(); + properties.put("Artifacts/artifact_name", "test-artifact"); + properties.put("Artifacts/cluster_name", "test-cluster"); + properties.put("artifact_data/foo", "bar"); + properties.put("artifact_data/child/childKey", "childValue"); + properties.put("artifact_data/child/child2/child2Key", "child2Value"); + properties.put("artifact_data/child/child2/child3/child4/child4Key", "child4Value"); + + Set<Map<String, Object>> requestProperties = Collections.singleton(properties); + + Collection<Object> collectionProperties = new HashSet<Object>(); + properties.put("artifact_data/collection", collectionProperties); + + // expectations + expect(request.getProperties()).andReturn(requestProperties).anyTimes(); + expect(request.getRequestInfoProperties()).andReturn(requestInfoProps).anyTimes(); + expect(controller.getClusters()).andReturn(clusters).anyTimes(); + expect(clusters.getCluster("test-cluster")).andReturn(cluster).anyTimes(); + expect(clusters.getClusterById(500L)).andReturn(cluster).anyTimes(); + expect(cluster.getClusterId()).andReturn(500L).anyTimes(); + expect(cluster.getClusterName()).andReturn("test-cluster").anyTimes(); + + expect(request.getPropertyIds()).andReturn(propertyIds).anyTimes(); + + expect(dao.findByForeignKeys(eq(foreignKeys))).andReturn(entities).anyTimes(); + expect(entity.getArtifactName()).andReturn("test-artifact").anyTimes(); + expect(entity.getForeignKeys()).andReturn(responseForeignKeys).anyTimes(); + expect(entity.getArtifactData()).andReturn(artifact_data).anyTimes(); + expect(entity2.getArtifactName()).andReturn("test-artifact2").anyTimes(); + expect(entity2.getForeignKeys()).andReturn(responseForeignKeys).anyTimes(); + expect(entity2.getArtifactData()).andReturn(artifact_data2).anyTimes(); + + expect(dao.merge(capture(updateEntityCapture))).andReturn(entity).once(); + expect(dao.merge(capture(updateEntityCapture2))).andReturn(entity2).once(); + + // end of expectation setting + replay(dao, em, controller, request, clusters, cluster, entity, entity2); + + PredicateBuilder pb = new PredicateBuilder(); + Predicate predicate = pb.begin().property("Artifacts/cluster_name").equals("test-cluster").end().toPredicate(); + + RequestStatus response = resourceProvider.updateResources(request, predicate); + ArtifactEntity updateEntity = updateEntityCapture.getValue(); + ArtifactEntity updateEntity2 = updateEntityCapture2.getValue(); + + Gson serializer = new Gson(); + ArtifactEntity expected = new ArtifactEntity(); + expected.setArtifactData((Map<String, Object>) serializer.<Map<String, Object>>fromJson( + bodyJson, Map.class).get("artifact_data")); + + assertEquals(expected.getArtifactData(), updateEntity.getArtifactData()); + assertEquals(expected.getArtifactData(), updateEntity2.getArtifactData()); + + if (updateEntity.getArtifactName().equals("test-artifact")) { + assertEquals("test-artifact2",updateEntity2.getArtifactName() ); + } else if (updateEntity.getArtifactName().equals("test-artifact2")) { + assertEquals("test-artifact", updateEntity2.getArtifactName()); + } else { + fail ("Unexpected artifact name: " + updateEntity.getArtifactName()); + } + + assertEquals(foreignKeys, updateEntity.getForeignKeys()); + assertEquals(foreignKeys, updateEntity2.getForeignKeys()); + + assertEquals(RequestStatus.Status.Complete, response.getStatus()); + + verify(dao, em, controller, request, clusters, cluster, entity, entity2); + } + + @Test + public void testDeleteResources() throws Exception { + + Capture<ArtifactEntity> deleteEntityCapture = new Capture<ArtifactEntity>(); + Capture<ArtifactEntity> deleteEntityCapture2 = new Capture<ArtifactEntity>(); + TreeMap<String, String> foreignKeys = new TreeMap<String, String>(); + foreignKeys.put("cluster", "500"); + + List<ArtifactEntity> entities = new ArrayList<ArtifactEntity>(); + entities.add(entity); + entities.add(entity2); + + Map<String, Object> artifact_data = Collections.<String, Object>singletonMap("foo", "bar"); + Map<String, Object> artifact_data2 = Collections.<String, Object>singletonMap("foo2", "bar2"); + + Map<String, String> responseForeignKeys = new HashMap<String, String>(); + responseForeignKeys.put("cluster", "500"); + + // expectations + expect(controller.getClusters()).andReturn(clusters).anyTimes(); + expect(clusters.getCluster("test-cluster")).andReturn(cluster).anyTimes(); + expect(clusters.getClusterById(500L)).andReturn(cluster).anyTimes(); + expect(cluster.getClusterId()).andReturn(500L).anyTimes(); + expect(cluster.getClusterName()).andReturn("test-cluster").anyTimes(); + + + expect(dao.findByForeignKeys(eq(foreignKeys))).andReturn(entities).anyTimes(); + expect(entity.getArtifactName()).andReturn("test-artifact").anyTimes(); + expect(entity.getForeignKeys()).andReturn(responseForeignKeys).anyTimes(); + expect(entity.getArtifactData()).andReturn(artifact_data).anyTimes(); + expect(entity2.getArtifactName()).andReturn("test-artifact2").anyTimes(); + expect(entity2.getForeignKeys()).andReturn(responseForeignKeys).anyTimes(); + expect(entity2.getArtifactData()).andReturn(artifact_data2).anyTimes(); + + dao.remove(capture(deleteEntityCapture)); + dao.remove(capture(deleteEntityCapture2)); + + // end of expectation setting + replay(dao, em, controller, request, clusters, cluster, entity, entity2); + + PredicateBuilder pb = new PredicateBuilder(); + Predicate predicate = pb.begin().property("Artifacts/cluster_name").equals("test-cluster").end().toPredicate(); + + RequestStatus response = resourceProvider.deleteResources(predicate); + ArtifactEntity deleteEntity = deleteEntityCapture.getValue(); + ArtifactEntity deleteEntity2 = deleteEntityCapture2.getValue(); + + if (deleteEntity.getArtifactName().equals("test-artifact")) { + assertEquals("test-artifact2", deleteEntity2.getArtifactName()); + } else if (deleteEntity.getArtifactName().equals("test-artifact2")) { + assertEquals("test-artifact", deleteEntity2.getArtifactName()); + } else { + fail ("Unexpected artifact name: " + deleteEntity.getArtifactName()); + } + + assertEquals(foreignKeys, deleteEntity.getForeignKeys()); + assertEquals(foreignKeys, deleteEntity2.getForeignKeys()); + + assertEquals(RequestStatus.Status.Complete, response.getStatus()); + + verify(dao, em, controller, request, clusters, cluster, entity, entity2); + } + private void setPrivateField(Object o, String field, Object value) throws Exception{ Class<?> c = o.getClass(); @@ -336,4 +457,40 @@ public class ArtifactResourceProviderTest { f.setAccessible(true); f.set(o, value); } + + private String bodyJson = + "{ " + + " \"artifact_data\" : {" + + " \"foo\" : \"bar\"," + + " \"child\" : {" + + " \"childKey\" : \"childValue\"," + + " \"child2\" : {" + + " \"child2Key\" : \"child2Value\"," + + " \"child3\" : {" + + " \"child4\" : {" + + " \"child4Key\" : \"child4Value\"" + + " }" + + " }" + + " }" + + " }," + + " \"collection\" : [" + + " {" + + " \"child\" : {" + + " \"childKey\" : \"childValue\"," + + " \"child2\" : {" + + " \"child2Key\" : \"child2Value\"," + + " \"child3\" : {" + + " \"child4\" : {" + + " \"child4Key\" : \"child4Value\"" + + " }" + + " }" + + " }" + + " }" + + " }," + + " {" + + " \"child4Key\" : \"child4Value\"" + + " } " + + " ]" + + " }" + + "}"; }