2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017-2018 Amdocs
7 * ================================================================================
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.
19 * ============LICENSE_END=========================================================
22 package org.onap.aai.sparky.viewandinspect.services;
24 import static org.junit.Assert.assertEquals;
25 import static org.junit.Assert.assertNotNull;
27 import java.io.InputStream;
28 import java.security.SecureRandom;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.List;
33 import java.util.concurrent.ExecutorService;
35 import javax.inject.Inject;
37 import org.eclipse.persistence.jaxb.JAXBContextProperties;
38 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
39 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
40 import org.hamcrest.Matcher;
41 import org.junit.Before;
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 import org.mockito.ArgumentMatcher;
45 import org.mockito.Matchers;
46 import org.mockito.Mockito;
47 import org.onap.aai.cl.api.Logger;
48 import org.onap.aai.cl.eelf.LoggerFactory;
49 import org.onap.aai.cl.mdc.MdcContext;
50 import org.onap.aai.restclient.client.OperationResult;
51 import org.onap.aai.sparky.config.oxm.OxmEntityLookup;
52 import org.onap.aai.sparky.dal.ActiveInventoryAdapter;
53 import org.onap.aai.sparky.dal.rest.config.RestEndpointConfig;
54 import org.onap.aai.sparky.sync.entity.SearchableEntity;
55 import org.onap.aai.sparky.util.NodeUtils;
56 import org.onap.aai.sparky.util.StringCollectionContainsMatcher;
57 import org.onap.aai.sparky.util.TestResourceLoader;
58 import org.onap.aai.sparky.viewandinspect.config.VisualizationConfigs;
59 import org.onap.aai.sparky.viewandinspect.context.BaseVisualizationContext;
60 import org.onap.aai.sparky.viewandinspect.entity.ActiveInventoryNode;
61 import org.onap.aai.sparky.viewandinspect.entity.QueryParams;
62 import org.onap.aai.sparky.viewandinspect.enumeration.NodeProcessingState;
63 import org.springframework.test.context.ContextConfiguration;
64 import org.springframework.test.context.TestPropertySource;
65 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
69 @RunWith(SpringJUnit4ClassRunner.class)
70 @TestPropertySource(properties = {
71 "schemaIngestPropLoc = src/test/resources/oxm-reader/schema-ingest-single-oxm.properties" })
72 @ContextConfiguration(locations = { "classpath:oxm-reader/oxm-reader-bean.xml" })
75 public class BaseVisualizationContextTest {
77 private static SecureRandom secureRandom = new SecureRandom();
78 private static Logger LOG =
79 LoggerFactory.getInstance().getLogger(BaseVisualizationContextTest.class);
81 private BaseVisualizationContext baseVisualizationContext;
82 private ExecutorService aaiExecutorService;
83 private VisualizationConfigs visualizationConfig;
85 private ActiveInventoryAdapter aaiAdapter;
86 private RestEndpointConfig aaiRestEndPointConfig;
89 private OxmEntityLookup oxmEntityLookup;
92 public void init() throws Exception {
94 aaiExecutorService = NodeUtils.createNamedExecutor("SLNC-WORKER", 5, LOG);
95 visualizationConfig = new VisualizationConfigs();
97 ArrayList<String> shallowEntities = new ArrayList<String>();
98 shallowEntities.add("cloud-region");
100 visualizationConfig.setShallowEntities(shallowEntities);
101 visualizationConfig.setMaxSelfLinkTraversalDepth(2);
104 aaiAdapter = Mockito.mock(ActiveInventoryAdapter.class);
106 aaiRestEndPointConfig = new RestEndpointConfig();
107 aaiRestEndPointConfig.setNumRequestRetries(5);
109 Mockito.when(aaiAdapter.getEndpointConfig()).thenReturn(aaiRestEndPointConfig);
111 MdcContext.initialize("" + secureRandom.nextLong(), "AAI-UI", "", "partner-name",
114 // all our resources are prefixed already, so the repairSelfLink shouldn't do anything to the link
115 Mockito.when(aaiAdapter.repairSelfLink(Matchers.contains(""))).thenReturn("");
120 private ArgumentMatcher<List<String>> listContainsValue(String expectedValue) {
121 return new StringCollectionContainsMatcher(expectedValue);
125 public void validateBasicConstruction() throws Exception {
127 long contextId = secureRandom.nextLong();
129 baseVisualizationContext = new BaseVisualizationContext(contextId, aaiAdapter,
130 aaiExecutorService, visualizationConfig, oxmEntityLookup);
132 assertEquals(contextId, baseVisualizationContext.getContextId());
137 public void validateSmallGraphAssembly() throws Exception {
140 * We have a tiny graph that we will validate assembly of:
142 * <li>customer -> tenant
143 * <li>customer -> service-subscription
144 * <li>service-subscription -> service-instance-1
145 * <li>service-subscription -> service-instance-2
147 * At the end of this success path, we should have 5 nodes in the node cache. Once we have this
148 * flow we can experiment with error paths involving resource download failures to ensure graph
149 * nodes are in the correct state and that expected nodes are successfully represented in the
153 long contextId = secureRandom.nextLong();
155 baseVisualizationContext = new BaseVisualizationContext(contextId, aaiAdapter,
156 aaiExecutorService, visualizationConfig, oxmEntityLookup);
158 SearchableEntity searchableEntity = new SearchableEntity();
159 String customerSelfLink =
160 "https://server.proxy:8443/aai/v11/business/customers/customer/customer-4";
161 String customerNodeId = NodeUtils.generateUniqueShaDigest(customerSelfLink);
163 searchableEntity.setId(customerNodeId);
164 searchableEntity.setEntityType("customer");
165 searchableEntity.setEntityPrimaryKeyValue("customer-4");
166 searchableEntity.setLink(customerSelfLink);
168 QueryParams queryParams = new QueryParams();
169 queryParams.setSearchTargetNodeId(customerNodeId);
170 queryParams.setSearchTargetPrimaryKeyValues("customer-4");
172 // aai customer resource dip
175 .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("customer-4"),
176 Mockito.anyString(), Mockito.anyInt(),Mockito.anyString()))
177 .thenReturn(new OperationResult(200, TestResourceLoader
178 .getTestResourceDataJson("/sync/aai/aai-resources/customer/customer-4.json")));
180 // aai tenant resource dip
183 .when(aaiAdapter.queryActiveInventoryWithRetries(Matchers.contains("tenant/tenant-1"),
184 Mockito.anyString(), Mockito.anyInt(),Mockito.anyString()))
185 .thenReturn(new OperationResult(200, TestResourceLoader
186 .getTestResourceDataJson("/sync/aai/aai-resources/tenant/tenant-1.json")));
188 // generic-queries for service-subscription
191 .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-subscription"),
193 listContainsValue("service-subscription.service-type:service-subscription-2"))))
195 "https://server.proxy:8443/aai/v11/search/generic-query/service-subscription-2");
198 .when(aaiAdapter.queryActiveInventoryWithRetries(
199 Matchers.contains("generic-query/service-subscription-2"), Mockito.anyString(),
200 Mockito.anyInt(),Mockito.anyString()))
201 .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
202 "/sync/aai/aai-traversal/generic-query/service-subscription/service-subscription-2.json")));
204 // generic-queries for service-instance-1
207 .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
208 Matchers.argThat(listContainsValue("service-instance-id:service-instance-54"))))
210 "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-id/service-instance-54");
213 .when(aaiAdapter.queryActiveInventoryWithRetries(
214 Matchers.contains("generic-query/service-instance-id/service-instance-54"),
215 Mockito.anyString(), Mockito.anyInt(),Mockito.anyString()))
216 .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
217 "/sync/aai/aai-traversal/generic-query/service-instance/service-instance-54.json")));
219 // generic-queries for service-instance-2
222 .when(aaiAdapter.getGenericQueryForSelfLink(Matchers.contains("service-instance"),
223 Matchers.argThat(listContainsValue("service-instance-id:service-instance-55"))))
225 "https://server.proxy:8443/aai/v11/search/generic-query/service-instance-id/service-instance-55");
228 .when(aaiAdapter.queryActiveInventoryWithRetries(
229 Matchers.contains("generic-query/service-instance-id/service-instance-55"),
230 Mockito.anyString(), Mockito.anyInt(),Mockito.anyString()))
231 .thenReturn(new OperationResult(200, TestResourceLoader.getTestResourceDataJson(
232 "/sync/aai/aai-traversal/generic-query/service-instance/service-instance-55.json")));
238 baseVisualizationContext.processSelfLinks(searchableEntity, queryParams);
241 * validation can be in the form of validating nodes + relationships from the node cache
242 * baseVisualizationContext.getNodeCache();
245 Map<String, ActiveInventoryNode> nodeCache = baseVisualizationContext.getNodeCache();
247 assertEquals(5, nodeCache.size());
248 assertNotNull(nodeCache.get(customerNodeId));
249 assertEquals("customer", nodeCache.get(customerNodeId).getEntityType());
251 // verify node collection nodes
253 ActiveInventoryNode customerNode =
254 nodeCache.get("da4101ad19b3c380a1c12ffeda8ab390e1489fb4a22a392c9a1939db63c3dec5");
255 ActiveInventoryNode ssNode =
256 nodeCache.get("f4ceaf19459993c4fc9438a7579dd20d786109f4455e38682c579045b7ae615e");
257 ActiveInventoryNode tenantNode =
258 nodeCache.get("4735439b29e446b339535668238076e4b392eaa3eec218936e12f735179bc55e");
259 ActiveInventoryNode s1 =
260 nodeCache.get("f975ab453b142197af5d0173e0a9cf2aa22d10502f8ad655c8d17de81b066e8f");
261 ActiveInventoryNode s2 =
262 nodeCache.get("de77ef8f76dd6f19662b163527ff839891b9596cac655e3143fdd7ad39e2e4e3");
264 assertNotNull(customerNode);
265 assertNotNull(ssNode);
266 assertNotNull(tenantNode);
270 // verify node depths
272 assertEquals(0, customerNode.getNodeDepth());
273 assertEquals(1, ssNode.getNodeDepth());
276 * I think there is a bug in the way the node depth is represented due to the enforcement of
277 * bidirectional links being disabled. We may have to circle back to this behavior at some point
278 * and re-verify that the behavior works properly.
281 assertEquals(2, tenantNode.getNodeDepth());
282 assertEquals(2, s1.getNodeDepth());
283 assertEquals(2, s2.getNodeDepth());
285 // verify node states
287 assertEquals(NodeProcessingState.READY, customerNode.getState());
288 assertEquals(NodeProcessingState.READY, ssNode.getState());
291 * these nodes have a NEIGHBORS_UNPROCESSED state because the max traversal depth was hit before
292 * processing all the nested relationships. I think what we should look at is advancing the
293 * state to READY if in fact there are no relationships to process, which I think could be the
296 assertEquals(NodeProcessingState.NEIGHBORS_UNPROCESSED, tenantNode.getState());
297 assertEquals(NodeProcessingState.NEIGHBORS_UNPROCESSED, s1.getState());
298 assertEquals(NodeProcessingState.NEIGHBORS_UNPROCESSED, s2.getState());
302 protected DynamicJAXBContext createVersionedOxm() {
303 Map<String, Object> properties = new HashMap<>();
304 ClassLoader classLoader = null;
305 InputStream iStream = classLoader.getResourceAsStream("example/resources/eclipselink/eclipselink-oxm.xml");
307 properties.put(JAXBContextProperties.OXM_METADATA_SOURCE, iStream);
309 return DynamicJAXBContextFactory.createContextFromOXM(this.getClass().getClassLoader(), properties);
310 } catch (Exception e) {