| /* |
| * Copyright 2016-present Open Networking Foundation |
| * |
| * 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 org.onosproject.protocol.rest.ctl; |
| |
| import org.apache.commons.io.IOUtils; |
| import org.glassfish.jersey.server.ResourceConfig; |
| import org.glassfish.jersey.test.JerseyTest; |
| import org.glassfish.jersey.test.TestProperties; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.onlab.junit.TestUtils; |
| import org.onlab.packet.IpAddress; |
| import org.onosproject.protocol.rest.DefaultRestSBDevice; |
| import org.onosproject.protocol.rest.RestSBDevice; |
| import org.onosproject.common.event.impl.TestEventDispatcher; |
| import org.onosproject.protocol.rest.RestSBEventListener; |
| |
| import javax.ws.rs.Consumes; |
| import javax.ws.rs.DELETE; |
| import javax.ws.rs.GET; |
| import javax.ws.rs.PATCH; |
| import javax.ws.rs.POST; |
| import javax.ws.rs.PUT; |
| import javax.ws.rs.Path; |
| import javax.ws.rs.Produces; |
| import javax.ws.rs.core.Application; |
| import javax.ws.rs.core.Context; |
| import javax.ws.rs.core.MediaType; |
| import javax.ws.rs.core.Response; |
| import javax.ws.rs.sse.InboundSseEvent; |
| import javax.ws.rs.sse.OutboundSseEvent; |
| import javax.ws.rs.sse.Sse; |
| import javax.ws.rs.sse.SseEventSink; |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.net.HttpURLConnection; |
| import java.nio.charset.StandardCharsets; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import java.util.function.Consumer; |
| |
| import static org.junit.Assert.*; |
| |
| /** |
| * Basic testing for RestSBController. |
| */ |
| public class RestSBControllerImplTest extends JerseyTest { |
| private static final String SAMPLE_PAYLOAD = "{ \"msg\": \"ONOS Rocks!\" }"; |
| |
| RestSBControllerImpl controller; |
| |
| RestSBDevice device1; |
| RestSBDevice device2; |
| |
| /** |
| * Mockup of an arbitrary device. |
| */ |
| @Path("testme") |
| public static class HelloResource { |
| @POST |
| @Consumes(MediaType.APPLICATION_JSON) |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response post(InputStream payload) throws IOException { |
| String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8); |
| if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) { |
| return Response.ok().build(); |
| } |
| return Response.status(Response.Status.EXPECTATION_FAILED).build(); |
| } |
| |
| @POST |
| @Path("testpostreturnstring") |
| @Consumes(MediaType.APPLICATION_JSON) |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response postReturnString(InputStream payload) throws IOException { |
| String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8); |
| if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) { |
| return Response.ok().entity("OK").build(); |
| } |
| return Response.status(Response.Status.EXPECTATION_FAILED).entity("Failed").build(); |
| } |
| |
| @PUT |
| @Consumes(MediaType.APPLICATION_JSON) |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response put(InputStream payload) throws IOException { |
| String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8); |
| if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) { |
| return Response.ok().build(); |
| } |
| return Response.status(Response.Status.EXPECTATION_FAILED).build(); |
| } |
| |
| @PATCH |
| @Consumes(MediaType.APPLICATION_JSON) |
| @Produces(MediaType.APPLICATION_JSON) |
| public Response patch(InputStream payload) throws IOException { |
| String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8); |
| if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) { |
| return Response.ok().build(); |
| } |
| return Response.status(Response.Status.EXPECTATION_FAILED).build(); |
| } |
| |
| @GET |
| public String getHello() { |
| return SAMPLE_PAYLOAD; |
| } |
| |
| @DELETE |
| public int delete() { |
| return Response.Status.NO_CONTENT.getStatusCode(); |
| } |
| |
| @GET |
| @Path("server-sent-events") |
| @Produces(MediaType.SERVER_SENT_EVENTS) |
| public void getServerSentEvents(@Context SseEventSink eventSink, @Context Sse sse) throws InterruptedException { |
| new Thread(() -> { |
| try { |
| for (int i = 0; i < 10; i++) { |
| // ... code that waits 0.1 second |
| Thread.sleep(100L); |
| final OutboundSseEvent event = sse.newEventBuilder() |
| .id(String.valueOf(i)) |
| .name("message-to-rest-sb") |
| .data(String.class, "Test message " + i + "!") |
| .build(); |
| eventSink.send(event); |
| System.out.println("Message " + i + " sent"); |
| } |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| } |
| }).start(); |
| } |
| |
| } |
| |
| @Override |
| protected Application configure() { |
| set(TestProperties.CONTAINER_PORT, 8080); |
| return new ResourceConfig(HelloResource.class); |
| } |
| |
| @Before |
| public void setUpTest() { |
| controller = new RestSBControllerImpl(); |
| TestUtils.setField(controller, "eventDispatcher", new TestEventDispatcher()); |
| controller.activate(); |
| device1 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.1"), 8080, "foo", "bar", "http", null, true); |
| device2 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.2"), 8080, "foo1", "bar2", "http", null, true); |
| controller.addDevice(device1); |
| |
| } |
| |
| @Test |
| public void basics() { |
| assertTrue("Device1 non added", controller.getDevices().containsValue(device1)); |
| assertEquals("Device1 added but with wrong key", controller.getDevices() |
| .get(device1.deviceId()), device1); |
| assertEquals("Incorrect Get Device by ID", controller.getDevice(device1.deviceId()), device1); |
| assertEquals("Incorrect Get Device by IP, Port", controller.getDevice(device1.ip(), device1.port()), device1); |
| controller.addDevice(device2); |
| assertTrue("Device2 non added", controller.getDevices().containsValue(device2)); |
| controller.removeDevice(device2.deviceId()); |
| assertFalse("Device2 not removed", controller.getDevices().containsValue(device2)); |
| } |
| |
| /** |
| * Tests the post function of the REST SB Controller. |
| */ |
| @Test |
| public void testPost() { |
| InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8)); |
| int response = controller.post(device1.deviceId(), "/testme", payload, MediaType.APPLICATION_JSON_TYPE); |
| assertEquals(HttpURLConnection.HTTP_OK, response); |
| } |
| |
| /** |
| * Tests the put function of the REST SB Controller. |
| */ |
| @Test |
| public void testPut() { |
| InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8)); |
| int response = controller.put(device1.deviceId(), "/testme", payload, MediaType.APPLICATION_JSON_TYPE); |
| assertEquals(HttpURLConnection.HTTP_OK, response); |
| } |
| |
| @Test |
| public void testPatch() { |
| InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8)); |
| int response = controller.patch(device1.deviceId(), "/testme", payload, MediaType.APPLICATION_JSON_TYPE); |
| assertEquals(HttpURLConnection.HTTP_OK, response); |
| } |
| |
| /** |
| * Tests the delete function of the REST SB Controller. |
| */ |
| @Test |
| public void testDelete() { |
| int response = controller.delete(device1.deviceId(), "/testme", null, null); |
| assertEquals(HttpURLConnection.HTTP_OK, response); |
| } |
| |
| /** |
| * Tests the get function of the REST SB Controller. |
| */ |
| @Test |
| public void testGet() throws IOException { |
| InputStream payload = controller.get(device1.deviceId(), "/testme", MediaType.APPLICATION_JSON_TYPE); |
| String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8); |
| assertEquals(SAMPLE_PAYLOAD, responseText); |
| } |
| |
| /** |
| * Tests the post function of the REST SB Controller. |
| */ |
| @Test |
| public void testPostReturnString() { |
| InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8)); |
| String result = controller.post(device1.deviceId(), "/testme/testpostreturnstring", |
| payload, MediaType.APPLICATION_JSON_TYPE, String.class); |
| assertEquals("OK", result); |
| } |
| |
| /** |
| * Tests the low level getServerSentEvents function of the REST SB Controller. |
| * |
| * Note: If the consumer throws an error it will not be propagated back up |
| * to here - instead the source will go in to error and no more callbacks |
| * will be executed |
| */ |
| @Test |
| public void testGetServerSentEvents() { |
| Consumer<InboundSseEvent> sseEventConsumer = (event) -> { |
| System.out.println("ServerSentEvent received: " + event); |
| assertEquals("message-to-rest-sb", event.getName()); |
| // Just to show it works we stop before the last message is sent |
| if (Integer.parseInt(event.getId()) == 8) { |
| controller.cancelServerSentEvents(device1.deviceId()); |
| } |
| }; |
| |
| Consumer<Throwable> sseError = (error) -> { |
| System.err.println(error); |
| controller.cancelServerSentEvents(device1.deviceId()); |
| //fail(error.toString()); //Does nothing as it's in lambda scope |
| }; |
| |
| int response = controller.getServerSentEvents(device1.deviceId(), |
| "/testme/server-sent-events", |
| sseEventConsumer, |
| sseError |
| ); |
| assertEquals(204, response); |
| } |
| |
| /** |
| * Test of cancelling of events from a device - in this case there should not be any. |
| */ |
| @Test |
| public void testCancelServerSentEvents() { |
| assertEquals(404, controller.cancelServerSentEvents(device1.deviceId())); |
| } |
| |
| /** |
| * Test the high level API for Server Sent Events. |
| */ |
| @Test |
| public void testStartServerSentEvents() { |
| AtomicInteger listener1Count = new AtomicInteger(); |
| AtomicInteger listener2Count = new AtomicInteger(); |
| |
| RestSBEventListener listener1 = event -> { |
| System.out.println("Event on Lsnr1: " + event); |
| listener1Count.incrementAndGet(); |
| if (Integer.parseInt(event.getId()) == 8) { |
| controller.cancelServerSentEvents(device1.deviceId()); |
| } |
| }; |
| |
| RestSBEventListener listener2 = event -> { |
| listener2Count.incrementAndGet(); |
| System.out.println("Event on Lsnr2: " + event); |
| }; |
| |
| controller.addListener(listener1); |
| controller.addListener(listener2); |
| |
| controller.startServerSentEvents(device1.deviceId(), "/testme/server-sent-events"); |
| |
| controller.removeListener(listener1); |
| controller.removeListener(listener2); |
| |
| assertEquals(9, listener1Count.get()); |
| assertEquals(9, listener2Count.get()); |
| } |
| } |