e2f3d89c9459310a218cf2803171dab72be7ba80
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / rests / services / impl / RestconfStreamsSubscriptionServiceImplTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040.rests.services.impl;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.mockito.ArgumentMatchers.any;
12 import static org.mockito.Mockito.doReturn;
13 import static org.mockito.Mockito.mock;
14
15 import com.google.common.collect.ImmutableClassToInstanceMap;
16 import java.io.FileNotFoundException;
17 import java.net.URI;
18 import java.net.URISyntaxException;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22 import javax.ws.rs.core.MultivaluedHashMap;
23 import javax.ws.rs.core.UriBuilder;
24 import javax.ws.rs.core.UriInfo;
25 import org.junit.AfterClass;
26 import org.junit.Before;
27 import org.junit.BeforeClass;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.mockito.Mock;
31 import org.mockito.junit.MockitoJUnitRunner;
32 import org.opendaylight.mdsal.common.api.CommitInfo;
33 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
34 import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
35 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
36 import org.opendaylight.mdsal.dom.api.DOMNotificationService;
37 import org.opendaylight.mdsal.dom.api.DOMSchemaService;
38 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
39 import org.opendaylight.restconf.common.util.SimpleUriInfo;
40 import org.opendaylight.restconf.nb.rfc8040.TestRestconfUtils;
41 import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
42 import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload;
43 import org.opendaylight.restconf.nb.rfc8040.streams.Configuration;
44 import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenerAdapter;
45 import org.opendaylight.restconf.nb.rfc8040.streams.listeners.ListenersBroker;
46 import org.opendaylight.restconf.nb.rfc8040.utils.RestconfConstants;
47 import org.opendaylight.restconf.nb.rfc8040.utils.parser.IdentifierCodec;
48 import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
49 import org.opendaylight.yangtools.concepts.ListenerRegistration;
50 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
51 import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
52
53 @RunWith(MockitoJUnitRunner.StrictStubs.class)
54 public class RestconfStreamsSubscriptionServiceImplTest {
55
56     private static final String URI = "/restconf/18/data/ietf-restconf-monitoring:restconf-state/streams/stream/"
57             + "toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE";
58
59     @Mock
60     private DOMDataBroker dataBroker;
61     @Mock
62     private UriInfo uriInfo;
63     @Mock
64     private DOMNotificationService notificationService;
65
66     private Configuration configurationWs;
67     private Configuration configurationSse;
68
69     private SchemaContextHandler schemaHandler;
70
71     @Before
72     public void setUp() throws FileNotFoundException, URISyntaxException {
73         final DOMDataTreeWriteTransaction wTx = mock(DOMDataTreeWriteTransaction.class);
74         doReturn(wTx).when(dataBroker).newWriteOnlyTransaction();
75         doReturn(CommitInfo.emptyFluentFuture()).when(wTx).commit();
76
77         schemaHandler = new SchemaContextHandler(dataBroker, mock(DOMSchemaService.class));
78
79         DOMDataTreeChangeService dataTreeChangeService = mock(DOMDataTreeChangeService.class);
80         doReturn(mock(ListenerRegistration.class)).when(dataTreeChangeService)
81                 .registerDataTreeChangeListener(any(), any());
82
83         doReturn(ImmutableClassToInstanceMap.of(DOMDataTreeChangeService.class, dataTreeChangeService))
84                 .when(dataBroker).getExtensions();
85
86         doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters();
87         doReturn(new LocalUriInfo().getBaseUriBuilder()).when(uriInfo).getBaseUriBuilder();
88         doReturn(new URI("http://127.0.0.1/" + URI)).when(uriInfo).getAbsolutePath();
89         schemaHandler.onModelContextUpdated(
90             YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/notifications")));
91         configurationWs = new Configuration(0, 100, 10, false);
92         configurationSse = new Configuration(0, 100, 10, true);
93     }
94
95     private static class LocalUriInfo extends SimpleUriInfo {
96         LocalUriInfo() {
97             super("/");
98         }
99
100         @Override
101         public URI getBaseUri() {
102             return UriBuilder.fromUri("http://localhost:8181").build();
103         }
104     }
105
106     @BeforeClass
107     public static void setUpBeforeTest() {
108         final Map<String, ListenerAdapter> listenersByStreamNameSetter = new HashMap<>();
109         final ListenerAdapter adapter = mock(ListenerAdapter.class);
110         final YangInstanceIdentifier yiid = mock(YangInstanceIdentifier.class);
111         doReturn(yiid).when(adapter).getPath();
112         doReturn("JSON").when(adapter).getOutputType();
113         listenersByStreamNameSetter.put(
114                 "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
115                 adapter);
116         ListenersBroker.getInstance().setDataChangeListeners(listenersByStreamNameSetter);
117     }
118
119     @AfterClass
120     public static void setUpAfterTest() {
121         ListenersBroker.getInstance().setDataChangeListeners(Collections.emptyMap());
122     }
123
124     @Test
125     public void testSubscribeToStreamSSE() {
126         ListenersBroker.getInstance().registerDataChangeListener(
127                 IdentifierCodec.deserialize("toaster:toaster/toasterStatus", schemaHandler.get()),
128                 "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
129                 NotificationOutputType.XML);
130         final RestconfStreamsSubscriptionServiceImpl streamsSubscriptionService =
131                 new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService,
132                         schemaHandler, configurationSse);
133         final NormalizedNodePayload response = streamsSubscriptionService.subscribeToStream(
134             "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE", uriInfo);
135         assertEquals("http://localhost:8181/" + RestconfConstants.BASE_URI_PATTERN
136                 + "/" + RestconfConstants.NOTIF
137                 + "/data-change-event-subscription/toaster:toaster/toasterStatus/"
138                 + "datastore=OPERATIONAL/scope=ONE", response.getNewHeaders().get("Location").toString());
139     }
140
141     @Test
142     public void testSubscribeToStreamWS() {
143         ListenersBroker.getInstance().registerDataChangeListener(
144                 IdentifierCodec.deserialize("toaster:toaster/toasterStatus", schemaHandler.get()),
145                 "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE",
146                 NotificationOutputType.XML);
147         final RestconfStreamsSubscriptionServiceImpl streamsSubscriptionService =
148                 new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService,
149                         schemaHandler, configurationWs);
150         final NormalizedNodePayload response = streamsSubscriptionService.subscribeToStream(
151             "data-change-event-subscription/toaster:toaster/toasterStatus/datastore=OPERATIONAL/scope=ONE", uriInfo);
152         assertEquals("ws://localhost:8181/" + RestconfConstants.BASE_URI_PATTERN
153                 + "/data-change-event-subscription/toaster:toaster/toasterStatus/"
154                 + "datastore=OPERATIONAL/scope=ONE", response.getNewHeaders().get("Location").toString());
155     }
156
157     @Test(expected = RestconfDocumentedException.class)
158     public void testSubscribeToStreamMissingDatastoreInPath() {
159         final RestconfStreamsSubscriptionServiceImpl streamsSubscriptionService =
160                 new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService,
161                         schemaHandler, configurationWs);
162         streamsSubscriptionService.subscribeToStream("toaster:toaster/toasterStatus/scope=ONE", uriInfo);
163     }
164
165     @Test(expected = RestconfDocumentedException.class)
166     public void testSubscribeToStreamMissingScopeInPath() {
167         final RestconfStreamsSubscriptionServiceImpl streamsSubscriptionService =
168                 new RestconfStreamsSubscriptionServiceImpl(dataBroker, notificationService,
169                         schemaHandler, configurationWs);
170         streamsSubscriptionService.subscribeToStream("toaster:toaster/toasterStatus/datastore=OPERATIONAL",
171                 uriInfo);
172     }
173 }