Fix some security vulnerabilities
[vfc/nfvo/driver/vnfm/svnfm.git] / nokiav2 / driver / src / test / java / org / onap / vfc / nfvo / driver / vnfm / svnfm / nokia / vnfm / notification / TestLifecycleChangeNotificationManager.java
1 /*
2  * Copyright 2016-2017, Nokia Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.notification;
17
18 import com.google.gson.*;
19 import com.nokia.cbam.lcm.v32.model.*;
20 import org.junit.Before;
21 import org.junit.Test;
22 import org.mockito.ArgumentCaptor;
23 import org.mockito.InjectMocks;
24 import org.mockito.Mockito;
25 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.LifecycleManager;
26 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.TestBase;
27 import org.threeten.bp.OffsetDateTime;
28
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.NoSuchElementException;
32 import java.util.Optional;
33 import java.util.concurrent.*;
34
35 import static com.nokia.cbam.lcm.v32.model.OperationType.*;
36 import static junit.framework.TestCase.*;
37 import static org.mockito.Mockito.*;
38 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.CbamRestApiProvider.NOKIA_LCM_API_VERSION;
39 import static org.springframework.test.util.ReflectionTestUtils.setField;
40
41 public class TestLifecycleChangeNotificationManager extends TestBase {
42
43     @InjectMocks
44     private LifecycleChangeNotificationManager lifecycleChangeNotificationManager;
45     private VnfLifecycleChangeNotification recievedLcn = new VnfLifecycleChangeNotification();
46     private List<OperationExecution> operationExecutions = new ArrayList<>();
47     private OperationExecution instantiationOperation = new OperationExecution();
48     private OperationExecution scaleOperation = new OperationExecution();
49     private OperationExecution healOperation = new OperationExecution();
50     private OperationExecution terminationOperation = new OperationExecution();
51
52     private ArgumentCaptor<OperationExecution> currentOperationExecution = ArgumentCaptor.forClass(OperationExecution.class);
53     private ArgumentCaptor<Optional> affectedConnectionPoints = ArgumentCaptor.forClass(Optional.class);
54
55     private List<VnfInfo> vnfs = new ArrayList<>();
56     private VnfInfo vnf = new VnfInfo();
57
58     @Before
59     public void initMocks() throws Exception {
60         setField(LifecycleChangeNotificationManager.class, "logger", logger);
61         instantiationOperation.setId("instantiationOperationExecutionId");
62         instantiationOperation.setStartTime(OffsetDateTime.now());
63         instantiationOperation.setOperationType(OperationType.INSTANTIATE);
64         scaleOperation.setId("scaleOperationExecutionId");
65         scaleOperation.setStartTime(OffsetDateTime.now().plusDays(1));
66         scaleOperation.setOperationType(OperationType.SCALE);
67         terminationOperation.setId("terminationExecutionId");
68         terminationOperation.setStartTime(OffsetDateTime.now().plusDays(1));
69         terminationOperation.setOperationType(OperationType.TERMINATE);
70         healOperation.setId("healOperaitonExecutionId");
71         healOperation.setOperationType(OperationType.HEAL);
72         recievedLcn.setLifecycleOperationOccurrenceId("instantiationOperationExecutionId");
73         healOperation.setStartTime(OffsetDateTime.now().plusDays(1));
74         recievedLcn.setVnfInstanceId(VNF_ID);
75         when(vnfApi.vnfsVnfInstanceIdOperationExecutionsGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationExecutions));
76         prepOperation(instantiationOperation);
77         prepOperation(scaleOperation);
78         prepOperation(healOperation);
79         prepOperation(terminationOperation);
80         doNothing().when(notificationSender).processNotification(eq(recievedLcn), currentOperationExecution.capture(), affectedConnectionPoints.capture(), eq(VIM_ID));
81         InstantiateVnfRequest instantiateVnfRequest = new InstantiateVnfRequest();
82         VimInfo vimInfo = new VimInfo();
83         vimInfo.setId(VIM_ID);
84         instantiateVnfRequest.getVims().add(vimInfo);
85         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(instantiationOperation.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(new Gson().toJsonTree(instantiateVnfRequest)));
86         when(vnfApi.vnfsGet(NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(vnfs));
87         vnfs.add(vnf);
88         vnf.setId(VNF_ID);
89         VnfProperty prop = new VnfProperty();
90         prop.setName(LifecycleManager.EXTERNAL_VNFM_ID);
91         prop.setValue(VNFM_ID);
92         vnf.setExtensions(new ArrayList<>());
93         vnf.getExtensions().add(prop);
94         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(vnf));
95     }
96
97     private void prepOperation(OperationExecution operationExecution) {
98         addEmptyModifiedConnectionPoints(operationExecution);
99         JsonElement root = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + JOB_ID + "\"}}");
100         operationExecution.setOperationParams(root);
101         switch (operationExecution.getOperationType()) {
102             case TERMINATE:
103                 root.getAsJsonObject().addProperty("terminationType", "GRACEFULL");
104         }
105         when(operationExecutionApi.operationExecutionsOperationExecutionIdGet(operationExecution.getId(), NOKIA_LCM_API_VERSION)).thenReturn(buildObservable(operationExecution));
106         operationExecutions.add(operationExecution);
107     }
108
109     private void addEmptyModifiedConnectionPoints(OperationExecution operationExecution) {
110         OperationResult operationResult = new OperationResult();
111         operationResult.operationResult = new ReportedAffectedConnectionPoints();
112         JsonElement additionalData = new Gson().toJsonTree(operationResult);
113         operationExecution.setAdditionalData(additionalData);
114     }
115
116     /**
117      * The first instantiation before the current operation is selected
118      */
119     @Test
120     public void testLastInstantiationSelection() {
121         List<OperationExecution> operations = new ArrayList<>();
122
123         OperationExecution operation = buildOperation(OffsetDateTime.now(), TERMINATE);
124         OperationExecution operationScale = buildOperation(OffsetDateTime.now().minusDays(1), SCALE);
125         OperationExecution operationClosestInstantiate = buildOperation(OffsetDateTime.now().minusDays(2), INSTANTIATE);
126         OperationExecution operationFurthers = buildOperation(OffsetDateTime.now().minusDays(3), INSTANTIATE);
127
128         operations.add(operation);
129         operations.add(operationScale);
130         operations.add(operationClosestInstantiate);
131         operations.add(operationFurthers);
132         assertEquals(operationClosestInstantiate, LifecycleChangeNotificationManager.findLastInstantiationBefore(operations, operation));
133     }
134
135     /**
136      * The instantiation operation itself is valid as the last instantiation operation
137      */
138     @Test
139     public void testInstantiationSufficesTheLastInstantiation() {
140         OffsetDateTime baseTime = OffsetDateTime.now();
141         List<OperationExecution> operations = new ArrayList<>();
142
143         OperationExecution operation = buildOperation(OffsetDateTime.now(), INSTANTIATE);
144         OperationExecution operationScale = buildOperation(OffsetDateTime.now().minusDays(1), SCALE);
145         OperationExecution operationFurthers = buildOperation(OffsetDateTime.now().minusDays(2), INSTANTIATE);
146
147         operations.add(operation);
148         operations.add(operationScale);
149         operations.add(operationFurthers);
150         assertEquals(operation, LifecycleChangeNotificationManager.findLastInstantiationBefore(operations, operation));
151     }
152
153     /**
154      * If no instantiation operation is found for before the selected operation
155      */
156     @Test
157     public void testNoInstantiation() {
158         OffsetDateTime baseTime = OffsetDateTime.now();
159         List<OperationExecution> operations = new ArrayList<>();
160
161         OperationExecution operation = buildOperation(OffsetDateTime.now(), TERMINATE);
162         OperationExecution operationScale = buildOperation(OffsetDateTime.now().minusDays(1), SCALE);
163
164         operations.add(operation);
165         operations.add(operationScale);
166         try {
167             LifecycleChangeNotificationManager.findLastInstantiationBefore(operations, operation);
168             fail();
169         } catch (NoSuchElementException e) {
170
171         }
172     }
173
174     /**
175      * the operations are ordered from newest (first) to oldest (last)
176      */
177     @Test
178     public void testOperationOrdering() {
179         List<OperationExecution> operationExecutions = new ArrayList<>();
180         OperationExecution before = buildOperation(OffsetDateTime.now(), OperationType.INSTANTIATE);
181         operationExecutions.add(before);
182         OperationExecution after = buildOperation(OffsetDateTime.now().plusDays(1), OperationType.SCALE);
183         operationExecutions.add(after);
184         List<OperationExecution> sorted1 = LifecycleChangeNotificationManager.NEWEST_OPERATIONS_FIRST.sortedCopy(operationExecutions);
185         assertEquals(after, sorted1.get(0));
186         assertEquals(before, sorted1.get(1));
187     }
188
189     /**
190      * if VNF listing fails the processing of the notifications is aborted
191      */
192     @Test
193     public void testUnableToListVnfs() throws Exception {
194         RuntimeException expectedException = new RuntimeException();
195         when(vnfApi.vnfsGet(NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
196         //when
197         try {
198             lifecycleChangeNotificationManager.handleLcn(recievedLcn);
199             fail();
200         } catch (Exception e) {
201             assertEquals(expectedException, e.getCause());
202             verify(logger).error("Unable to list VNFs / query VNF", expectedException);
203         }
204     }
205
206     /**
207      * if VNF query fails the processing of the notifications is aborted
208      */
209     @Test
210     public void testUnableToQueryVnf() throws Exception {
211         RuntimeException expectedException = new RuntimeException();
212         when(vnfApi.vnfsVnfInstanceIdGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
213         //when
214         try {
215             lifecycleChangeNotificationManager.handleLcn(recievedLcn);
216             fail();
217         } catch (Exception e) {
218             assertEquals(expectedException, e.getCause());
219             verify(logger).error("Unable to list VNFs / query VNF", expectedException);
220         }
221     }
222
223     /**
224      * if the VNF is not managed by this VNFM the LCN is dropped
225      */
226     @Test
227     public void testNonManagedVnf() throws Exception {
228         vnf.getExtensions().clear();
229         //when
230         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
231         //verify
232         Mockito.verifyZeroInteractions(operationExecutionApi);
233         verify(logger).warn("The VNF with " + VNF_ID + " identifier is not a managed VNF");
234     }
235
236     /**
237      * LCN is not logged in case of non info log level
238      */
239     @Test
240     public void testNoLogging() throws Exception {
241         vnf.getExtensions().clear();
242         when(logger.isInfoEnabled()).thenReturn(false);
243         //when
244         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
245         //verify
246         verify(logger, never()).info(eq("Received LCN: {}"), anyString());
247     }
248
249     /**
250      * if the VNF is not managed by this VNFM the LCN is dropped
251      */
252     @Test
253     public void testManagedByOtherVnf() throws Exception {
254         vnf.getExtensions().get(0).setValue("unknownVnfmId");
255         //when
256         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
257         //verify
258         Mockito.verifyZeroInteractions(operationExecutionApi);
259         verify(logger).warn("The VNF with " + VNF_ID + " identifier is not a managed by the VNFM with id unknownVnfmId");
260     }
261
262     /**
263      * if the VNF disappeared before processing the LCN
264      */
265     @Test
266     public void testDisappearedVnf() throws Exception {
267         vnfs.clear();
268         //when
269         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
270         //verify
271         Mockito.verifyZeroInteractions(operationExecutionApi);
272         verify(logger).warn("The VNF with " + VNF_ID + " identifier disappeared before being able to process the LCN");
273     }
274
275     /**
276      * if the operation parameters of the last instantiation is non querieable error is propagated
277      */
278     @Test
279     public void testUnableToQueryOperationParams() throws Exception {
280         recievedLcn.setOperation(OperationType.TERMINATE);
281         recievedLcn.setStatus(OperationStatus.FINISHED);
282         RuntimeException expectedException = new RuntimeException();
283         when(operationExecutionApi.operationExecutionsOperationExecutionIdOperationParamsGet(instantiationOperation.getId(), NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
284         //when
285         try {
286             lifecycleChangeNotificationManager.handleLcn(recievedLcn);
287             fail();
288         } catch (Exception e) {
289             //verify
290             Mockito.verifyZeroInteractions(nsLcmApi);
291             assertEquals(expectedException, e.getCause());
292             verify(logger).error("Unable to detect last instantiation operation", e.getCause());
293         }
294     }
295
296     /**
297      * if unable to send LCN to VF-C the error is propagated
298      */
299     @Test
300     public void testUnableToQueryCurrentOperation() throws Exception {
301         recievedLcn.setOperation(OperationType.TERMINATE);
302         recievedLcn.setStatus(OperationStatus.FINISHED);
303         RuntimeException expectedException = new RuntimeException();
304         when(vnfApi.vnfsVnfInstanceIdOperationExecutionsGet(VNF_ID, NOKIA_LCM_API_VERSION)).thenThrow(expectedException);
305         //when
306         try {
307             lifecycleChangeNotificationManager.handleLcn(recievedLcn);
308             fail();
309         } catch (Exception e) {
310             //verify
311             assertEquals(expectedException, e.getCause());
312             verify(logger).error("Unable to retrieve the operation executions for the VNF myVnfId", e.getCause());
313         }
314     }
315
316     /**
317      * test that waitForTerminationToBeProcessed outwaits the successfull processing of the termination notification
318      */
319     @Test
320     public void testWaitForTermination() throws Exception {
321         //given
322         //add an non processed notification
323         VnfLifecycleChangeNotification nonProcessedEvent = new VnfLifecycleChangeNotification();
324         nonProcessedEvent.setStatus(OperationStatus.FINISHED);
325         nonProcessedEvent.setOperation(OperationType.TERMINATE);
326         OperationExecution secondTerminationOperationExecution = new OperationExecution();
327         secondTerminationOperationExecution.setOperationType(OperationType.TERMINATE);
328         secondTerminationOperationExecution.setId("secondId");
329         secondTerminationOperationExecution.setOperationParams(buildTerminationParams());
330         nonProcessedEvent.setLifecycleOperationOccurrenceId(secondTerminationOperationExecution.getId());
331         lifecycleChangeNotificationManager.handleLcn(nonProcessedEvent);
332         //add second termination
333         recievedLcn.setOperation(OperationType.TERMINATE);
334         recievedLcn.setStatus(OperationStatus.FINISHED);
335         recievedLcn.setLifecycleOperationOccurrenceId(terminationOperation.getId());
336         ExecutorService executorService = Executors.newCachedThreadPool();
337         Future<Boolean> waitExitedWithSuccess = executorService.submit(new Callable<Boolean>() {
338             @Override
339             public Boolean call() throws Exception {
340                 try {
341                     lifecycleChangeNotificationManager.waitForTerminationToBeProcessed(terminationOperation.getId());
342                     return true;
343                 } catch (Exception e) {
344                     return false;
345                 }
346             }
347         });
348         //when
349         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
350         //verify
351         assertTrue(waitExitedWithSuccess.get());
352     }
353
354     /**
355      * the processing of the start notification does not trigger the deletion of the VNF
356      */
357     @Test
358     public void testStartLcnForTerminate() throws Exception {
359         recievedLcn.setOperation(OperationType.TERMINATE);
360         recievedLcn.setStatus(OperationStatus.STARTED);
361         recievedLcn.setLifecycleOperationOccurrenceId(terminationOperation.getId());
362         ExecutorService executorService = Executors.newCachedThreadPool();
363         Future<Boolean> waitExitedWithSuccess = executorService.submit(() -> {
364             try {
365                 lifecycleChangeNotificationManager.waitForTerminationToBeProcessed(terminationOperation.getId());
366                 return true;
367             } catch (Exception e) {
368                 return false;
369             }
370         });
371         //processing the start notification
372         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
373         //verify
374         try {
375             waitExitedWithSuccess.get(10, TimeUnit.MILLISECONDS);
376             fail();
377         } catch (Exception e) {
378         }
379         recievedLcn.setStatus(OperationStatus.FINISHED);
380         //when
381         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
382         //verify
383         assertTrue(waitExitedWithSuccess.get());
384     }
385
386     /**
387      * Forceful termination results in an empty affected connection points
388      */
389     @Test
390     public void testMissingPreResultForForcefullTermination() {
391         //given
392         recievedLcn.setOperation(OperationType.INSTANTIATE);
393         recievedLcn.setStatus(OperationStatus.FINISHED);
394         recievedLcn.setLifecycleOperationOccurrenceId(terminationOperation.getId());
395         JsonObject additionalData = new JsonObject();
396         additionalData.add("operationResult", new JsonObject());
397         ((JsonObject) terminationOperation.getOperationParams()).addProperty("terminationType", "FORCEFUL");
398         terminationOperation.setAdditionalData(additionalData);
399         terminationOperation.setStatus(OperationStatus.FINISHED);
400         terminationOperation.setOperationType(OperationType.TERMINATE);
401         //when
402         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
403         assertFalse(affectedConnectionPoints.getValue().isPresent());
404         verify(logger).warn("Unable to send information related to affected connection points during forceful termination");
405     }
406
407     /**
408      * Failures in affected connection point processing are tolerated for failed operation
409      * (because the POST script was not able to run)
410      */
411     @Test
412     public void testFailedOperations() throws Exception {
413         //given
414         recievedLcn.setOperation(OperationType.INSTANTIATE);
415         recievedLcn.setStatus(OperationStatus.FAILED);
416         recievedLcn.setLifecycleOperationOccurrenceId(instantiationOperation.getId());
417         instantiationOperation.setAdditionalData(null);
418         instantiationOperation.setStatus(OperationStatus.FAILED);
419         //when
420         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
421         //verify
422         assertFalse(affectedConnectionPoints.getValue().isPresent());
423         verify(logger).warn("The operation failed and the affected connection points were not reported");
424     }
425
426     /**
427      * Failures in affected connection point processing are tolerated for failed operation
428      * (because the POST script was not able to run)
429      */
430     @Test
431     public void testMissingOperationResult() throws Exception {
432         //given
433         recievedLcn.setOperation(OperationType.INSTANTIATE);
434         recievedLcn.setStatus(OperationStatus.FAILED);
435         recievedLcn.setLifecycleOperationOccurrenceId(instantiationOperation.getId());
436         instantiationOperation.setStatus(OperationStatus.FAILED);
437         JsonObject additionalData = (JsonObject) instantiationOperation.getAdditionalData();
438         additionalData.remove("operationResult");
439         //when
440         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
441         //verify
442         assertFalse(affectedConnectionPoints.getValue().isPresent());
443         verify(logger).warn("The operation failed and the affected connection points were not reported");
444     }
445
446     /**
447      * test end notification scenario for failed scale-out
448      * - LCN is sent to VF-C, but the
449      */
450     @Test
451     public void testMissingPreResultForFailedOperation() {
452         //given
453         recievedLcn.setOperation(OperationType.SCALE);
454         recievedLcn.setStatus(OperationStatus.FAILED);
455         recievedLcn.setLifecycleOperationOccurrenceId(scaleOperation.getId());
456         ScaleVnfRequest request = new ScaleVnfRequest();
457         request.setAdditionalParams(new JsonParser().parse("{ \"type\" : \"IN\", \"jobId\" : \"" + JOB_ID + "\" }"));
458         request.setType(ScaleDirection.OUT);
459         scaleOperation.setOperationParams(request);
460         scaleOperation.setAdditionalData(null);
461         scaleOperation.setStatus(OperationStatus.FAILED);
462         scaleOperation.setOperationType(OperationType.SCALE);
463         //when
464         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
465         assertFalse(affectedConnectionPoints.getValue().isPresent());
466         verify(logger).warn("The operation failed and the affected connection points were not reported");
467     }
468
469     /**
470      * if the cbam_post is missing error handling should be applied
471      */
472     @Test
473     public void testMissingPostResultForFailedOperation() {
474         //given
475         recievedLcn.setOperation(OperationType.SCALE);
476         recievedLcn.setStatus(OperationStatus.FAILED);
477         recievedLcn.setLifecycleOperationOccurrenceId(scaleOperation.getId());
478         ScaleVnfRequest request = new ScaleVnfRequest();
479         request.setAdditionalParams(new JsonParser().parse("{ \"type\" : \"IN\", \"jobId\" : \"" + JOB_ID + "\" }"));
480         request.setType(ScaleDirection.OUT);
481         scaleOperation.setOperationParams(request);
482         scaleOperation.setStatus(OperationStatus.FAILED);
483         ((JsonObject) scaleOperation.getAdditionalData()).get("operationResult").getAsJsonObject().remove("cbam_post");
484         scaleOperation.setOperationType(OperationType.SCALE);
485         //when
486         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
487         assertFalse(affectedConnectionPoints.getValue().isPresent());
488         verify(logger).warn("The operation failed and the affected connection points were not reported");
489     }
490
491     /**
492      * if invalid type is specified for cbam_post error handling should be applied
493      */
494     @Test
495     public void testInvalidPost() {
496         //given
497         recievedLcn.setOperation(OperationType.SCALE);
498         recievedLcn.setStatus(OperationStatus.FAILED);
499         recievedLcn.setLifecycleOperationOccurrenceId(scaleOperation.getId());
500         ScaleVnfRequest request = new ScaleVnfRequest();
501         request.setAdditionalParams(new JsonParser().parse("{ \"type\" : \"IN\", \"jobId\" : \"" + JOB_ID + "\" }"));
502         request.setType(ScaleDirection.OUT);
503         scaleOperation.setOperationParams(request);
504         scaleOperation.setStatus(OperationStatus.FAILED);
505         JsonObject operationResult = ((JsonObject) scaleOperation.getAdditionalData()).get("operationResult").getAsJsonObject();
506         operationResult.remove("cbam_post");
507         operationResult.addProperty("cbam_post", "");
508         scaleOperation.setOperationType(OperationType.SCALE);
509         //when
510         lifecycleChangeNotificationManager.handleLcn(recievedLcn);
511         assertFalse(affectedConnectionPoints.getValue().isPresent());
512         verify(logger).warn("The operation failed and the affected connection points were not reported");
513     }
514
515
516     /**
517      * test end notification success scenario for scale-out
518      * - LCN is sent to VF-C
519      */
520     @Test
521     public void testMissingPreResult() {
522         //given
523         recievedLcn.setOperation(OperationType.SCALE);
524         recievedLcn.setStatus(OperationStatus.FINISHED);
525         recievedLcn.setLifecycleOperationOccurrenceId(scaleOperation.getId());
526         ScaleVnfRequest request = new ScaleVnfRequest();
527         request.setAdditionalParams(new JsonParser().parse("{ \"type\" : \"IN\", \"jobId\" : \"" + JOB_ID + "\" }"));
528         request.setType(ScaleDirection.OUT);
529         scaleOperation.setOperationParams(request);
530         JsonObject additionalData = new JsonObject();
531         additionalData.add("operationResult", new JsonObject());
532         scaleOperation.setAdditionalData(additionalData);
533         scaleOperation.setStatus(OperationStatus.FINISHED);
534         scaleOperation.setOperationType(OperationType.SCALE);
535         JsonElement root = new JsonParser().parse("{ \"additionalParams\" : { \"jobId\" : \"" + JOB_ID + "\"}}");
536         JsonObject operationParams = new JsonObject();
537         //when
538         try {
539             lifecycleChangeNotificationManager.handleLcn(recievedLcn);
540             fail();
541         } catch (Exception e) {
542             assertEquals("All operations must return the { \"operationResult\" : { \"cbam_pre\" : [<fillMeOut>], \"cbam_post\" : [<fillMeOut>] } } structure", e.getMessage());
543         }
544     }
545
546     private JsonObject buildTerminationParams() {
547         JsonObject root = new JsonObject();
548         root.add("terminationType", new JsonPrimitive("GRACEFULL"));
549         return root;
550     }
551
552     private OperationExecution buildOperation(OffsetDateTime baseTime, OperationType operationType) {
553         OperationExecution operation = new OperationExecution();
554         operation.setStartTime(baseTime);
555         operation.setOperationType(operationType);
556         return operation;
557     }
558
559     class OperationResult {
560         ReportedAffectedConnectionPoints operationResult;
561     }
562
563 }