/* * Copyright © 2015 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.gateway.handlers; import co.cask.cdap.api.data.format.FormatSpecification; import co.cask.cdap.api.data.format.Formats; import co.cask.cdap.api.data.schema.Schema; import co.cask.cdap.gateway.GatewayTestBase; import co.cask.cdap.internal.io.SchemaTypeAdapter; import co.cask.cdap.proto.ViewDetail; import co.cask.cdap.proto.ViewSpecification; import co.cask.common.http.HttpRequest; import co.cask.common.http.HttpRequests; import co.cask.common.http.HttpResponse; import co.cask.common.http.ObjectResponse; import com.google.common.collect.ImmutableList; import com.google.common.collect.Ordering; import com.google.common.reflect.TypeToken; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import org.junit.Assert; import org.junit.Test; import java.io.IOException; import java.lang.reflect.Type; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; import java.util.List; /** * */ public class StreamViewHttpHandlerTest extends GatewayTestBase { private static final Gson GSON = new GsonBuilder() .registerTypeAdapter(Schema.class, new SchemaTypeAdapter()) .create(); @Test public void testAll() throws Exception { execute(404, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views")).build()); execute(404, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views/view1")).build()); execute(404, HttpRequest.delete(resolve("/v3/namespaces/default/streams/foo/views/view1")).build()); execute(200, HttpRequest.put(resolve("/v3/namespaces/default/streams/foo")).build()); execute(404, HttpRequest.delete(resolve("/v3/namespaces/default/streams/foo/views/nonexistent")).build()); List<String> views = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views")).build(), new TypeToken<List<String>>() { }.getType()); Assert.assertEquals(ImmutableList.of(), views); Schema schema = Schema.recordOf("foo", Schema.Field.of("name", Schema.of(Schema.Type.STRING))); FormatSpecification formatSpec = new FormatSpecification( Formats.AVRO, schema, Collections.<String, String>emptyMap()); ViewSpecification config = new ViewSpecification(formatSpec); // trying to create without request body should give 400 execute(400, HttpRequest.put(resolve("/v3/namespaces/default/streams/foo/views/view1")).build()); execute( 201, HttpRequest.put(resolve("/v3/namespaces/default/streams/foo/views/view1")) .withBody(GSON.toJson(config)) .build()); ViewDetail actualDetail = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views/view1")).build(), ViewDetail.class); Assert.assertEquals( new ViewDetail("view1", new ViewSpecification(config.getFormat(), "stream_foo_view1")), actualDetail); views = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views")).build(), new TypeToken<List<String>>() { }.getType()); Assert.assertEquals(ImmutableList.of("view1"), views); execute( 201, HttpRequest.put(resolve("/v3/namespaces/default/streams/foo/views/view2")) .withBody(GSON.toJson(config)) .build()); actualDetail = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views/view2")).build(), ViewDetail.class); Assert.assertEquals( new ViewDetail("view2", new ViewSpecification(config.getFormat(), "stream_foo_view2")), actualDetail); views = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views")).build(), new TypeToken<List<String>>() { }.getType()); Assert.assertEquals(ImmutableList.of("view1", "view2"), views == null ? null : Ordering.natural().sortedCopy(views)); execute(200, HttpRequest.delete(resolve("/v3/namespaces/default/streams/foo/views/view1")).build()); views = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views")).build(), new TypeToken<List<String>>() { }.getType()); Assert.assertEquals(ImmutableList.of("view2"), views); execute(200, HttpRequest.delete(resolve("/v3/namespaces/default/streams/foo/views/view2")).build()); views = execute( 200, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views")).build(), new TypeToken<List<String>>() { }.getType()); Assert.assertEquals(ImmutableList.<String>of(), views); // Deleting a stream should also delete the associated views execute(200, HttpRequest.delete(resolve("/v3/namespaces/default/streams/foo")).build()); execute(200, HttpRequest.put(resolve("/v3/namespaces/default/streams/foo")).build()); execute(404, HttpRequest.get(resolve("/v3/namespaces/default/streams/foo/views/view1")).build()); } private URL resolve(String format, Object... args) throws MalformedURLException, URISyntaxException { return getEndPoint(String.format(format, args)).toURL(); } private <T> T execute(int expectedCode, HttpRequest request, Type type) throws IOException { HttpResponse response = HttpRequests.execute(request); Assert.assertEquals( String.format("Got '%s' for path '%s'", response.getResponseMessage(), request.getURL().toString()), expectedCode, response.getResponseCode()); if (type != null) { try { return ObjectResponse.<T>fromJsonBody(response, type, GSON).getResponseObject(); } catch (JsonSyntaxException e) { throw new RuntimeException("Couldn't decode body as JSON: " + response.getResponseBodyAsString(), e); } } return null; } private void execute(int expectedCode, HttpRequest request) throws IOException { execute(expectedCode, request, null); } }