2 * //******************************************************************
4 * // Copyright 2016 Samsung Electronics All Rights Reserved.
6 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
8 * // Licensed under the Apache License, Version 2.0 (the "License");
9 * // you may not use this file except in compliance with the License.
10 * // You may obtain a copy of the License at
12 * // http://www.apache.org/licenses/LICENSE-2.0
14 * // Unless required by applicable law or agreed to in writing, software
15 * // distributed under the License is distributed on an "AS IS" BASIS,
16 * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * // See the License for the specific language governing permissions and
18 * // limitations under the License.
20 * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
23 package org.iotivity.cloud.mqserver.resources;
25 import static com.jayway.awaitility.Awaitility.await;
26 import static java.util.concurrent.TimeUnit.SECONDS;
27 import static org.junit.Assert.assertFalse;
28 import static org.junit.Assert.assertTrue;
29 import static org.mockito.Mockito.mock;
30 import static org.mockito.Mockito.timeout;
31 import static org.mockito.Mockito.verify;
33 import java.util.ArrayList;
34 import java.util.HashMap;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.atomic.AtomicBoolean;
38 import org.iotivity.cloud.base.device.CoapDevice;
39 import org.iotivity.cloud.base.exception.ServerException.ForbiddenException;
40 import org.iotivity.cloud.base.exception.ServerException.NotFoundException;
41 import org.iotivity.cloud.base.exception.ServerException.PreconditionFailedException;
42 import org.iotivity.cloud.base.protocols.IRequest;
43 import org.iotivity.cloud.base.protocols.IResponse;
44 import org.iotivity.cloud.base.protocols.MessageBuilder;
45 import org.iotivity.cloud.base.protocols.coap.CoapRequest;
46 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
47 import org.iotivity.cloud.base.protocols.enums.ContentFormat;
48 import org.iotivity.cloud.base.protocols.enums.Observe;
49 import org.iotivity.cloud.base.protocols.enums.RequestMethod;
50 import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
51 import org.iotivity.cloud.util.Cbor;
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.mockito.Mockito;
55 import org.mockito.invocation.InvocationOnMock;
56 import org.mockito.stubbing.Answer;
58 public class MQBrokerResourceTest {
59 private final String MQ_BROKER_URI = "/.well-known/ocf/ps";
61 private MQBrokerResource mMqBrokerResource = null;
62 private String mTopicPrefix = null;
63 private CoapDevice mMockDevice = null;
64 IResponse mResponse = null;
65 CountDownLatch mLatch = null;
68 // setup for each test
69 public void setUp() throws Exception {
70 mMqBrokerResource = new MQBrokerResource();
72 // insert user's zookeper and broker addresses
73 String zookeeper = "127.0.0.1:2181";
74 String broker = "127.0.0.1:9092";
76 mTopicPrefix = "mqtestTopic";
77 mMqBrokerResource.setKafkaInformation(zookeeper, broker);
78 mLatch = new CountDownLatch(1);
79 mResponse = null; // initialize response packet
80 mMockDevice = mock(CoapDevice.class);
83 Mockito.doAnswer(new Answer<Object>() {
85 public CoapResponse answer(InvocationOnMock invocation)
87 Object[] args = invocation.getArguments();
88 CoapResponse resp = (CoapResponse) args[0];
93 }).when(mMockDevice).sendResponse(Mockito.anyObject());
97 // test topic creation
98 public void testTopicCreationOnDefaultRequestReceived() throws Exception {
99 System.out.println("\t--------------Topic Creation Test------------");
100 CreateTopic(mMockDevice, mTopicPrefix);
101 // assertion: if the response status is "CREATED"
102 assertTrue(mLatch.await(1L, SECONDS));
103 assertTrue(methodCheck(mResponse, ResponseStatus.CREATED));
107 // test subtopic create
108 public void testSubTopicCreationOnDefaultRequestReceived() throws Exception {
110 .println("\t--------------SubTopic Creation Test------------");
111 String mainTopic = mTopicPrefix + "Main";
112 String subTopic = mTopicPrefix + "Sub";
114 CreateTopic(mMockDevice, mainTopic);
116 CreateSubTopic(mMockDevice, mainTopic, subTopic);
117 // assertion: if the response status is "CREATED"
118 assertTrue(mLatch.await(1L, SECONDS));
119 assertTrue(methodCheck(mResponse, ResponseStatus.CREATED));
123 // test topic publish
124 public void testTopicPublishOnDefaultRequestReceived() throws Exception {
125 System.out.println("\t--------------Topic Publish Test------------");
126 String topic = mTopicPrefix + "ForPub";
128 CreateTopic(mMockDevice, topic);
130 PublishTopic(mMockDevice, topic);
131 // assertion: if the response status is "CHANGED"
132 assertTrue(mLatch.await(1L, SECONDS));
133 assertTrue(methodCheck(mResponse, ResponseStatus.CHANGED));
137 // test subscribe request
138 public void testSubscribeOnDefaultRequestReceived() throws Exception {
139 System.out.println("\t--------------Topic Subscribe Test------------");
140 CoapDevice mockSubscriber = mock(CoapDevice.class);
141 String topic = mTopicPrefix + "SubscribeTest";
143 CreateTopic(mMockDevice, topic);
145 PublishTopic(mMockDevice, topic);
146 // callback mock for subscriber
147 Mockito.doAnswer(new Answer<Object>() {
149 public CoapResponse answer(InvocationOnMock invocation)
151 Object[] args = invocation.getArguments();
152 CoapResponse resp = (CoapResponse) args[0];
153 // assertion: if the response status is "CONTENT"
154 // assertion: if the response payload has the "message" property
155 assertTrue(methodCheck(resp, ResponseStatus.CONTENT));
156 assertTrue(hashmapCheck(resp, "message"));
159 }).when(mockSubscriber).sendResponse(Mockito.anyObject());
161 SubscribeTopic(mockSubscriber, topic, Observe.SUBSCRIBE);
165 // test unsubscribe request
166 public void testUnSubscribeOnDefaultRequestReceived() throws Exception {
168 .println("\t--------------Topic Unsubscribe Test------------");
169 CountDownLatch latchSubscriber = new CountDownLatch(2);
170 CoapDevice mockSubscriber = mock(CoapDevice.class);
171 String topic = mTopicPrefix + "UnSubscribeTest";
173 CreateTopic(mMockDevice, topic);
175 PublishTopic(mMockDevice, topic);
176 // callback mock for subscriber
177 Mockito.doAnswer(new Answer<Object>() {
179 public CoapResponse answer(InvocationOnMock invocation)
181 Object[] args = invocation.getArguments();
182 CoapResponse resp = (CoapResponse) args[0];
183 latchSubscriber.countDown();
184 if (latchSubscriber.getCount() == 0) {
185 // assertion: if the response payload has the "message"
187 assertTrue(methodCheck(resp, ResponseStatus.CONTENT));
188 assertTrue(hashmapCheck(resp, "message"));
192 }).when(mockSubscriber).sendResponse(Mockito.anyObject());
194 SubscribeTopic(mockSubscriber, topic, Observe.SUBSCRIBE);
196 SubscribeTopic(mockSubscriber, topic, Observe.UNSUBSCRIBE);
200 // test delete request
201 public void testDeleteTopicOnDefaultRequestReceived() throws Exception {
202 System.out.println("\t--------------Topic Delete Test------------");
203 String topic = mTopicPrefix + "DeleteTest";
205 CreateTopic(mMockDevice, topic);
207 DeleteTopic(mMockDevice, topic);
208 // assertion: if the response status is "DELETED"
209 assertTrue(methodCheck(mResponse, ResponseStatus.DELETED));
210 assertTrue(mLatch.await(1L, SECONDS));
214 // test delete subtopic request
215 public void testDeleteSubTopicOnDefaultRequestReceived() throws Exception {
216 System.out.println("\t--------------Subtopic Delete Test------------");
217 String topic = mTopicPrefix + "DeleteTest";
218 String subTopic = mTopicPrefix + "DeleteTestSub";
220 CreateTopic(mMockDevice, topic);
222 CreateSubTopic(mMockDevice, topic, subTopic);
224 DeleteSubTopic(mMockDevice, topic, subTopic);
225 // assertion: if the response status is "DELETED"
226 assertTrue(methodCheck(mResponse, ResponseStatus.DELETED));
231 public void testTopicSubscribeNofityOnDefaultRequestReceived()
234 .println("\t--------------Topic Publish Notify Test------------");
235 CoapDevice mockSubscriber = mock(CoapDevice.class);
236 CountDownLatch latchSubscriber = new CountDownLatch(2);
237 AtomicBoolean countTrue = new AtomicBoolean();
238 countTrue.set(false);
239 String topic = mTopicPrefix + "NotifyTest";
240 // callback mock for subscriber
241 Mockito.doAnswer(new Answer<Object>() {
243 public CoapResponse answer(InvocationOnMock invocation)
245 Object[] args = invocation.getArguments();
246 CoapResponse resp = (CoapResponse) args[0];
247 latchSubscriber.countDown();
248 // assertion for subscriber
249 if (latchSubscriber.getCount() == 0) {
250 assertTrue(methodCheck(resp, ResponseStatus.CONTENT));
251 assertTrue(hashmapCheck(resp, "message"));
255 }).when(mockSubscriber).sendResponse(Mockito.anyObject());
257 CreateTopic(mMockDevice, topic);
258 // publish topic (publisher)
259 PublishTopic(mMockDevice, topic);
260 // subscribe topic (subscriber)
261 SubscribeTopic(mockSubscriber, topic, Observe.SUBSCRIBE);
262 await().atMost(2, SECONDS).untilFalse(countTrue);
263 PublishTopic(mMockDevice, topic);
264 // verity if subscriber receives two responses
265 assertTrue(latchSubscriber.await(2L, SECONDS));
266 verify(mockSubscriber, timeout(5000).times(2)).sendResponse(
267 Mockito.anyObject());
271 // test discover request
272 public void testTopicDiscoverOnDefaultRequestReceived() throws Exception {
273 System.out.println("\t--------------Topic Discover Test------------");
274 String topic = mTopicPrefix + "DiscoverTest";
275 String subTopic = topic + "sub";
277 CreateTopic(mMockDevice, topic);
279 CreateSubTopic(mMockDevice, topic, subTopic);
282 // assertion 1: if the response status is "CONTENT"
283 // assertion 2: if the response payload has "topiclist" property
284 // and there is the topic created in this unit test in the array
285 boolean methodCheck = methodCheck(mResponse, ResponseStatus.CONTENT);
286 Cbor<HashMap<String, ArrayList<String>>> mArrayCbor = new Cbor<>();
287 HashMap<String, ArrayList<String>> payloadData = mArrayCbor
288 .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
289 ArrayList<String> topicList = payloadData.get("topiclist");
290 System.out.println("\ttopicList : " + topicList);
291 assertTrue(methodCheck);
292 assertTrue(topicList.contains("/.well-known/ocf/ps/" + topic));
293 assertTrue(topicList.contains("/.well-known/ocf/ps/" + topic + "/"
298 // topic read request
299 public void testTopicReadOnDefaultRequestReceived() throws Exception {
300 System.out.println("\t--------------Topic Read Test------------");
301 String topic = mTopicPrefix + "ReadTest";
303 CreateTopic(mMockDevice, topic);
305 PublishTopic(mMockDevice, topic);
308 // assertion1 : if the response status is "CONTENT"
309 // assertion2 : if the response payload has the "message" property
310 assertTrue(methodCheck(mResponse, ResponseStatus.CONTENT));
311 assertTrue(hashmapCheck(mResponse, "message"));
314 @Test(expected = NotFoundException.class)
315 public void testNotCreatedTopicDeleteOnDefaultRequestReceived()
318 .println("\t--------------Not Created Topic Delete Test------------");
319 String topic = mTopicPrefix + "NotCreatedTopicDeleteTest";
321 DeleteTopic(mMockDevice, topic);
324 @Test(expected = NotFoundException.class)
325 public void testNotCreatedSubtopicDeleteOnDefaultRequestReceived()
328 .println("\t--------------Not Created Subtopic Delete Test------------");
329 String topic = mTopicPrefix + "Maintopic";
331 CreateTopic(mMockDevice, topic);
333 topic += "/" + "NotCreatedSubtopicTest";
335 DeleteTopic(mMockDevice, topic);
338 @Test(expected = ForbiddenException.class)
339 // duplicate topic creation
340 public void testDuplicatedTopicCreateOnDefaultRequestReceived()
343 .println("\t--------------Duplicated Topic Creation Test------------");
344 String topic = mTopicPrefix + "DuplicateTest";
346 CreateTopic(mMockDevice, topic);
347 // create topic again
348 CreateTopic(mMockDevice, topic);
351 @Test(expected = ForbiddenException.class)
352 // duplicate subtopic creation
353 public void testDuplicatedSubtopicCreateOnDefaultRequestReceived()
356 .println("\t--------------Duplicated Subtopic Creation Test------------");
358 String topic = mTopicPrefix + "DuplicateTest2";
361 CreateTopic(mMockDevice, topic);
364 topic += "/subtopic";
365 CreateTopic(mMockDevice, topic);
367 // create subtopic again
368 CreateTopic(mMockDevice, topic);
371 @Test(expected = NotFoundException.class)
372 // publish not created topic
373 public void testNotCreatedTopicPublishOnDefaultRequestReceived()
376 .println("\t--------------Not Created Topic Publish Test------------");
377 String topic = mTopicPrefix + "NotCreatedTopicTest";
378 // publish not created topic
379 PublishTopic(mMockDevice, topic);
382 @Test(expected = NotFoundException.class)
383 // subscribe not created topic
384 public void testNotCreatedTopicSubscribeOnDefaultRequestReceived()
387 .println("\t--------------Not Created Topic Subscribe Test------------");
388 String topic = mTopicPrefix + "NotCreatedTopicSubscribeTest";
389 SubscribeTopic(mMockDevice, topic, Observe.SUBSCRIBE);
392 @Test(expected = NotFoundException.class)
393 // unsubscribe not created topic
394 public void testNotCreatedTopicUnSubscribeOnDefaultRequestReceived()
397 .println("\t--------------Not Created Topic Unsubscribe Test------------");
398 String topic = mTopicPrefix + "NotCreatedTopicUnSubscribeTest";
399 SubscribeTopic(mMockDevice, topic, Observe.UNSUBSCRIBE);
402 @Test(expected = PreconditionFailedException.class)
403 public void testTopicPublishWithoutMessage() throws Exception {
405 .println("\t--------------Topic Publish Without Message Test------------");
406 String topic = mTopicPrefix + "ForPubWithoutMessage";
409 CreateTopic(mMockDevice, topic);
411 // topic publish without message
412 String requestUri = MQ_BROKER_URI + "/" + topic;
413 IRequest request = MessageBuilder.createRequest(RequestMethod.POST,
416 mMqBrokerResource.onDefaultRequestReceived(mMockDevice, request);
419 @Test(expected = NotFoundException.class)
420 // create subtopic under not created maintopic
421 public void testSubTopicCreateUnderNotCreatedTopicOnDefaultRequestReceived()
424 .println("\t--------------Create Subtopic under Not Created Maintopic ------------");
425 String mainTopic = mTopicPrefix + "NotCreatedMain";
426 String subTopic = mTopicPrefix + "NotCreatedSub";
428 CreateSubTopic(mMockDevice, mainTopic, subTopic);
432 // create topic which has 'core.light' rt
433 public void testTopicCreationWithRtOnDefaultRequestReceived()
436 .println("\t--------------Topic Creation with RT Test------------");
437 String topicName = mTopicPrefix + "RtTest";
438 String rt = "rt=core.light";
439 CreateTopicWithRt(mMockDevice, topicName, rt);
440 // assertion: if the response status is "CREATED"
441 assertTrue(methodCheck(mResponse, ResponseStatus.CREATED));
445 // create topic which has 'core.light' rt
446 public void testSubtopicCreationWithRtOnDefaultRequestReceived()
449 .println("\t--------------Subtopic Creation with RT Test------------");
450 String topicName = mTopicPrefix + "RtTest2";
451 String rt = "rt=core.light";
454 CreateTopicWithRt(mMockDevice, topicName, rt);
457 topicName += "/subtopic";
458 CreateTopicWithRt(mMockDevice, topicName, rt);
460 assertTrue(methodCheck(mResponse, ResponseStatus.CREATED));
464 // test discover request with rt
465 public void testDiscoverTopicWithRtOnDefaultRequestReceived()
468 .println("\t--------------Topic Discover with Rt Test------------");
469 String topicName = mTopicPrefix + "DiscoverRtTest";
470 String topicNameWithoutRt = mTopicPrefix + "DiscoverRtTestWithoutRt";
471 String rt = "rt=core.light";
472 // create topic with rt
473 CreateTopicWithRt(mMockDevice, topicName, rt);
475 CreateTopic(mMockDevice, topicNameWithoutRt);
477 DiscoverTopicWithRt(rt);
478 // assertion 1: if the response status is "CONTENT"
479 // assertion 2: if topic list contains the topic with rt
480 // assertion 3: if topic list contains no topics which does not have the
482 Cbor<HashMap<String, ArrayList<String>>> mArrayCbor = new Cbor<>();
483 HashMap<String, ArrayList<String>> payloadData = mArrayCbor
484 .parsePayloadFromCbor(mResponse.getPayload(), HashMap.class);
485 ArrayList<String> topicList = payloadData.get("topiclist");
486 System.out.println("\ttopicList : " + topicList);
487 assertTrue(methodCheck(mResponse, ResponseStatus.CONTENT));
488 assertTrue(topicList.contains("/.well-known/ocf/ps/" + topicName));
489 assertFalse(topicList.contains("/.well-known/ocf/ps/"
490 + topicNameWithoutRt));
493 private IRequest PublishTopicRequest(String topicName) {
494 IRequest request = null;
495 HashMap<String, Object> tags = new HashMap<String, Object>();
496 HashMap<String, Object> message = new HashMap<String, Object>();
497 message.put("status", "on");
498 message.put("brightness", 20);
499 tags.put("message", message);
500 Cbor<HashMap<String, Object>> cbor = new Cbor<HashMap<String, Object>>();
501 String uri = MQ_BROKER_URI + "/" + topicName;
502 request = MessageBuilder.createRequest(RequestMethod.POST, uri, null,
503 ContentFormat.APPLICATION_CBOR,
504 cbor.encodingPayloadToCbor(tags));
508 private IRequest CreateTopicRequest(String topicName) {
509 IRequest request = null;
510 request = MessageBuilder.createRequest(RequestMethod.PUT, MQ_BROKER_URI
511 + "/" + topicName, null);
515 private IRequest CreateSubTopicRequest(String topicName, String subTopicName) {
516 IRequest request = null;
517 String uri = MQ_BROKER_URI + "/" + topicName + "/" + subTopicName;
518 request = MessageBuilder.createRequest(RequestMethod.PUT, uri, null);
522 private IRequest CreateTopicWithRtRequest(String topicName, String type) {
523 IRequest request = null;
524 request = MessageBuilder.createRequest(RequestMethod.PUT, MQ_BROKER_URI
525 + "/" + topicName, type);
529 private IRequest DeleteTopicRequest(String topicName) {
530 IRequest request = null;
531 String uri = MQ_BROKER_URI + "/" + topicName;
532 request = MessageBuilder.createRequest(RequestMethod.DELETE, uri, null);
536 private IRequest SubscribeTopicRequest(String topicName) {
537 IRequest request = null;
538 String uri = MQ_BROKER_URI + "/" + topicName;
539 request = MessageBuilder.createRequest(RequestMethod.GET, uri, null);
543 private IRequest DiscoverTopicRequest() {
544 IRequest request = null;
545 request = MessageBuilder.createRequest(RequestMethod.GET,
546 MQ_BROKER_URI, null);
550 private IRequest DiscoverTopicWithRtRequest(String rt) {
551 IRequest request = null;
552 request = MessageBuilder.createRequest(RequestMethod.GET,
557 private CoapRequest ReadTopicRequest(String topicName) {
558 IRequest request = null;
559 String uri = MQ_BROKER_URI + "/" + topicName;
560 request = MessageBuilder.createRequest(RequestMethod.GET, uri, null);
561 CoapRequest mqRequest = (CoapRequest) request;
565 private void CreateTopicWithRt(CoapDevice mockDevice, String topicName,
566 String type) throws Exception {
567 System.out.println("-----CreateTopic || topic : " + topicName);
568 IRequest request = null;
569 request = CreateTopicWithRtRequest(topicName, type);
570 mMqBrokerResource.onDefaultRequestReceived(mockDevice, request);
573 private void CreateTopic(CoapDevice mockDevice, String topicName)
575 System.out.println("-----CreateTopic || topic : " + topicName);
576 IRequest request = null;
577 request = CreateTopicRequest(topicName);
578 mMqBrokerResource.onDefaultRequestReceived(mockDevice, request);
581 private void CreateSubTopic(CoapDevice mockDevice, String mainTopicName,
582 String subTopicName) throws Exception {
583 System.out.println("-----CreateSubTopic || topic : " + mainTopicName
584 + " || subtopic : " + subTopicName);
585 IRequest subTopicRequest = null;
586 subTopicRequest = CreateSubTopicRequest(mainTopicName, subTopicName);
587 mMqBrokerResource.onDefaultRequestReceived(mockDevice, subTopicRequest);
590 private void PublishTopic(CoapDevice mockDevice, String topicName)
592 System.out.println("-----PublishTopic : " + topicName);
593 IRequest request = null;
594 request = PublishTopicRequest(topicName);
595 mMqBrokerResource.onDefaultRequestReceived(mockDevice, request);
598 private void SubscribeTopic(CoapDevice mockSubscriber, String topicName,
599 Observe observe) throws Exception {
600 System.out.println("-----SubscribeTopic : " + topicName);
601 IRequest requestSubscribe = null;
602 requestSubscribe = SubscribeTopicRequest(topicName);
603 CoapRequest mqRequest = (CoapRequest) requestSubscribe;
604 mqRequest.setObserve(observe);
605 mMqBrokerResource.onDefaultRequestReceived(mockSubscriber, mqRequest);
608 private void DeleteTopic(CoapDevice mockDevice, String topicName)
610 System.out.println("-----DeleteTopic : " + topicName);
611 IRequest requestToDelete = null;
612 requestToDelete = DeleteTopicRequest(topicName);
613 mMqBrokerResource.onDefaultRequestReceived(mockDevice, requestToDelete);
616 private void DeleteSubTopic(CoapDevice mockDevice, String topicName,
617 String subTopicName) throws Exception {
618 System.out.println("-----DeleteTopic : " + topicName);
619 String deleteUri = topicName + "/" + subTopicName;
620 IRequest requestToDelete = null;
621 requestToDelete = DeleteTopicRequest(deleteUri);
622 mMqBrokerResource.onDefaultRequestReceived(mockDevice, requestToDelete);
625 private void DiscoverTopic() throws Exception {
626 System.out.println("-----DiscoverTopic : ");
627 IRequest requestToDiscover = null;
628 requestToDiscover = DiscoverTopicRequest();
629 mMqBrokerResource.onDefaultRequestReceived(mMockDevice,
633 private void DiscoverTopicWithRt(String rt) throws Exception {
634 System.out.println("-----DiscoverTopicWithRt : ");
635 IRequest requestToDiscover = null;
636 requestToDiscover = DiscoverTopicWithRtRequest(rt);
637 mMqBrokerResource.onDefaultRequestReceived(mMockDevice,
641 private void ReadTopic(String topicName) throws Exception {
642 System.out.println("-----ReadTopic : " + topicName);
643 CoapRequest readRequest = null;
644 readRequest = ReadTopicRequest(topicName);
645 mMqBrokerResource.onDefaultRequestReceived(mMockDevice, readRequest);
648 private boolean hashmapCheck(IResponse response, String propertyName) {
649 Cbor<HashMap<String, Object>> mCbor = new Cbor<>();
650 HashMap<String, Object> payloadData = mCbor.parsePayloadFromCbor(
651 response.getPayload(), HashMap.class);
652 if (payloadData.get(propertyName) != null)
658 private boolean methodCheck(IResponse response,
659 ResponseStatus responseStatus) {
660 if (responseStatus == response.getStatus())