/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed 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 co.cask.cdap.internal.app.services.http.handlers;
import co.cask.cdap.common.conf.Constants;
import co.cask.cdap.internal.app.services.http.AppFabricTestBase;
import co.cask.cdap.proto.Id;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import org.apache.http.HttpResponse;
import org.junit.Assert;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;
/**
* Tests for {@link co.cask.cdap.gateway.handlers.NotificationFeedHttpHandler}.
*/
public class NotificationFeedHttpHandlerTest extends AppFabricTestBase {
private static final Gson GSON = new Gson();
private static final String NAMESPACE_FIELD = "namespace";
private static final String CATEGORY_FIELD = "category";
private static final String NAME_FIELD = "name";
private static final String DESCRIPTION_FIELD = "description";
// TODO when [CDAP-903] is done, those tests will fail because the following namespace will not have been created
// Modify the tests at that time to create the namespace, and test the behavior when using non-existant namespaces
private static final String NAMESPACE = "namespaceTest";
private static final String CATEGORY = "categoryTest";
private static final String NAME = "test";
private static final String DESCRIPTION = "test description";
private static final Id.NotificationFeed FEED_VALID = new Id.NotificationFeed.Builder()
.setNamespaceId(NAMESPACE)
.setCategory(CATEGORY)
.setName(NAME)
.setDescription(DESCRIPTION)
.build();
private static final Id.NotificationFeed FEED_MISSING_DESCRIPTION = new Id.NotificationFeed.Builder()
.setNamespaceId(NAMESPACE)
.setCategory(CATEGORY)
.setName(NAME)
.build();
private static final Id.NotificationFeed FEED_EMPTY_DESCRIPTION = new Id.NotificationFeed.Builder()
.setNamespaceId(NAMESPACE)
.setCategory(CATEGORY)
.setName(NAME)
.setDescription("")
.build();
private static final String METADATA_INVALID_JSON = "invalid";
private HttpResponse createFeed(Id.NotificationFeed feed) throws Exception {
return createFeed(feed.getNamespaceId(), feed.getCategory(), feed.getName(), GSON.toJson(feed));
}
private HttpResponse createFeed(String namespace, String category, String name, String metadata) throws Exception {
return doPut(String.format("%s/namespaces/%s/feeds/categories/%s/names/%s", Constants.Gateway.API_VERSION_3,
namespace, category, name), metadata);
}
private HttpResponse listFeeds(String namespaceId) throws Exception {
return doGet(String.format("%s/namespaces/%s/feeds", Constants.Gateway.API_VERSION_3, namespaceId));
}
private HttpResponse getFeed(String namespaceId, String category, String name) throws Exception {
return doGet(String.format("%s/namespaces/%s/feeds/categories/%s/names/%s", Constants.Gateway.API_VERSION_3,
namespaceId, category, name));
}
private HttpResponse deleteFeed(String namespaceId, String category, String name) throws Exception {
return doDelete(String.format("%s/namespaces/%s/feeds/categories/%s/names/%s", Constants.Gateway.API_VERSION_3,
namespaceId, category, name));
}
private void assertResponseCode(int expected, HttpResponse response) {
Assert.assertEquals(expected, response.getStatusLine().getStatusCode());
}
private List<JsonObject> readListResponse(HttpResponse response) throws IOException {
Type typeToken = new TypeToken<List<JsonObject>>() { }.getType();
return readResponse(response, typeToken);
}
private JsonObject readGetResponse(HttpResponse response) throws IOException {
Type typeToken = new TypeToken<JsonObject>() { }.getType();
return readResponse(response, typeToken);
}
@Test
public void testFeedsValidFlows() throws Exception {
// no feeds initially
HttpResponse response = listFeeds(NAMESPACE);
assertResponseCode(200, response);
List<JsonObject> feeds = readListResponse(response);
Assert.assertEquals(0, feeds.size());
try {
// create and verify
response = createFeed(FEED_VALID);
assertResponseCode(200, response);
response = listFeeds(NAMESPACE);
feeds = readListResponse(response);
Assert.assertEquals(1, feeds.size());
Assert.assertEquals(NAME, feeds.get(0).get(NAME_FIELD).getAsString());
JsonElement namespace = feeds.get(0).get(NAMESPACE_FIELD);
Assert.assertTrue(namespace instanceof JsonObject);
Assert.assertEquals(NAMESPACE, ((JsonObject) namespace).get("id").getAsString());
Assert.assertEquals(CATEGORY, feeds.get(0).get(CATEGORY_FIELD).getAsString());
Assert.assertEquals(DESCRIPTION, feeds.get(0).get(DESCRIPTION_FIELD).getAsString());
} finally {
// cleanup
response = deleteFeed(NAMESPACE, CATEGORY, NAME);
assertResponseCode(200, response);
response = listFeeds(NAMESPACE);
feeds = readListResponse(response);
Assert.assertEquals(0, feeds.size());
}
}
@Test
public void testCreateDuplicate() throws Exception {
try {
// prepare - create feed
HttpResponse response = createFeed(FEED_VALID);
assertResponseCode(200, response);
response = getFeed(NAMESPACE, CATEGORY, NAME);
JsonObject feed = readGetResponse(response);
Assert.assertNotNull(feed);
Assert.assertEquals(NAME, feed.get(NAME_FIELD).getAsString());
JsonElement namespace = feed.get(NAMESPACE_FIELD);
Assert.assertTrue(namespace instanceof JsonObject);
Assert.assertEquals(NAMESPACE, ((JsonObject) namespace).get("id").getAsString());
Assert.assertEquals(CATEGORY, feed.get(CATEGORY_FIELD).getAsString());
Assert.assertEquals(DESCRIPTION, feed.get(DESCRIPTION_FIELD).getAsString());
// create again with the same name
response = createFeed(FEED_EMPTY_DESCRIPTION);
assertResponseCode(200, response);
// check that no updates happened
response = getFeed(NAMESPACE, CATEGORY, NAME);
feed = readGetResponse(response);
Assert.assertNotNull(feed);
Assert.assertEquals(NAME, feed.get(NAME_FIELD).getAsString());
namespace = feed.get(NAMESPACE_FIELD);
Assert.assertTrue(namespace instanceof JsonObject);
Assert.assertEquals(NAMESPACE, ((JsonObject) namespace).get("id").getAsString());
Assert.assertEquals(CATEGORY, feed.get(CATEGORY_FIELD).getAsString());
Assert.assertEquals(DESCRIPTION, feed.get(DESCRIPTION_FIELD).getAsString());
} finally {
// cleanup
HttpResponse response = deleteFeed(NAMESPACE, CATEGORY, NAME);
assertResponseCode(200, response);
}
}
@Test
public void testCreateInvalidJson() throws Exception {
// invalid json should return 400
HttpResponse response = createFeed(NAMESPACE, CATEGORY, NAME, METADATA_INVALID_JSON);
assertResponseCode(400, response);
// verify
response = getFeed(NAMESPACE, CATEGORY, NAME);
assertResponseCode(404, response);
}
@Test
public void testCreateMissingEmptyOrInvalidName() throws Exception {
// name must be non-null, non-empty
JsonObject object = new JsonObject();
object.add(DESCRIPTION_FIELD, GSON.toJsonTree(DESCRIPTION));
String metadata = GSON.toJson(object);
HttpResponse response = createFeed(NAMESPACE, CATEGORY, "", metadata);
assertResponseCode(404, response);
response = createFeed(NAMESPACE, CATEGORY, "$.a", metadata);
assertResponseCode(400, response);
}
@Test
public void testCreateMissingEmptyOrInvalidNamespace() throws Exception {
// namespace must be non-null, non-empty
JsonObject object = new JsonObject();
object.add(DESCRIPTION_FIELD, GSON.toJsonTree(DESCRIPTION));
String metadata = GSON.toJson(object);
HttpResponse response = createFeed("", CATEGORY, NAME, metadata);
assertResponseCode(404, response);
response = createFeed("$.a", CATEGORY, NAME, metadata);
assertResponseCode(400, response);
}
@Test
public void testCreateMissingEmptyOrInvalidCategory() throws Exception {
// category must be non-null, non-empty
JsonObject object = new JsonObject();
object.add(DESCRIPTION_FIELD, GSON.toJsonTree(DESCRIPTION));
String metadata = GSON.toJson(object);
HttpResponse response = createFeed(NAMESPACE, "", NAME, metadata);
assertResponseCode(404, response);
response = createFeed(NAMESPACE, "$.a", NAME, metadata);
assertResponseCode(400, response);
}
@Test
public void testCreateMissingOrEmptyDescription() throws Exception {
// create with missing description
HttpResponse response = createFeed(FEED_MISSING_DESCRIPTION);
assertResponseCode(200, response);
try {
// verify
response = getFeed(NAMESPACE, CATEGORY, NAME);
JsonObject feed = readGetResponse(response);
Assert.assertNotNull(feed);
Assert.assertEquals(NAME, feed.get(NAME_FIELD).getAsString());
JsonElement namespace = feed.get(NAMESPACE_FIELD);
Assert.assertTrue(namespace instanceof JsonObject);
Assert.assertEquals(NAMESPACE, ((JsonObject) namespace).get("id").getAsString());
Assert.assertEquals(CATEGORY, feed.get(CATEGORY_FIELD).getAsString());
Assert.assertNull(feed.get(DESCRIPTION_FIELD));
// cleanup
response = deleteFeed(NAMESPACE, CATEGORY, NAME);
assertResponseCode(200, response);
// create with empty description
response = createFeed(FEED_EMPTY_DESCRIPTION);
assertResponseCode(200, response);
// verify
response = getFeed(NAMESPACE, CATEGORY, NAME);
feed = readGetResponse(response);
Assert.assertNotNull(feed);
Assert.assertEquals(NAME, feed.get(NAME_FIELD).getAsString());
namespace = feed.get(NAMESPACE_FIELD);
Assert.assertTrue(namespace instanceof JsonObject);
Assert.assertEquals(NAMESPACE, ((JsonObject) namespace).get("id").getAsString());
Assert.assertEquals(CATEGORY, feed.get(CATEGORY_FIELD).getAsString());
Assert.assertEquals("", feed.get(DESCRIPTION_FIELD).getAsString());
} finally {
// cleanup
response = deleteFeed(NAMESPACE, CATEGORY, NAME);
assertResponseCode(200, response);
}
response = createFeed(NAMESPACE, CATEGORY, NAME, "");
assertResponseCode(200, response);
}
@Test
public void testDeleteMissingFeed() throws Exception {
// test deleting non-existent feed
HttpResponse response = deleteFeed("does", "not", "exist");
assertResponseCode(404, response);
}
}