2 * ============LICENSE_START===================================================
3 * Copyright (c) 2018 Amdocs
4 * ============================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 * ============LICENSE_END=====================================================
19 package org.onap.sdnc.apps.pomba.networkdiscovery.unittest.service;
21 import static com.github.tomakehurst.wiremock.client.WireMock.get;
22 import static com.github.tomakehurst.wiremock.client.WireMock.ok;
23 import static com.github.tomakehurst.wiremock.client.WireMock.okJson;
24 import static com.github.tomakehurst.wiremock.client.WireMock.post;
25 import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
26 import static org.junit.Assert.assertEquals;
27 import static org.junit.Assert.assertNull;
28 import static org.junit.Assert.assertTrue;
29 import static org.junit.Assert.fail;
31 import com.bazaarvoice.jolt.JsonUtils;
32 import com.fasterxml.jackson.databind.AnnotationIntrospector;
33 import com.fasterxml.jackson.databind.ObjectMapper;
34 import com.fasterxml.jackson.databind.type.TypeFactory;
35 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
36 import com.github.tomakehurst.wiremock.client.WireMock;
37 import com.github.tomakehurst.wiremock.junit.WireMockRule;
38 import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
39 import com.github.tomakehurst.wiremock.verification.LoggedRequest;
41 import java.net.URISyntaxException;
42 import java.text.MessageFormat;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Base64;
46 import java.util.List;
47 import java.util.UUID;
49 import javax.servlet.http.HttpServletRequest;
50 import javax.ws.rs.core.HttpHeaders;
51 import javax.ws.rs.core.Response;
52 import javax.ws.rs.core.Response.Status;
54 import org.eclipse.jetty.util.security.Password;
55 import org.junit.After;
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.Mockito;
61 import org.onap.logging.ref.slf4j.ONAPLogConstants;
62 import org.onap.pomba.common.datatypes.DataQuality;
63 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.Attribute;
64 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.NetworkDiscoveryNotification;
65 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.NetworkDiscoveryResponse;
66 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.Resource;
67 import org.onap.sdnc.apps.pomba.networkdiscovery.service.rs.RestService;
68 import org.springframework.beans.factory.annotation.Autowired;
69 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
70 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
71 import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
72 import org.springframework.boot.test.context.SpringBootTest;
73 import org.springframework.test.context.TestPropertySource;
74 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
75 import org.springframework.test.context.web.WebAppConfiguration;
77 @RunWith(SpringJUnit4ClassRunner.class)
78 @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
81 @TestPropertySource(properties = { "openstack.type.vserver.url=http://localhost:8774/v2.1/servers/{0}",
82 "openstack.identity.url=http://localhost:5000/v3/auth/tokens",
83 "enricher.keyStorePath=src/test/resources/client-cert-onap.p12",
84 "enricher.keyStorePassword=OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10",
85 "basicAuth.username=admin",
86 "basicAuth.password=OBF:1u2a1toa1w8v1tok1u30" })
88 public class NetworkDiscoveryTest {
89 private static final String V1 = "v1";
90 private static final String APP = "junit";
92 private static final String RESOURCE_TYPE_VSERVER = "vserver";
93 private static final String CALLBACK_PATH = "/callback";
95 private static final String AUTH = "Basic " + Base64.getEncoder().encodeToString((
96 "admin:" + Password.deobfuscate("OBF:1u2a1toa1w8v1tok1u30")).getBytes());
99 public WireMockRule identityRule = new WireMockRule(wireMockConfig().port(5000));
102 public WireMockRule openstackRule = new WireMockRule(wireMockConfig().port(8774));
105 public WireMockRule callbackRule = new WireMockRule(wireMockConfig().dynamicPort());
108 private RestService service;
110 private String transactionId = UUID.randomUUID().toString();
111 private String requestId = UUID.randomUUID().toString();
112 private HttpServletRequest httpRequest = Mockito.mock(HttpServletRequest.class);
114 private static final String TEST_RESOURCES = "src/test/resources/jolt/";
117 public NetworkDiscoveryTest() throws URISyntaxException {
122 public void setUp() throws Exception {
126 public void tearDown() throws Exception {
130 public void testNoAuthHeader() throws Exception {
131 // no Authorization header
132 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
133 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, null, APP, this.transactionId,
134 this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
135 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
136 // should get WWW-Authenticate header in response
137 assertTrue(response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE).startsWith("Basic realm"));
141 public void testUnauthorized() throws Exception {
142 String authorization = "Basic " + Base64.getEncoder().encodeToString("aaa:bbb".getBytes());
143 // bad Authorization header
144 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
145 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, authorization, APP,
146 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
147 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
148 // should not get WWW-Authenticate header in response
149 assertNull(response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
153 public void testNoVersion() throws Exception {
154 // no Authorization header
155 String authorization = "Basic " + Base64.getEncoder().encodeToString("aaa:bbb".getBytes());
156 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
157 Response response = this.service.findbyResourceIdAndType(this.httpRequest, null, authorization, APP,
158 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
159 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
160 // should get WWW-Authenticate header in response
161 assertTrue(((String) response.getEntity()).contains("version"));
165 public void testVerifyAppId() throws Exception {
166 // no X-FromAppId header
167 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
168 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, null, this.transactionId,
169 this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
170 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
171 assertTrue(((String) response.getEntity()).contains(ONAPLogConstants.Headers.PARTNER_NAME));
175 public void testVerifyRequestId() throws Exception {
176 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
177 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
178 null, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
179 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
180 assertTrue(((String) response.getEntity()).contains("requestId"));
184 public void testVerifyNotificationUrl() throws Exception {
185 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
186 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
187 this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, null);
188 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
189 assertTrue(((String) response.getEntity()).contains("notificationURL"));
193 public void testVerifyResourceIds() throws Exception {
194 // no resourceIds list
196 List<String> resourceIds = null;
197 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP,
198 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
199 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
200 assertTrue(((String) response.getEntity()).contains("resourceIds"));
203 // empty resourceId list
205 List<String> resourceIds = new ArrayList<>();
206 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP,
207 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
208 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
209 assertTrue(((String) response.getEntity()).contains("resourceIds"));
214 public void testVerifyResourceType() throws Exception {
216 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
217 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
218 this.requestId, null, resourceIds, getCallbackUrl());
219 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
220 assertTrue(((String) response.getEntity()).contains("resourceType"));
224 public void testVerifyInternalError() throws Exception {
226 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
227 Response response = this.service.findbyResourceIdAndType(null, V1, AUTH, APP, this.transactionId,
228 this.requestId, null, resourceIds, getCallbackUrl());
229 assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatus());
233 public void testDiscoverVserver() throws Exception {
234 String vserverId = UUID.randomUUID().toString();
236 String resourcePath = MessageFormat.format("/v2.1/servers/{0}",
237 new Object[] { vserverId });
239 String identityPath = "/v3/auth/tokens";
241 Object sourceObject = JsonUtils.filepathToObject(TEST_RESOURCES + "vserver-input.json");
243 String openstackApiResponse = JsonUtils.toJsonString(sourceObject);
245 this.openstackRule.stubFor(get(resourcePath).willReturn(okJson(openstackApiResponse)));
247 this.identityRule.stubFor(post(identityPath).willReturn(okJson("{}").withHeader("X-Subject-Token", "tokenId")));
249 this.callbackRule.stubFor(post(CALLBACK_PATH).willReturn(ok("Acknowledged")));
251 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, null, this.requestId,
252 RESOURCE_TYPE_VSERVER, Arrays.asList(vserverId), getCallbackUrl());
254 assertEquals(Status.OK.getStatusCode(), response.getStatus());
255 NetworkDiscoveryResponse entity = (NetworkDiscoveryResponse) response.getEntity();
256 assertEquals(requestId, entity.getRequestId());
257 assertEquals(Status.ACCEPTED.getStatusCode(), entity.getCode().intValue());
258 assertEquals(Boolean.FALSE, entity.getAckFinalIndicator());
260 List<ServeEvent> events = waitForRequests(this.callbackRule, 1, 10);
261 LoggedRequest notificationRequest = events.get(0).getRequest();
262 assertEquals(AUTH, notificationRequest.getHeader(HttpHeaders.AUTHORIZATION));
263 String notificationJson = notificationRequest.getBodyAsString();
265 ObjectMapper mapper = new ObjectMapper();
266 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
267 mapper.setAnnotationIntrospector(introspector);
268 NetworkDiscoveryNotification notification = mapper.readValue(notificationJson,
269 NetworkDiscoveryNotification.class);
271 assertEquals(requestId, notification.getRequestId());
272 assertEquals(Status.OK.getStatusCode(), notification.getCode().intValue());
273 assertEquals(Boolean.TRUE, notification.getAckFinalIndicator());
275 assertEquals(1, notification.getResources().size());
276 Resource vserver = notification.getResources().get(0);
277 assertEquals(vserverId, vserver.getId());
278 assertEquals("vserver", vserver.getType());
279 assertEquals(DataQuality.Status.ok, vserver.getDataQuality().getStatus());
281 verifyAttribute(vserver.getAttributeList(), "status", "ACTIVE");
282 verifyAttribute(vserver.getAttributeList(), "inMaintenance", "true");
283 verifyAttribute(vserver.getAttributeList(), "hostname", "norm-bouygues");
284 verifyAttribute(vserver.getAttributeList(), "vmState", "active");
288 public void testDiscoverVserverFailure() throws Exception {
289 String vserverId = UUID.randomUUID().toString();
291 String resourcePath = MessageFormat.format("/v2.1/servers/{0}",
292 new Object[] { vserverId });
294 String identityPath = "/v3/auth/tokens";
296 this.openstackRule.stubFor(get(resourcePath).willReturn(WireMock.notFound()));
298 this.identityRule.stubFor(post(identityPath).willReturn(okJson("{}").withHeader("X-Subject-Token", "tokenId")));
300 this.callbackRule.stubFor(post(CALLBACK_PATH).willReturn(ok("Acknowledged")));
302 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, null, this.requestId,
303 RESOURCE_TYPE_VSERVER, Arrays.asList(vserverId), getCallbackUrl());
305 assertEquals(Status.OK.getStatusCode(), response.getStatus());
306 NetworkDiscoveryResponse entity = (NetworkDiscoveryResponse) response.getEntity();
307 assertEquals(requestId, entity.getRequestId());
308 assertEquals(Status.ACCEPTED.getStatusCode(), entity.getCode().intValue());
309 assertEquals(Boolean.FALSE, entity.getAckFinalIndicator());
311 List<ServeEvent> events = waitForRequests(this.callbackRule, 1, 10);
312 LoggedRequest notificationRequest = events.get(0).getRequest();
313 assertEquals(AUTH, notificationRequest.getHeader(HttpHeaders.AUTHORIZATION));
314 String notificationJson = notificationRequest.getBodyAsString();
316 ObjectMapper mapper = new ObjectMapper();
317 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
318 mapper.setAnnotationIntrospector(introspector);
319 NetworkDiscoveryNotification notification = mapper.readValue(notificationJson,
320 NetworkDiscoveryNotification.class);
322 assertEquals(requestId, notification.getRequestId());
323 assertEquals(Status.OK.getStatusCode(), notification.getCode().intValue());
324 assertEquals(Boolean.TRUE, notification.getAckFinalIndicator());
326 assertEquals(1, notification.getResources().size());
327 Resource vserver = notification.getResources().get(0);
328 assertEquals(vserverId, vserver.getId());
329 assertEquals("vserver", vserver.getType());
330 assertEquals(DataQuality.Status.error, vserver.getDataQuality().getStatus());
331 assertNull(vserver.getAttributeList());
336 * Verify API returns a final response indicating no discovery possible.
339 public void testUnsupportedResourceType() throws Exception {
341 String resourceType = "unsupported";
342 List<String> resourceIds = Arrays.asList("dummyId");
343 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
344 this.requestId, resourceType, resourceIds, getCallbackUrl());
345 assertEquals(Status.OK.getStatusCode(), response.getStatus());
347 NetworkDiscoveryResponse entity = (NetworkDiscoveryResponse) response.getEntity();
348 System.err.println("entity:" + entity);
349 assertEquals(Boolean.TRUE, entity.getAckFinalIndicator());
350 assertEquals(Status.NO_CONTENT.getStatusCode(), entity.getCode().intValue());
354 public void testLoginFailure() throws Exception {
355 String vserverId = UUID.randomUUID().toString();
357 String identityPath = "/v3/auth/tokens";
359 this.identityRule.stubFor(post(identityPath).willReturn(WireMock.unauthorized()));
361 this.callbackRule.stubFor(post(CALLBACK_PATH).willReturn(ok("Acknowledged")));
363 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, null, this.requestId,
364 RESOURCE_TYPE_VSERVER, Arrays.asList(vserverId), getCallbackUrl());
366 assertEquals(Status.OK.getStatusCode(), response.getStatus());
367 NetworkDiscoveryResponse entity = (NetworkDiscoveryResponse) response.getEntity();
368 assertEquals(requestId, entity.getRequestId());
369 assertEquals(Status.ACCEPTED.getStatusCode(), entity.getCode().intValue());
370 assertEquals(Boolean.FALSE, entity.getAckFinalIndicator());
372 List<ServeEvent> events = waitForRequests(this.callbackRule, 1, 10);
373 LoggedRequest notificationRequest = events.get(0).getRequest();
374 assertEquals(AUTH, notificationRequest.getHeader(HttpHeaders.AUTHORIZATION));
375 String notificationJson = notificationRequest.getBodyAsString();
377 ObjectMapper mapper = new ObjectMapper();
378 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
379 mapper.setAnnotationIntrospector(introspector);
380 NetworkDiscoveryNotification notification = mapper.readValue(notificationJson,
381 NetworkDiscoveryNotification.class);
383 assertEquals(requestId, notification.getRequestId());
384 assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), notification.getCode().intValue());
385 assertEquals(Boolean.TRUE, notification.getAckFinalIndicator());
386 assertNull(notification.getResources());
390 private void verifyAttribute(List<Attribute> attributeList, String attrName, String attrValue) {
391 for (Attribute attr : attributeList) {
392 if (attr.getName().equals(attrName)) {
393 assertEquals("Unexpected value for attribute " + attrName, attrValue, attr.getValue());
397 fail("Attribute " + attrName + " not found");
400 private List<ServeEvent> waitForRequests(WireMockRule service, int minRequests, long timeoutSeconds)
401 throws InterruptedException {
403 long remaining = timeoutSeconds * 1000L;
404 long retryInterval = Math.min(remaining / 5, 1000);
406 List<ServeEvent> events = service.getAllServeEvents();
407 if (events.size() >= minRequests) {
410 if (remaining <= 0) {
411 fail("Timeout waiting for " + minRequests + " requests");
413 Thread.sleep(retryInterval);
414 remaining -= retryInterval;
418 private String getCallbackUrl() {
419 return "http://localhost:" + this.callbackRule.port() + CALLBACK_PATH;