blob: 62ee1897e377cf2ac35f25596d6822c92c92e12f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.brooklyn.rest.resources;
import static org.testng.Assert.assertEquals;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import javax.ws.rs.core.MediaType;
import org.apache.brooklyn.api.entity.Entity;
import org.apache.brooklyn.core.entity.Entities;
import org.apache.brooklyn.core.entity.EntityInternal;
import org.apache.brooklyn.core.test.entity.TestEntity;
import org.apache.brooklyn.entity.stock.BasicApplication;
import org.apache.brooklyn.entity.stock.BasicEntity;
import org.apache.brooklyn.rest.domain.ApplicationSpec;
import org.apache.brooklyn.rest.domain.EntitySpec;
import org.apache.brooklyn.rest.domain.TaskSummary;
import org.apache.brooklyn.rest.testing.BrooklynRestResourceTest;
import org.apache.brooklyn.rest.testing.mocks.RestMockSimpleEntity;
import org.apache.brooklyn.util.collections.MutableList;
import org.apache.brooklyn.util.exceptions.Exceptions;
import org.apache.brooklyn.util.http.HttpAsserts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import javax.ws.rs.core.Response;
@Test(singleThreaded = true,
// by using a different suite name we disallow interleaving other tests between the methods of this test class, which wrecks the test fixtures
suiteName = "EntityResourceTest")
public class EntityResourceTest extends BrooklynRestResourceTest {
private static final Logger log = LoggerFactory.getLogger(EntityResourceTest.class);
private final ApplicationSpec simpleSpec = ApplicationSpec.builder()
.name("simple-app")
.entities(ImmutableSet.of(new EntitySpec("simple-ent", RestMockSimpleEntity.class.getName())))
.locations(ImmutableSet.of("localhost"))
.build();
private EntityInternal entity;
private static final String entityEndpoint = "/applications/simple-app/entities/simple-ent";
@BeforeClass(alwaysRun = true)
public void setUp() throws Exception {
// Deploy application
startServer();
Response deploy = clientDeploy(simpleSpec);
waitForApplicationToBeRunning(deploy.getLocation());
// Add tag
entity = (EntityInternal) Iterables.find(getManagementContext().getEntityManager().getEntities(), new Predicate<Entity>() {
@Override
public boolean apply(@Nullable Entity input) {
return "RestMockSimpleEntity".equals(input.getEntityType().getSimpleName());
}
});
}
@Test
public void testGetSpecAcceptingXYaml() throws Exception {
testGetSpec("text/x-yaml");
}
@Test
public void testGetSpecWithNoExplicitAccepts() throws Exception {
testGetSpec(null);
}
protected void testGetSpec(String acceptMimeType) throws Exception {
String appName = "ent-with-spec";
// Create an app with a yaml spec
String yaml = Joiner.on("\n").join(
"name: " + appName,
"services:",
"- type: "+BasicEntity.class.getName());
Response appResponse = client().path("/applications")
.header("Content-Type", "text/x-yaml")
.post(yaml);
waitForApplicationToBeRunning(appResponse.getLocation());
// Retrieve the yaml spec, and confirm it is as expected (not wrapped in quotes, and treating \n sensibly)
Response response;
if (acceptMimeType != null) {
response = client().path("/applications/" + appName + "/entities/" + appName + "/spec")
.accept(acceptMimeType)
.get();
} else {
response = client().path("/applications/" + appName + "/entities/" + appName + "/spec")
.get();
}
String data = response.readEntity(String.class);
assertEquals(data.trim(), yaml.trim());
}
@Test
public void testTagsSanity() throws Exception {
entity.tags().addTag("foo");
Response response = client().path(entityEndpoint + "/tags")
.accept(MediaType.APPLICATION_JSON_TYPE)
.get();
String data = response.readEntity(String.class);
try {
List<Object> tags = new ObjectMapper().readValue(data, new TypeReference<List<Object>>() {});
Assert.assertTrue(tags.contains("foo"));
Assert.assertFalse(tags.contains("bar"));
} catch (Exception e) {
Exceptions.propagateIfFatal(e);
throw new IllegalStateException("Error with deserialization of tags list: "+e+"\n"+data, e);
}
}
@Test
public void testRename() throws Exception {
try {
Response response = client().path(entityEndpoint + "/name")
.query("name", "New Name")
.post(null);
HttpAsserts.assertHealthyStatusCode(response.getStatus());
Assert.assertTrue(entity.getDisplayName().equals("New Name"));
} finally {
// restore it for other tests!
entity.setDisplayName("simple-ent");
}
}
@Test
public void testAddChild() throws Exception {
try {
// to test in GUI:
// services: [ { type: org.apache.brooklyn.entity.stock.BasicEntity }]
Response response = client().path(entityEndpoint + "/children").query("timeout", "10s")
.post(javax.ws.rs.client.Entity.entity("services: [ { type: "+TestEntity.class.getName()+" }]", "application/yaml"));
HttpAsserts.assertHealthyStatusCode(response.getStatus());
Assert.assertEquals(entity.getChildren().size(), 1);
Entity child = Iterables.getOnlyElement(entity.getChildren());
Assert.assertTrue(Entities.isManaged(child));
TaskSummary task = response.readEntity(TaskSummary.class);
Assert.assertEquals(task.getResult(), MutableList.of(child.getId()));
} finally {
// restore it for other tests
Collection<Entity> children = entity.getChildren();
if (!children.isEmpty()) Entities.unmanage(Iterables.getOnlyElement(children));
}
}
@Test
public void testTagsDoNotSerializeTooMuch() throws Exception {
entity.tags().addTag("foo");
entity.tags().addTag(entity.getParent());
Response response = client().path(entityEndpoint + "/tags")
.accept(MediaType.APPLICATION_JSON)
.get();
String raw = response.readEntity(String.class);
log.info("TAGS raw: "+raw);
HttpAsserts.assertHealthyStatusCode(response.getStatus());
Assert.assertTrue(raw.contains(entity.getParent().getId()), "unexpected app tag, does not include ID: "+raw);
Assert.assertTrue(raw.length() < 1000, "unexpected app tag, includes too much mgmt info (len "+raw.length()+"): "+raw);
Assert.assertFalse(raw.contains(entity.getManagementContext().getManagementNodeId()), "unexpected app tag, includes too much mgmt info: "+raw);
Assert.assertFalse(raw.contains("managementContext"), "unexpected app tag, includes too much mgmt info: "+raw);
Assert.assertFalse(raw.contains("localhost"), "unexpected app tag, includes too much mgmt info: "+raw);
Assert.assertFalse(raw.contains("catalog"), "unexpected app tag, includes too much mgmt info: "+raw);
@SuppressWarnings("unchecked")
List<Object> tags = mapper().readValue(raw, List.class);
log.info("TAGS are: "+tags);
Assert.assertEquals(tags.size(), 2, "tags are: "+tags);
Assert.assertTrue(tags.contains("foo"));
Assert.assertFalse(tags.contains("bar"));
MutableList<Object> appTags = MutableList.copyOf(tags);
appTags.remove("foo");
Object appTag = Iterables.getOnlyElement( appTags );
// it's a map at this point, because there was no way to make it something stronger than Object
Assert.assertTrue(appTag instanceof Map, "Should have deserialized an entity: "+appTag);
// let's re-serialize it as an entity
appTag = mapper().readValue(mapper().writeValueAsString(appTag), Entity.class);
Assert.assertTrue(appTag instanceof Entity, "Should have deserialized an entity: "+appTag);
Assert.assertEquals( ((Entity)appTag).getId(), entity.getApplicationId(), "Wrong ID: "+appTag);
Assert.assertTrue(appTag instanceof BasicApplication, "Should have deserialized BasicApplication: "+appTag);
}
}