f8b033ca035d509f335ef070bf3b3eb45cf478ae
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.controlloop.common.rules.test;
22
23 import static org.junit.Assert.assertEquals;
24
25 import java.util.List;
26 import java.util.UUID;
27 import java.util.function.Function;
28 import java.util.function.Supplier;
29 import java.util.stream.Collectors;
30 import lombok.AccessLevel;
31 import lombok.Getter;
32
33 import org.junit.Test;
34 import org.onap.policy.appc.Request;
35 import org.onap.policy.appclcm.AppcLcmDmaapWrapper;
36 import org.onap.policy.common.utils.coder.Coder;
37 import org.onap.policy.common.utils.coder.StandardCoder;
38 import org.onap.policy.common.utils.coder.StandardCoderInstantAsMillis;
39 import org.onap.policy.controlloop.ControlLoopNotificationType;
40 import org.onap.policy.controlloop.VirtualControlLoopNotification;
41 import org.onap.policy.drools.system.PolicyController;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
43
44 /**
45  * Superclass used for rule tests.
46  */
47 public abstract class BaseRuleTest {
48     private static final String APPC_RESTART_OP = "restart";
49
50     /*
51      * Canonical Topic Names.
52      */
53     protected static final String DCAE_TOPIC = "DCAE_TOPIC";
54     protected static final String APPC_LCM_WRITE_TOPIC = "APPC-LCM-WRITE";
55     protected static final String POLICY_CL_MGT_TOPIC = "POLICY-CL-MGT";
56     protected static final String APPC_LCM_READ_TOPIC = "APPC-LCM-READ";
57     protected static final String APPC_CL_TOPIC = "APPC-CL";
58
59     /*
60      * Constants for each test case.
61      */
62
63     // service123 (i.e., multi-operation policy)
64     private static final String SERVICE123_TOSCA_COMPLIANT_POLICY = "service123/tosca-compliant-service123.json";
65     private static final String SERVICE123_ONSET = "service123/service123.onset.json";
66     private static final String SERVICE123_APPC_RESTART_FAILURE = "service123/service123.appc.restart.failure.json";
67     private static final String SERVICE123_APPC_REBUILD_FAILURE = "service123/service123.appc.rebuild.failure.json";
68     private static final String SERVICE123_APPC_MIGRATE_SUCCESS = "service123/service123.appc.migrate.success.json";
69
70     // duplicates (i.e., mutliple events in the engine at the same time)
71     private static final String DUPLICATES_TOSCA_COMPLIANT_POLICY = "duplicates/tosca-compliant-duplicates.json";
72     private static final String DUPLICATES_ONSET_1 = "duplicates/duplicates.onset.1.json";
73     private static final String DUPLICATES_ONSET_2 = "duplicates/duplicates.onset.2.json";
74     private static final String DUPLICATES_APPC_SUCCESS = "duplicates/duplicates.appc.success.json";
75
76     // VCPE
77     private static final String VCPE_TOSCA_LEGACY_POLICY = "vcpe/tosca-legacy-vcpe.json";
78     private static final String VCPE_TOSCA_COMPLIANT_POLICY = "vcpe/tosca-compliant-vcpe.json";
79     private static final String VCPE_ONSET_1 = "vcpe/vcpe.onset.1.json";
80     private static final String VCPE_ONSET_2 = "vcpe/vcpe.onset.2.json";
81     private static final String VCPE_ONSET_3 = "vcpe/vcpe.onset.3.json";
82     private static final String VCPE_APPC_SUCCESS = "vcpe/vcpe.appc.success.json";
83
84     // VDNS
85     private static final String VDNS_TOSCA_COMPLIANT_POLICY = "vdns/tosca-compliant-vdns.json";
86     private static final String VDNS_ONSET = "vdns/vdns.onset.json";
87
88     // VFW
89     private static final String VFW_TOSCA_LEGACY_POLICY = "vfw/tosca-vfw.json";
90     private static final String VFW_TOSCA_COMPLIANT_POLICY = "vfw/tosca-compliant-vfw.json";
91     private static final String VFW_TOSCA_COMPLIANT_TIME_OUT_POLICY = "vfw/tosca-compliant-timeout-vfw.json";
92     private static final String VFW_ONSET = "vfw/vfw.onset.json";
93     private static final String VFW_APPC_SUCCESS = "vfw/vfw.appc.success.json";
94     private static final String VFW_APPC_FAILURE = "vfw/vfw.appc.failure.json";
95
96     // VLB
97     private static final String VLB_TOSCA_LEGACY_POLICY = "vlb/tosca-vlb.json";
98     private static final String VLB_TOSCA_COMPLIANT_POLICY = "vlb/tosca-compliant-vlb.json";
99     private static final String VLB_ONSET = "vlb/vlb.onset.json";
100
101     /*
102      * Coders used to decode requests and responses.
103      */
104     private static final Coder APPC_LEGACY_CODER = new StandardCoderInstantAsMillis();
105     private static final Coder APPC_LCM_CODER = new StandardCoder();
106
107     // these may be overridden by junit tests
108     private static Function<String, Rules> ruleMaker = Rules::new;
109     private static Supplier<HttpClients> httpClientMaker = HttpClients::new;
110     private static Supplier<Simulators> simMaker = Simulators::new;
111     private static Supplier<Topics> topicMaker = Topics::new;
112
113     protected static Rules rules;
114     protected static HttpClients httpClients;
115     protected static Simulators simulators;
116
117     // used to inject and wait for messages
118     @Getter(AccessLevel.PROTECTED)
119     private Topics topics;
120
121     // used to wait for messages on SINK topics
122     protected Listener<VirtualControlLoopNotification> policyClMgt;
123     protected Listener<Request> appcClSink;
124     protected Listener<AppcLcmDmaapWrapper> appcLcmRead;
125
126     protected PolicyController controller;
127
128     /*
129      * Tosca Policy that was loaded.
130      */
131     protected ToscaPolicy policy;
132
133
134     /**
135      * Initializes {@link #rules}, {@link #httpClients}, and {@link #simulators}.
136      *
137      * @param controllerName the rule controller name
138      */
139     public static void initStatics(String controllerName) {
140         rules = ruleMaker.apply(controllerName);
141         httpClients = httpClientMaker.get();
142         simulators = simMaker.get();
143     }
144
145     /**
146      * Destroys {@link #httpClients}, {@link #simulators}, and {@link #rules}.
147      */
148     public static void finishStatics() {
149         httpClients.destroy();
150         simulators.destroy();
151         rules.destroy();
152     }
153
154     /**
155      * Initializes {@link #topics} and {@link #controller}.
156      */
157     public void init() {
158         topics = topicMaker.get();
159         controller = rules.getController();
160     }
161
162     /**
163      * Destroys {@link #topics} and resets the rule facts.
164      */
165     public void finish() {
166         topics.destroy();
167         rules.resetFacts();
168     }
169
170     // Service123 (i.e., Policy with multiple operations)
171
172     /**
173      * Service123 with Tosca Compliant Policy.
174      */
175     @Test
176     public void testService123Compliant() {
177         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
178         appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
179
180         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
181         policy = rules.setupPolicyFromFile(SERVICE123_TOSCA_COMPLIANT_POLICY);
182         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
183
184         // inject an ONSET event over the DCAE topic
185         topics.inject(DCAE_TOPIC, SERVICE123_ONSET);
186
187         /* Wait to acquire a LOCK and a PDP-X PERMIT */
188         waitForLockAndPermit(policy, policyClMgt);
189
190         // restart request should be sent and fail four times (i.e., because retry=3)
191         for (int count = 0; count < 4; ++count) {
192             AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> APPC_RESTART_OP.equals(req.getRpcName()));
193
194             topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_RESTART_FAILURE,
195                             appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
196         }
197
198         // rebuild request should be sent and fail once
199         AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> "rebuild".equals(req.getRpcName()));
200
201         topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_REBUILD_FAILURE,
202                         appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
203
204         // migrate request should be sent and succeed
205         appcreq = appcLcmRead.await(req -> "migrate".equals(req.getRpcName()));
206
207         topics.inject(APPC_LCM_WRITE_TOPIC, SERVICE123_APPC_MIGRATE_SUCCESS,
208                         appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
209
210         /* --- Operation Completed --- */
211
212         waitForOperationSuccess();
213
214         /* --- Transaction Completed --- */
215         waitForFinalSuccess(policy, policyClMgt);
216     }
217
218     // Duplicate events
219
220     /**
221      * This test case tests the scenario where 3 events occur and 2 of the requests refer
222      * to the same target entity while the 3rd is for another entity. The expected result
223      * is that the event with the duplicate target entity will have a final success result
224      * for one of the events, and a rejected message for the one that was unable to obtain
225      * the lock. The event that is referring to a different target entity should be able
226      * to obtain a lock since it is a different target. After processing of all events
227      * there should only be the policy and params objects left in memory.
228      */
229     @Test
230     public void testDuplicatesEvents() {
231         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
232         appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
233
234         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
235         policy = rules.setupPolicyFromFile(DUPLICATES_TOSCA_COMPLIANT_POLICY);
236         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
237
238         /*
239          * Inject ONSET events over the DCAE topic. First and last have the same target
240          * entity, but different request IDs - only one should succeed. The middle one is
241          * for a different target entity, so it should succeed.
242          */
243         topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
244         topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_2);
245         topics.inject(DCAE_TOPIC, DUPLICATES_ONSET_1, UUID.randomUUID().toString());
246
247         // one should immediately generate a FINAL failure
248         waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_FAILURE);
249
250         // should see two restarts
251         for (int count = 0; count < 2; ++count) {
252             AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> APPC_RESTART_OP.equals(req.getRpcName()));
253
254             // indicate success
255             topics.inject(APPC_LCM_WRITE_TOPIC, DUPLICATES_APPC_SUCCESS,
256                             appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
257         }
258
259         // should see two FINAL successes
260         VirtualControlLoopNotification notif1 = waitForFinalSuccess(policy, policyClMgt);
261         VirtualControlLoopNotification notif2 = waitForFinalSuccess(policy, policyClMgt);
262
263         // get the list of target names so we can ensure there's one of each
264         List<String> actual = List.of(notif1, notif2).stream().map(notif -> notif.getAai().get("generic-vnf.vnf-id"))
265                         .sorted().collect(Collectors.toList());
266
267         assertEquals(List.of("duplicate-VNF", "vCPE_Infrastructure_vGMUX_demo_app").toString(), actual.toString());
268     }
269
270     // VCPE
271
272     /**
273      * Sunny Day with Legacy Tosca Policy.
274      */
275     @Test
276     public void testVcpeSunnyDayLegacy() {
277         appcLcmSunnyDay(VCPE_TOSCA_LEGACY_POLICY, VCPE_ONSET_1, APPC_RESTART_OP);
278     }
279
280     /**
281      * Sunny Day with Tosca Compliant Policy.
282      */
283     @Test
284     public void testVcpeSunnyDayCompliant() {
285         appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, VCPE_ONSET_1, APPC_RESTART_OP);
286     }
287
288     /**
289      * An ONSET flood prevention test that injects a few ONSETs at once. It attempts to
290      * simulate the flooding behavior of the DCAE TCA microservice. TCA could blast tens
291      * or hundreds of ONSETs within sub-second intervals.
292      */
293     @Test
294     public void testVcpeOnsetFloodPrevention() {
295         appcLcmSunnyDay(VCPE_TOSCA_COMPLIANT_POLICY, List.of(VCPE_ONSET_1, VCPE_ONSET_2, VCPE_ONSET_3),
296                         APPC_RESTART_OP);
297     }
298
299     // VDNS
300
301     /**
302      * Sunny Day with Tosca Compliant Policy.
303      */
304     @Test
305     public void testVdnsSunnyDayCompliant() {
306         httpSunnyDay(VDNS_TOSCA_COMPLIANT_POLICY, VDNS_ONSET);
307     }
308
309     // VFW
310
311     /**
312      * VFW Sunny Day with Legacy Tosca Policy.
313      */
314     @Test
315     public void testVfwSunnyDayLegacy() {
316         appcLegacySunnyDay(VFW_TOSCA_LEGACY_POLICY, VFW_ONSET, "ModifyConfig");
317     }
318
319     /**
320      * VFW Sunny Day with Tosca Compliant Policy.
321      */
322     @Test
323     public void testVfwSunnyDayCompliant() {
324         appcLegacySunnyDay(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, "ModifyConfig");
325     }
326
327     /**
328      * VFW Rainy Day using legacy tosca policy (operation and final failure).
329      */
330     @Test
331     public void testVfwRainyDayLegacyFailure() {
332         appcLegacyRainyDay(VFW_TOSCA_LEGACY_POLICY, VFW_ONSET, "ModifyConfig");
333     }
334
335     /**
336      * VFW Rainy Day using compliant tosca policy (final failure).
337      */
338     @Test
339     public void testVfwRainyDayOverallTimeout() {
340         appcLegacyRainyDayNoResponse(VFW_TOSCA_COMPLIANT_TIME_OUT_POLICY, VFW_ONSET, "ModifyConfig");
341     }
342
343     /**
344      * VFW Rainy day using compliant tosca policy (final failure due to timeout).
345      */
346     @Test
347     public void testVfwRainyDayCompliantTimeout() {
348         appcLegacyRainyDayNoResponse(VFW_TOSCA_COMPLIANT_POLICY, VFW_ONSET, "ModifyConfig");
349     }
350
351     // VLB
352
353     /**
354      * Sunny Day with Legacy Tosca Policy.
355      */
356     @Test
357     public void testVlbSunnyDayLegacy() {
358         httpSunnyDay(VLB_TOSCA_LEGACY_POLICY, VLB_ONSET);
359     }
360
361     /**
362      * Sunny Day with Tosca Compliant Policy.
363      */
364     @Test
365     public void testVlbSunnyDayCompliant() {
366         httpSunnyDay(VLB_TOSCA_COMPLIANT_POLICY, VLB_ONSET);
367     }
368
369     /**
370      * Sunny day scenario for use cases that use APPC-LCM.
371      *
372      * @param policyFile file containing the ToscaPolicy to be loaded
373      * @param onsetFile file containing the ONSET to be injected
374      * @param operation expected APPC operation request
375      */
376     protected void appcLcmSunnyDay(String policyFile, String onsetFile, String operation) {
377         appcLcmSunnyDay(policyFile, List.of(onsetFile), operation);
378     }
379
380     /**
381      * Sunny day scenario for use cases that use APPC-LCM.
382      *
383      * @param policyFile file containing the ToscaPolicy to be loaded
384      * @param onsetFiles list of files containing the ONSET to be injected
385      * @param operation expected APPC operation request
386      */
387     protected void appcLcmSunnyDay(String policyFile, List<String> onsetFiles, String operation) {
388         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
389         appcLcmRead = topics.createListener(APPC_LCM_READ_TOPIC, AppcLcmDmaapWrapper.class, APPC_LCM_CODER);
390
391         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
392         policy = rules.setupPolicyFromFile(policyFile);
393         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
394
395         // inject several ONSET events over the DCAE topic
396         for (String onsetFile : onsetFiles) {
397             topics.inject(DCAE_TOPIC, onsetFile);
398         }
399
400         /* Wait to acquire a LOCK and a PDP-X PERMIT */
401         waitForLockAndPermit(policy, policyClMgt);
402
403         /*
404          * Ensure that an APPC RESTART request was sent in response to the matching ONSET
405          */
406         AppcLcmDmaapWrapper appcreq = appcLcmRead.await(req -> operation.equals(req.getRpcName()));
407
408         /*
409          * Inject a 400 APPC Response Return over the APPC topic, with appropriate
410          * subRequestId
411          */
412         topics.inject(APPC_LCM_WRITE_TOPIC, VCPE_APPC_SUCCESS,
413                         appcreq.getBody().getInput().getCommonHeader().getSubRequestId());
414
415         /* --- Operation Completed --- */
416
417         waitForOperationSuccess();
418
419         /* --- Transaction Completed --- */
420         waitForFinalSuccess(policy, policyClMgt);
421     }
422
423     /**
424      * Sunny day scenario for use cases that use Legacy APPC.
425      *
426      * @param policyFile file containing the ToscaPolicy to be loaded
427      * @param onsetFile file containing the ONSET to be injected
428      * @param operation expected APPC operation request
429      */
430     protected void appcLegacySunnyDay(String policyFile, String onsetFile, String operation) {
431         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
432         appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
433
434         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
435         policy = rules.setupPolicyFromFile(policyFile);
436         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
437
438         /* Inject an ONSET event over the DCAE topic */
439         topics.inject(DCAE_TOPIC, onsetFile);
440
441         /* Wait to acquire a LOCK and a PDP-X PERMIT */
442         waitForLockAndPermit(policy, policyClMgt);
443
444         /*
445          * Ensure that an APPC RESTART request was sent in response to the matching ONSET
446          */
447         Request appcreq = appcClSink.await(req -> operation.equals(req.getAction()));
448
449         /*
450          * Inject a 400 APPC Response Return over the APPC topic, with appropriate
451          * subRequestId
452          */
453         topics.inject(APPC_CL_TOPIC, VFW_APPC_SUCCESS, appcreq.getCommonHeader().getSubRequestId());
454
455         /* --- Operation Completed --- */
456
457         waitForOperationSuccess();
458
459         /* --- Transaction Completed --- */
460         waitForFinalSuccess(policy, policyClMgt);
461     }
462
463     /**
464      * Rainy day scenario for use cases that use Legacy APPC.
465      *
466      * @param policyFile file containing the ToscaPolicy to be loaded
467      * @param onsetFile file containing the ONSET to be injected
468      * @param operation expected APPC operation request
469      * @param checkOperation flag to determine whether or not to wait for operation timeout
470      */
471     protected void appcLegacyRainyDay(String policyFile, String onsetFile, String operation) {
472         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
473         appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
474
475         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
476         policy = rules.setupPolicyFromFile(policyFile);
477         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
478
479         /* Inject an ONSET event over the DCAE topic */
480         topics.inject(DCAE_TOPIC, onsetFile);
481
482         /* Wait to acquire a LOCK and a PDP-X PERMIT */
483         waitForLockAndPermit(policy, policyClMgt);
484
485         /*
486          * Ensure that an APPC RESTART request was sent in response to the matching ONSET
487          */
488         Request appcreq = appcClSink.await(req -> operation.equals(req.getAction()));
489
490         /*
491          * Inject a 401 APPC Response Return over the APPC topic, with appropriate
492          * subRequestId
493          */
494         topics.inject(APPC_CL_TOPIC, VFW_APPC_FAILURE, appcreq.getCommonHeader().getSubRequestId());
495
496         /* --- Operation Completed --- */
497         waitForOperationFailure();
498
499         /* --- Transaction Completed --- */
500         waitForFinalFailure(policy, policyClMgt);
501     }
502
503     /**
504      * Rainy day scenario for use cases that use Legacy APPC.
505      * Expected to fail due to timeout.
506      *
507      * @param policyFile file containing the ToscaPolicy to be loaded
508      * @param onsetFile file containing the ONSET to be injected
509      * @param operation expected APPC operation request
510      */
511     protected void appcLegacyRainyDayNoResponse(String policyFile, String onsetFile, String operation) {
512         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
513         appcClSink = topics.createListener(APPC_CL_TOPIC, Request.class, APPC_LEGACY_CODER);
514
515         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
516         policy = rules.setupPolicyFromFile(policyFile);
517         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
518
519         /* Inject an ONSET event over the DCAE topic */
520         topics.inject(DCAE_TOPIC, onsetFile);
521
522         /* Wait to acquire a LOCK and a PDP-X PERMIT */
523         waitForLockAndPermit(policy, policyClMgt);
524
525         /*
526          * Ensure that an APPC RESTART request was sent in response to the matching ONSET
527          */
528         appcClSink.await(req -> operation.equals(req.getAction()));
529
530         /*
531          * Do not inject an APPC Response.
532          */
533
534         /* --- Transaction Completed --- */
535         waitForFinalFailure(policy, policyClMgt);
536     }
537
538     /**
539      * Sunny day scenario for use cases that use an HTTP simulator.
540      *
541      * @param policyFile file containing the ToscaPolicy to be loaded
542      * @param onsetFile file containing the ONSET to be injected
543      * @param operation expected APPC operation request
544      */
545     protected void httpSunnyDay(String policyFile, String onsetFile) {
546         policyClMgt = topics.createListener(POLICY_CL_MGT_TOPIC, VirtualControlLoopNotification.class, controller);
547
548         assertEquals(0, controller.getDrools().factCount(rules.getControllerName()));
549         policy = rules.setupPolicyFromFile(policyFile);
550         assertEquals(2, controller.getDrools().factCount(rules.getControllerName()));
551
552         /* Inject an ONSET event over the DCAE topic */
553         topics.inject(DCAE_TOPIC, onsetFile);
554
555         /* Wait to acquire a LOCK and a PDP-X PERMIT */
556         waitForLockAndPermit(policy, policyClMgt);
557
558         /* --- Operation Completed --- */
559
560         waitForOperationSuccess();
561
562         /* --- Transaction Completed --- */
563         waitForFinalSuccess(policy, policyClMgt);
564     }
565
566     /**
567      * Waits for a OPERATION SUCCESS transaction notification.
568      */
569     protected void waitForOperationSuccess() {
570         policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION_SUCCESS);
571     }
572
573     /**
574      * Waits for a FINAL SUCCESS transaction notification.
575      *
576      * @return the FINAL SUCCESS notification
577      */
578     protected VirtualControlLoopNotification waitForFinalSuccess(ToscaPolicy policy,
579                     Listener<VirtualControlLoopNotification> policyClMgt) {
580
581         return this.waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_SUCCESS);
582     }
583
584     /**
585      * Waits for a OPERATION FAILURE transaction notification.
586      */
587     protected void waitForOperationFailure() {
588         policyClMgt.await(notif -> notif.getNotification() == ControlLoopNotificationType.OPERATION_FAILURE);
589     }
590
591     /**
592      * Waits for a FINAL FAILURE transaction notification.
593      *
594      * @return the FINAL FAILURE notification
595      */
596     protected VirtualControlLoopNotification waitForFinalFailure(ToscaPolicy policy,
597                     Listener<VirtualControlLoopNotification> policyClMgt) {
598
599         return this.waitForFinal(policy, policyClMgt, ControlLoopNotificationType.FINAL_FAILURE);
600     }
601
602     /**
603      * Waits for notifications for LOCK acquisition and GUARD Permit so that event
604      * processing may proceed.
605      */
606     protected abstract void waitForLockAndPermit(ToscaPolicy policy,
607                     Listener<VirtualControlLoopNotification> policyClMgt);
608
609     /**
610      * Waits for a FINAL transaction notification.
611      *
612      * @param finalType FINAL_xxx type for which to wait
613      *
614      * @return the FINAL notification
615      */
616     protected abstract VirtualControlLoopNotification waitForFinal(ToscaPolicy policy,
617                     Listener<VirtualControlLoopNotification> policyClMgt, ControlLoopNotificationType finalType);
618 }