Merge "Add CDS simulator to policy-models"
[policy/models.git] / models-interactions / model-actors / actor.cds / src / test / java / org / onap / policy / controlloop / actor / cds / GrpcOperationTest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * Copyright (C) 2020 Bell Canada. All rights reserved.
4  * Modifications Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  * ============LICENSE_END=========================================================
18  */
19
20 package org.onap.policy.controlloop.actor.cds;
21
22 import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNotNull;
25 import static org.junit.Assert.assertTrue;
26 import static org.mockito.ArgumentMatchers.any;
27 import static org.mockito.ArgumentMatchers.eq;
28 import static org.mockito.Mockito.mock;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
31
32 import java.util.HashMap;
33 import java.util.Map;
34 import java.util.UUID;
35 import java.util.concurrent.CompletableFuture;
36 import java.util.concurrent.CountDownLatch;
37 import java.util.concurrent.ExecutionException;
38 import java.util.concurrent.Executor;
39 import java.util.concurrent.TimeUnit;
40 import java.util.concurrent.TimeoutException;
41 import java.util.concurrent.atomic.AtomicBoolean;
42 import org.junit.AfterClass;
43 import org.junit.Before;
44 import org.junit.BeforeClass;
45 import org.junit.Test;
46 import org.mockito.Mock;
47 import org.mockito.MockitoAnnotations;
48 import org.onap.aai.domain.yang.GenericVnf;
49 import org.onap.aai.domain.yang.ServiceInstance;
50 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
51 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput;
52 import org.onap.policy.aai.AaiCqResponse;
53 import org.onap.policy.cds.client.CdsProcessorGrpcClient;
54 import org.onap.policy.cds.properties.CdsServerProperties;
55 import org.onap.policy.common.utils.coder.Coder;
56 import org.onap.policy.common.utils.coder.CoderException;
57 import org.onap.policy.common.utils.coder.StandardCoder;
58 import org.onap.policy.common.utils.coder.StandardCoderObject;
59 import org.onap.policy.common.utils.time.PseudoExecutor;
60 import org.onap.policy.controlloop.VirtualControlLoopEvent;
61 import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation;
62 import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants;
63 import org.onap.policy.controlloop.actorserviceprovider.ActorService;
64 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
65 import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext;
66 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
67 import org.onap.policy.controlloop.policy.PolicyResult;
68 import org.onap.policy.controlloop.policy.Target;
69 import org.onap.policy.controlloop.policy.TargetType;
70 import org.onap.policy.simulators.CdsSimulator;
71 import org.onap.policy.simulators.Util;
72
73 public class GrpcOperationTest {
74     private static final String TARGET_ENTITY = "entity";
75     private static final String MY_VNF = "my-vnf";
76     private static final String MY_SVC_ID = "my-service-instance-id";
77     private static final String RESOURCE_ID = "my-resource-id";
78     private static final String CDS_BLUEPRINT_NAME = "vfw-cds";
79     private static final String CDS_BLUEPRINT_VERSION = "1.0.0";
80     private static final UUID REQUEST_ID = UUID.randomUUID();
81     private static final Coder coder = new StandardCoder();
82
83     protected static final Executor blockingExecutor = command -> {
84         Thread thread = new Thread(command);
85         thread.setDaemon(true);
86         thread.start();
87     };
88
89     private static CdsSimulator sim;
90
91     @Mock
92     private CdsProcessorGrpcClient cdsClient;
93     private CdsServerProperties cdsProps;
94     private VirtualControlLoopEvent onset;
95     private PseudoExecutor executor;
96     private Target target;
97     private GrpcOperation operation;
98
99     @BeforeClass
100     public static void setUpBeforeClass() throws Exception {
101         sim = Util.buildCdsSim();
102     }
103
104     @AfterClass
105     public static void tearDownAfterClass() {
106         sim.stop();
107     }
108
109     /**
110      * Sets up the fields.
111      */
112     @Before
113     public void setUp() throws Exception {
114         MockitoAnnotations.initMocks(this);
115
116         // Setup the CDS properties
117         cdsProps = new CdsServerProperties();
118         cdsProps.setHost("10.10.10.10");
119         cdsProps.setPort(2000);
120         cdsProps.setUsername("testUser");
121         cdsProps.setPassword("testPassword");
122         cdsProps.setTimeout(1);
123
124         // Setup cdsClient
125         when(cdsClient.sendRequest(any(ExecutionServiceInput.class))).thenReturn(mock(CountDownLatch.class));
126
127         // Setup onset event
128         onset = new VirtualControlLoopEvent();
129         onset.setRequestId(REQUEST_ID);
130
131         // Setup executor
132         executor = new PseudoExecutor();
133
134         target = new Target();
135         target.setType(TargetType.VM);
136         target.setResourceID(RESOURCE_ID);
137     }
138
139     /**
140      * Tests "success" case with simulator.
141      */
142     @Test
143     public void testSuccess() throws Exception {
144         ControlLoopEventContext context = new ControlLoopEventContext(onset);
145         loadCqData(context);
146
147         Map<String, Object> payload = Map.of("artifact_name", "my_artifact", "artifact_version", "1.0");
148
149         final ControlLoopOperationParams params = ControlLoopOperationParams.builder()
150                         .actor(CdsActorConstants.CDS_ACTOR).operation("subscribe").context(context)
151                         .actorService(new ActorService()).targetEntity(TARGET_ENTITY).target(target).retry(0)
152                         .timeoutSec(5).executor(blockingExecutor).payload(payload).build();
153
154         cdsProps.setHost("localhost");
155         cdsProps.setPort(sim.getPort());
156         cdsProps.setTimeout(3);
157
158         GrpcConfig config = new GrpcConfig(blockingExecutor, cdsProps);
159
160         operation = new GrpcOperation(params, config) {
161             @Override
162             protected CompletableFuture<OperationOutcome> startGuardAsync() {
163                 // indicate that guard completed successfully
164                 return CompletableFuture.completedFuture(params.makeOutcome());
165             }
166         };
167
168         OperationOutcome outcome = operation.start().get();
169         assertEquals(PolicyResult.SUCCESS, outcome.getResult());
170         assertTrue(outcome.getResponse() instanceof ExecutionServiceOutput);
171     }
172
173     @Test
174     public void testStartPreprocessorAsync() throws InterruptedException, ExecutionException, TimeoutException {
175
176         CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>();
177         ControlLoopEventContext context = mock(ControlLoopEventContext.class);
178         when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future2);
179         when(context.getEvent()).thenReturn(onset);
180
181         AtomicBoolean guardStarted = new AtomicBoolean();
182
183         ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR)
184                         .operation(GrpcOperation.NAME).context(context).actorService(new ActorService())
185                         .targetEntity(TARGET_ENTITY).target(target).build();
186         GrpcConfig config = new GrpcConfig(executor, cdsProps);
187
188         operation = new GrpcOperation(params, config) {
189             @Override
190             protected CompletableFuture<OperationOutcome> startGuardAsync() {
191                 guardStarted.set(true);
192                 return future2;
193             }
194         };
195
196         CompletableFuture<OperationOutcome> future3 = operation.startPreprocessorAsync();
197         assertNotNull(future3);
198         assertTrue(guardStarted.get());
199         verify(context).obtain(eq(AaiCqResponse.CONTEXT_KEY), any());
200
201         future2.complete(params.makeOutcome());
202         assertTrue(executor.runAll(100));
203         assertEquals(PolicyResult.SUCCESS, future3.get(2, TimeUnit.SECONDS).getResult());
204         assertTrue(future3.isDone());
205     }
206
207     /**
208      * Tests startPreprocessorAsync() when the target type is PNF.
209      */
210     @Test
211     public void testStartPreprocessorAsyncPnf() throws InterruptedException, ExecutionException, TimeoutException {
212
213         CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>();
214         ControlLoopEventContext context = mock(ControlLoopEventContext.class);
215         when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future2);
216         when(context.getEvent()).thenReturn(onset);
217
218         AtomicBoolean guardStarted = new AtomicBoolean();
219
220         target.setType(TargetType.PNF);
221
222         ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR)
223                         .operation(GrpcOperation.NAME).context(context).actorService(new ActorService())
224                         .targetEntity(TARGET_ENTITY).target(target).build();
225         GrpcConfig config = new GrpcConfig(executor, cdsProps);
226
227         operation = new GrpcOperation(params, config) {
228             @Override
229             protected CompletableFuture<OperationOutcome> startGuardAsync() {
230                 guardStarted.set(true);
231                 return future2;
232             }
233         };
234
235         CompletableFuture<OperationOutcome> future3 = operation.startPreprocessorAsync();
236         assertNotNull(future3);
237         assertTrue(guardStarted.get());
238         verify(context).obtain(eq(AaiGetPnfOperation.getKey(TARGET_ENTITY)), any());
239
240         future2.complete(params.makeOutcome());
241         assertTrue(executor.runAll(100));
242         assertEquals(PolicyResult.SUCCESS, future3.get(2, TimeUnit.SECONDS).getResult());
243         assertTrue(future3.isDone());
244     }
245
246     @Test
247     public void testStartOperationAsync() throws Exception {
248
249         ControlLoopEventContext context = new ControlLoopEventContext(onset);
250         loadCqData(context);
251
252         verifyOperation(context);
253     }
254
255     /**
256      * Tests startOperationAsync() when the target type is PNF.
257      */
258     @Test
259     public void testStartOperationAsyncPnf() throws Exception {
260
261         target.setType(TargetType.PNF);
262
263         ControlLoopEventContext context = new ControlLoopEventContext(onset);
264         loadPnfData(context);
265
266         verifyOperation(context);
267     }
268
269     @Test
270     public void testStartOperationAsyncWithAdditionalParams() throws Exception {
271
272         Map<String, String> additionalParams = new HashMap<>();
273         additionalParams.put("test", "additionalParams");
274         onset.setAdditionalEventParams(additionalParams);
275         ControlLoopEventContext context = new ControlLoopEventContext(onset);
276         loadCqData(context);
277         verifyOperation(context);
278     }
279
280     @Test
281     public void testStartOperationAsyncError() throws Exception {
282
283         ControlLoopEventContext context = new ControlLoopEventContext(onset);
284         ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR)
285                         .operation(GrpcOperation.NAME).context(context).actorService(new ActorService())
286                         .targetEntity(TARGET_ENTITY).target(target).build();
287
288         GrpcConfig config = new GrpcConfig(executor, cdsProps);
289         operation = new GrpcOperation(params, config);
290         assertThatIllegalArgumentException().isThrownBy(() -> operation.startOperationAsync(1, params.makeOutcome()));
291     }
292
293     private void verifyOperation(ControlLoopEventContext context) {
294
295         Map<String, Object> payloadMap = Map.of(CdsActorConstants.KEY_CBA_NAME, CDS_BLUEPRINT_NAME,
296                         CdsActorConstants.KEY_CBA_VERSION, CDS_BLUEPRINT_VERSION, "data",
297                         "{\"mapInfo\":{\"key\":\"val\"},\"arrayInfo\":[\"one\",\"two\"],\"paramInfo\":\"val\"}");
298
299         ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR)
300                         .operation(GrpcOperation.NAME).context(context).actorService(new ActorService())
301                         .targetEntity(TARGET_ENTITY).target(target).payload(payloadMap).build();
302
303         GrpcConfig config = new GrpcConfig(executor, cdsProps);
304         operation = new GrpcOperation(params, config);
305         assertEquals(1000, operation.getTimeoutMs(null));
306         assertEquals(1000, operation.getTimeoutMs(0));
307         assertEquals(2000, operation.getTimeoutMs(2));
308         operation.generateSubRequestId(1);
309         CompletableFuture<OperationOutcome> future3 = operation.startOperationAsync(1, params.makeOutcome());
310         assertNotNull(future3);
311     }
312
313     private void loadPnfData(ControlLoopEventContext context) throws CoderException {
314         String json = "{'dataA': 'valueA', 'dataB': 'valueB'}".replace('\'', '"');
315         StandardCoderObject sco = coder.decode(json, StandardCoderObject.class);
316
317         context.setProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY), sco);
318     }
319
320     private void loadCqData(ControlLoopEventContext context) {
321         GenericVnf genvnf = new GenericVnf();
322         genvnf.setVnfId(MY_VNF);
323
324         ServiceInstance serviceInstance = new ServiceInstance();
325         serviceInstance.setServiceInstanceId(MY_SVC_ID);
326
327         AaiCqResponse cq = mock(AaiCqResponse.class);
328         when(cq.getGenericVnfByModelInvariantId(any())).thenReturn(genvnf);
329         when(cq.getServiceInstance()).thenReturn(serviceInstance);
330
331         context.setProperty(AaiCqResponse.CONTEXT_KEY, cq);
332     }
333 }