blob: fa9f9523549c998f00b2749fb5e037b51062aac8 [file] [log] [blame]
Andrea Campanellace279ee2016-01-25 10:21:45 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Andrea Campanellace279ee2016-01-25 10:21:45 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.protocol.rest.ctl;
18
Sean Condon5548ce62018-07-30 16:00:10 +010019import org.apache.commons.io.IOUtils;
20import org.glassfish.jersey.server.ResourceConfig;
21import org.glassfish.jersey.test.JerseyTest;
22import org.glassfish.jersey.test.TestProperties;
Andrea Campanellace279ee2016-01-25 10:21:45 -080023import org.junit.Before;
24import org.junit.Test;
Sean Condon5548ce62018-07-30 16:00:10 +010025import org.onlab.junit.TestUtils;
Andrea Campanellace279ee2016-01-25 10:21:45 -080026import org.onlab.packet.IpAddress;
27import org.onosproject.protocol.rest.DefaultRestSBDevice;
28import org.onosproject.protocol.rest.RestSBDevice;
Sean Condon5548ce62018-07-30 16:00:10 +010029import org.onosproject.common.event.impl.TestEventDispatcher;
30import org.onosproject.protocol.rest.RestSBEventListener;
31
32import javax.ws.rs.Consumes;
33import javax.ws.rs.DELETE;
34import javax.ws.rs.GET;
35import javax.ws.rs.PATCH;
36import javax.ws.rs.POST;
37import javax.ws.rs.PUT;
38import javax.ws.rs.Path;
39import javax.ws.rs.Produces;
40import javax.ws.rs.core.Application;
41import javax.ws.rs.core.Context;
42import javax.ws.rs.core.MediaType;
43import javax.ws.rs.core.Response;
44import javax.ws.rs.sse.InboundSseEvent;
45import javax.ws.rs.sse.OutboundSseEvent;
46import javax.ws.rs.sse.Sse;
47import javax.ws.rs.sse.SseEventSink;
48import java.io.ByteArrayInputStream;
49import java.io.IOException;
50import java.io.InputStream;
51import java.net.HttpURLConnection;
52import java.nio.charset.StandardCharsets;
53import java.util.concurrent.atomic.AtomicInteger;
54import java.util.function.Consumer;
Andrea Campanellace279ee2016-01-25 10:21:45 -080055
56import static org.junit.Assert.*;
57
58/**
59 * Basic testing for RestSBController.
60 */
Sean Condon5548ce62018-07-30 16:00:10 +010061public class RestSBControllerImplTest extends JerseyTest {
62 private static final String SAMPLE_PAYLOAD = "{ \"msg\": \"ONOS Rocks!\" }";
Andrea Campanellace279ee2016-01-25 10:21:45 -080063
64 RestSBControllerImpl controller;
65
66 RestSBDevice device1;
67 RestSBDevice device2;
68
Sean Condon5548ce62018-07-30 16:00:10 +010069 /**
70 * Mockup of an arbitrary device.
71 */
72 @Path("testme")
73 public static class HelloResource {
74 @POST
75 @Consumes(MediaType.APPLICATION_JSON)
76 @Produces(MediaType.APPLICATION_JSON)
77 public Response post(InputStream payload) throws IOException {
78 String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8);
79 if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) {
80 return Response.ok().build();
81 }
82 return Response.status(Response.Status.EXPECTATION_FAILED).build();
83 }
84
85 @POST
86 @Path("testpostreturnstring")
87 @Consumes(MediaType.APPLICATION_JSON)
88 @Produces(MediaType.APPLICATION_JSON)
89 public Response postReturnString(InputStream payload) throws IOException {
90 String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8);
91 if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) {
92 return Response.ok().entity("OK").build();
93 }
94 return Response.status(Response.Status.EXPECTATION_FAILED).entity("Failed").build();
95 }
96
97 @PUT
98 @Consumes(MediaType.APPLICATION_JSON)
99 @Produces(MediaType.APPLICATION_JSON)
100 public Response put(InputStream payload) throws IOException {
101 String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8);
102 if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) {
103 return Response.ok().build();
104 }
105 return Response.status(Response.Status.EXPECTATION_FAILED).build();
106 }
107
108 @PATCH
109 @Consumes(MediaType.APPLICATION_JSON)
110 @Produces(MediaType.APPLICATION_JSON)
111 public Response patch(InputStream payload) throws IOException {
112 String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8);
113 if (responseText.equalsIgnoreCase(SAMPLE_PAYLOAD)) {
114 return Response.ok().build();
115 }
116 return Response.status(Response.Status.EXPECTATION_FAILED).build();
117 }
118
119 @GET
120 public String getHello() {
121 return SAMPLE_PAYLOAD;
122 }
123
124 @DELETE
125 public int delete() {
126 return Response.Status.NO_CONTENT.getStatusCode();
127 }
128
129 @GET
130 @Path("server-sent-events")
131 @Produces(MediaType.SERVER_SENT_EVENTS)
132 public void getServerSentEvents(@Context SseEventSink eventSink, @Context Sse sse) throws InterruptedException {
133 new Thread(() -> {
134 try {
135 for (int i = 0; i < 10; i++) {
136 // ... code that waits 0.1 second
137 Thread.sleep(100L);
138 final OutboundSseEvent event = sse.newEventBuilder()
139 .id(String.valueOf(i))
140 .name("message-to-rest-sb")
141 .data(String.class, "Test message " + i + "!")
142 .build();
143 eventSink.send(event);
144 System.out.println("Message " + i + " sent");
145 }
146 } catch (InterruptedException e) {
147 e.printStackTrace();
148 }
149 }).start();
150 }
151
152 }
153
154 @Override
155 protected Application configure() {
156 set(TestProperties.CONTAINER_PORT, 8080);
157 return new ResourceConfig(HelloResource.class);
158 }
Andrea Campanellace279ee2016-01-25 10:21:45 -0800159
160 @Before
Sean Condon5548ce62018-07-30 16:00:10 +0100161 public void setUpTest() {
Andrea Campanellace279ee2016-01-25 10:21:45 -0800162 controller = new RestSBControllerImpl();
Sean Condon5548ce62018-07-30 16:00:10 +0100163 TestUtils.setField(controller, "eventDispatcher", new TestEventDispatcher());
Andrea Campanellace279ee2016-01-25 10:21:45 -0800164 controller.activate();
Andrea Campanella2947e622016-01-27 09:23:46 -0800165 device1 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.1"), 8080, "foo", "bar", "http", null, true);
166 device2 = new DefaultRestSBDevice(IpAddress.valueOf("127.0.0.2"), 8080, "foo1", "bar2", "http", null, true);
Andrea Campanellace279ee2016-01-25 10:21:45 -0800167 controller.addDevice(device1);
Sean Condon5548ce62018-07-30 16:00:10 +0100168
Andrea Campanellace279ee2016-01-25 10:21:45 -0800169 }
170
171 @Test
172 public void basics() {
173 assertTrue("Device1 non added", controller.getDevices().containsValue(device1));
174 assertEquals("Device1 added but with wrong key", controller.getDevices()
175 .get(device1.deviceId()), device1);
176 assertEquals("Incorrect Get Device by ID", controller.getDevice(device1.deviceId()), device1);
177 assertEquals("Incorrect Get Device by IP, Port", controller.getDevice(device1.ip(), device1.port()), device1);
178 controller.addDevice(device2);
179 assertTrue("Device2 non added", controller.getDevices().containsValue(device2));
Andrea Campanella86294db2016-03-07 11:42:49 -0800180 controller.removeDevice(device2.deviceId());
Andrea Campanellace279ee2016-01-25 10:21:45 -0800181 assertFalse("Device2 not removed", controller.getDevices().containsValue(device2));
182 }
Sean Condon5548ce62018-07-30 16:00:10 +0100183
184 /**
185 * Tests the post function of the REST SB Controller.
186 */
187 @Test
188 public void testPost() {
189 InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8));
190 int response = controller.post(device1.deviceId(), "/testme", payload, MediaType.APPLICATION_JSON_TYPE);
191 assertEquals(HttpURLConnection.HTTP_OK, response);
192 }
193
194 /**
195 * Tests the put function of the REST SB Controller.
196 */
197 @Test
198 public void testPut() {
199 InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8));
200 int response = controller.put(device1.deviceId(), "/testme", payload, MediaType.APPLICATION_JSON_TYPE);
201 assertEquals(HttpURLConnection.HTTP_OK, response);
202 }
203
204 @Test
205 public void testPatch() {
206 InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8));
207 int response = controller.patch(device1.deviceId(), "/testme", payload, MediaType.APPLICATION_JSON_TYPE);
208 assertEquals(HttpURLConnection.HTTP_OK, response);
209 }
210
211 /**
212 * Tests the delete function of the REST SB Controller.
213 */
214 @Test
215 public void testDelete() {
216 int response = controller.delete(device1.deviceId(), "/testme", null, null);
217 assertEquals(HttpURLConnection.HTTP_OK, response);
218 }
219
220 /**
221 * Tests the get function of the REST SB Controller.
222 */
223 @Test
224 public void testGet() throws IOException {
225 InputStream payload = controller.get(device1.deviceId(), "/testme", MediaType.APPLICATION_JSON_TYPE);
226 String responseText = IOUtils.toString(payload, StandardCharsets.UTF_8);
227 assertEquals(SAMPLE_PAYLOAD, responseText);
228 }
229
230 /**
231 * Tests the post function of the REST SB Controller.
232 */
233 @Test
234 public void testPostReturnString() {
235 InputStream payload = new ByteArrayInputStream(SAMPLE_PAYLOAD.getBytes(StandardCharsets.UTF_8));
236 String result = controller.post(device1.deviceId(), "/testme/testpostreturnstring",
237 payload, MediaType.APPLICATION_JSON_TYPE, String.class);
238 assertEquals("OK", result);
239 }
240
241 /**
242 * Tests the low level getServerSentEvents function of the REST SB Controller.
243 *
244 * Note: If the consumer throws an error it will not be propagated back up
245 * to here - instead the source will go in to error and no more callbacks
246 * will be executed
247 */
248 @Test
249 public void testGetServerSentEvents() {
250 Consumer<InboundSseEvent> sseEventConsumer = (event) -> {
251 System.out.println("ServerSentEvent received: " + event);
252 assertEquals("message-to-rest-sb", event.getName());
253 // Just to show it works we stop before the last message is sent
254 if (Integer.parseInt(event.getId()) == 8) {
255 controller.cancelServerSentEvents(device1.deviceId());
256 }
257 };
258
259 Consumer<Throwable> sseError = (error) -> {
260 System.err.println(error);
261 controller.cancelServerSentEvents(device1.deviceId());
262 //fail(error.toString()); //Does nothing as it's in lambda scope
263 };
264
265 int response = controller.getServerSentEvents(device1.deviceId(),
266 "/testme/server-sent-events",
267 sseEventConsumer,
268 sseError
269 );
270 assertEquals(204, response);
271 }
272
273 /**
274 * Test of cancelling of events from a device - in this case there should not be any.
275 */
276 @Test
277 public void testCancelServerSentEvents() {
278 assertEquals(404, controller.cancelServerSentEvents(device1.deviceId()));
279 }
280
281 /**
282 * Test the high level API for Server Sent Events.
283 */
284 @Test
285 public void testStartServerSentEvents() {
286 AtomicInteger listener1Count = new AtomicInteger();
287 AtomicInteger listener2Count = new AtomicInteger();
288
289 RestSBEventListener listener1 = event -> {
290 System.out.println("Event on Lsnr1: " + event);
291 listener1Count.incrementAndGet();
292 if (Integer.parseInt(event.getId()) == 8) {
293 controller.cancelServerSentEvents(device1.deviceId());
294 }
295 };
296
297 RestSBEventListener listener2 = event -> {
298 listener2Count.incrementAndGet();
299 System.out.println("Event on Lsnr2: " + event);
300 };
301
302 controller.addListener(listener1);
303 controller.addListener(listener2);
304
305 controller.startServerSentEvents(device1.deviceId(), "/testme/server-sent-events");
306
307 controller.removeListener(listener1);
308 controller.removeListener(listener2);
309
310 assertEquals(9, listener1Count.get());
311 assertEquals(9, listener2Count.get());
312 }
Andrea Campanellace279ee2016-01-25 10:21:45 -0800313}