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.okTextXml;
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.fasterxml.jackson.databind.AnnotationIntrospector;
32 import com.fasterxml.jackson.databind.ObjectMapper;
33 import com.fasterxml.jackson.databind.type.TypeFactory;
34 import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
35 import com.github.tomakehurst.wiremock.junit.WireMockRule;
36 import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
37 import com.github.tomakehurst.wiremock.verification.LoggedRequest;
38 import java.net.URISyntaxException;
39 import java.text.MessageFormat;
40 import java.util.ArrayList;
41 import java.util.Arrays;
42 import java.util.Base64;
43 import java.util.List;
44 import java.util.UUID;
45 import javax.servlet.http.HttpServletRequest;
46 import javax.ws.rs.core.HttpHeaders;
47 import javax.ws.rs.core.Response;
48 import javax.ws.rs.core.Response.Status;
49 import org.eclipse.jetty.util.security.Password;
50 import org.junit.After;
51 import org.junit.Before;
52 import org.junit.Rule;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.onap.logging.ref.slf4j.ONAPLogConstants;
56 import org.onap.pomba.common.datatypes.DataQuality;
57 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.Attribute;
58 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.NetworkDiscoveryNotification;
59 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.NetworkDiscoveryResponse;
60 import org.onap.sdnc.apps.pomba.networkdiscovery.datamodel.Resource;
61 import org.onap.sdnc.apps.pomba.networkdiscovery.service.rs.RestService;
62 import org.springframework.beans.factory.annotation.Autowired;
63 import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
64 import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
65 import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
66 import org.springframework.boot.test.context.SpringBootTest;
67 import org.springframework.core.env.Environment;
68 import org.springframework.test.context.TestPropertySource;
69 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
70 import org.springframework.test.context.web.WebAppConfiguration;
72 @RunWith(SpringJUnit4ClassRunner.class)
73 @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
76 @TestPropertySource(properties = { "enricher.url=http://localhost:9505",
77 "enricher.keyStorePath=src/test/resources/client-cert-onap.p12",
78 "enricher.keyStorePassword=OBF:1y0q1uvc1uum1uvg1pil1pjl1uuq1uvk1uuu1y10",
79 "basicAuth.username=admin",
80 "basicAuth.password=OBF:1u2a1toa1w8v1tok1u30" })
81 public class NetworkDiscoveryTest {
82 private static final String V1 = "v1";
83 private static final String APP = "junit";
85 private static final String RESOURCE_TYPE_VSERVER = "vserver";
86 private static final String CALLBACK_PATH = "/callback";
88 private static final String AUTH = "Basic " + Base64.getEncoder().encodeToString((
89 "admin:" + Password.deobfuscate("OBF:1u2a1toa1w8v1tok1u30")).getBytes());
91 private Environment environment;
94 public WireMockRule enricherRule = new WireMockRule(wireMockConfig().port(9505));
97 public WireMockRule callbackRule = new WireMockRule(wireMockConfig().dynamicPort());
100 private RestService service;
102 private String transactionId = UUID.randomUUID().toString();
103 private String requestId = UUID.randomUUID().toString();
104 private HttpServletRequest httpRequest = new TestHttpServletRequest();
106 public NetworkDiscoveryTest() throws URISyntaxException {
111 public void setUp() throws Exception {
115 public void tearDown() throws Exception {
119 public void testNoAuthHeader() throws Exception {
120 // no Authorization header
121 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
122 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, null, APP, this.transactionId,
123 this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
124 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
125 // should get WWW-Authenticate header in response
126 assertTrue(response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE).startsWith("Basic realm"));
130 public void testUnauthorized() throws Exception {
131 String authorization = "Basic " + Base64.getEncoder().encodeToString("aaa:bbb".getBytes());
132 // bad Authorization header
133 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
134 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, authorization, APP,
135 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
136 assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
137 // should not get WWW-Authenticate header in response
138 assertNull(response.getHeaderString(HttpHeaders.WWW_AUTHENTICATE));
142 public void testVerifyAppId() throws Exception {
143 // no X-FromAppId header
144 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
145 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, null, this.transactionId,
146 this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
147 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
148 assertTrue(((String) response.getEntity()).contains(ONAPLogConstants.Headers.PARTNER_NAME));
152 public void testVerifyRequestId() throws Exception {
153 // no X-FromAppId header
154 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
155 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
156 null, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
157 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
158 assertTrue(((String) response.getEntity()).contains("requestId"));
162 public void testVerifyNotificationUrl() throws Exception {
163 // no X-FromAppId header
164 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
165 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
166 this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, null);
167 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
168 assertTrue(((String) response.getEntity()).contains("notificationURL"));
172 public void testVerifyResourceIds() throws Exception {
173 // no resourceIds list
175 List<String> resourceIds = null;
176 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP,
177 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
178 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
179 assertTrue(((String) response.getEntity()).contains("resourceIds"));
182 // empty resourceId list
184 List<String> resourceIds = new ArrayList<>();
185 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP,
186 this.transactionId, this.requestId, RESOURCE_TYPE_VSERVER, resourceIds, getCallbackUrl());
187 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
188 assertTrue(((String) response.getEntity()).contains("resourceIds"));
193 public void testVerifyResourceType() throws Exception {
195 List<String> resourceIds = Arrays.asList(UUID.randomUUID().toString());
196 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
197 this.requestId, null, resourceIds, getCallbackUrl());
198 assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
199 assertTrue(((String) response.getEntity()).contains("resourceType"));
203 public void testDiscoverVserver() throws Exception {
204 String vserverId = UUID.randomUUID().toString();
206 String resourcePath = MessageFormat.format(
207 this.environment.getProperty("enricher.type.vserver.url"),
208 new Object[] { vserverId });
210 String enricherPayload = String.format("<vserver xmlns=\"http://org.onap.aai.inventory/v11\">\r\n"
211 + " <vserver-id>%s</vserver-id>\r\n"
212 + " <power-state>1</power-state>\r\n"
213 + " <locked>true</locked>\r\n"
214 + " <hostname>10.147.112.48</hostname>\r\n"
215 + " <vm-state>active</vm-state>\r\n"
216 + " <status>ACTIVE</status>\r\n"
217 + " <host-status>UNKNOWN</host-status>\r\n"
218 + " <updated>2017-11-20T04:26:13Z</updated>\r\n"
219 + " <disk-allocation-gb>.010</disk-allocation-gb>\r\n"
220 + " <memory-usage-mb>null</memory-usage-mb>\r\n"
221 + " <cpu-util-percent>.043</cpu-util-percent>\r\n"
222 + " <retrieval-timestamp>2018-06-27 19:41:49 +0000</retrieval-timestamp>\r\n"
226 this.enricherRule.stubFor(get(resourcePath).willReturn(okTextXml(enricherPayload)));
228 this.callbackRule.stubFor(post(CALLBACK_PATH).willReturn(ok("Acknowledged")));
230 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, null, this.requestId,
231 RESOURCE_TYPE_VSERVER, Arrays.asList(vserverId), getCallbackUrl());
233 assertEquals(Status.OK.getStatusCode(), response.getStatus());
234 NetworkDiscoveryResponse entity = (NetworkDiscoveryResponse) response.getEntity();
235 assertEquals(requestId, entity.getRequestId());
236 assertEquals(Status.ACCEPTED.getStatusCode(), entity.getCode().intValue());
237 assertEquals(Boolean.FALSE, entity.getAckFinalIndicator());
239 List<ServeEvent> events = waitForRequests(this.callbackRule, 1, 10);
240 LoggedRequest notificationRequest = events.get(0).getRequest();
241 assertEquals(AUTH, notificationRequest.getHeader(HttpHeaders.AUTHORIZATION));
242 String notificationJson = notificationRequest.getBodyAsString();
244 ObjectMapper mapper = new ObjectMapper();
245 AnnotationIntrospector introspector = new JaxbAnnotationIntrospector(TypeFactory.defaultInstance());
246 mapper.setAnnotationIntrospector(introspector);
247 NetworkDiscoveryNotification notification = mapper.readValue(notificationJson,
248 NetworkDiscoveryNotification.class);
250 assertEquals(requestId, notification.getRequestId());
251 assertEquals(Status.OK.getStatusCode(), notification.getCode().intValue());
252 assertEquals(Boolean.TRUE, notification.getAckFinalIndicator());
254 assertEquals(1, notification.getResources().size());
255 Resource vserver = notification.getResources().get(0);
256 assertEquals(vserverId, vserver.getId());
257 assertEquals("vserver", vserver.getType());
258 assertEquals(DataQuality.Status.ok, vserver.getDataQuality().getStatus());
260 verifyAttribute(vserver.getAttributeList(), "status", "ACTIVE");
261 verifyAttribute(vserver.getAttributeList(), "inMaintenance", "true");
262 verifyAttribute(vserver.getAttributeList(), "hostName", "10.147.112.48");
263 verifyAttribute(vserver.getAttributeList(), "vmState", "active");
267 * Verify API returns a final response indicating no discovery possible.
270 public void testUnsupportedResourceType() throws Exception {
272 String resourceType = "unsupported";
273 List<String> resourceIds = Arrays.asList("dummyId");
274 Response response = this.service.findbyResourceIdAndType(this.httpRequest, V1, AUTH, APP, this.transactionId,
275 this.requestId, resourceType, resourceIds, getCallbackUrl());
276 assertEquals(Status.OK.getStatusCode(), response.getStatus());
278 NetworkDiscoveryResponse entity = (NetworkDiscoveryResponse) response.getEntity();
279 assertEquals(Boolean.TRUE, entity.getAckFinalIndicator());
280 assertEquals(Status.NO_CONTENT.getStatusCode(), entity.getCode().intValue());
283 private void verifyAttribute(List<Attribute> attributeList, String attrName, String attrValue) {
284 for (Attribute attr : attributeList) {
285 if (attr.getName().equals(attrName)) {
286 assertEquals("Unexpected value for attribute " + attrName, attrValue, attr.getValue());
290 fail("Attribute " + attrName + " not found");
293 private List<ServeEvent> waitForRequests(WireMockRule service, int minRequests, long timeoutSeconds)
294 throws InterruptedException {
296 long remaining = timeoutSeconds * 1000L;
297 long retryInterval = Math.min(remaining / 5, 1000);
299 List<ServeEvent> events = service.getAllServeEvents();
300 if (events.size() >= minRequests) {
303 if (remaining <= 0) {
304 fail("Timeout waiting for " + minRequests + " requests");
306 Thread.sleep(retryInterval);
307 remaining -= retryInterval;
311 private String getCallbackUrl() {
312 return "http://localhost:" + this.callbackRule.port() + CALLBACK_PATH;