1418e89c6ea29f19602973fcddc078c0fc499bef
[appc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * =============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.appc.transactionrecorder.impl;
25
26 import com.sun.rowset.CachedRowSetImpl;
27 import org.junit.After;
28 import org.junit.Assert;
29 import org.junit.Before;
30 import org.junit.Test;
31 import org.mockito.Mockito;
32
33 import org.onap.appc.dao.util.dbcp.DBConnectionPool;
34 import org.onap.appc.dao.util.helper.DBHelper;
35 import org.onap.appc.domainmodel.lcm.Flags;
36 import org.onap.appc.domainmodel.lcm.RequestStatus;
37 import org.onap.appc.domainmodel.lcm.TransactionRecord;
38 import org.onap.appc.domainmodel.lcm.VNFOperation;
39 import org.onap.appc.exceptions.APPCException;
40 import org.onap.appc.transactionrecorder.objects.TransactionConstants;
41 import org.onap.ccsdk.sli.core.dblib.DbLibService;
42
43 import javax.sql.rowset.CachedRowSet;
44 import java.sql.*;
45 import java.time.Instant;
46 import java.time.ZoneOffset;
47 import java.time.format.DateTimeFormatter;
48 import java.time.temporal.ChronoUnit;
49 import java.util.ArrayList;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.UUID;
54
55 import static org.mockito.Matchers.*;
56
57 /**
58  * Test class for TransactionRecorder
59  */
60 public class TransactionRecorderImplTest {
61
62     private String dbUrl = "jdbc:h2:mem:test;MODE=MYSQL;DB_CLOSE_DELAY=-1";
63     private String username = "sa";
64     private String password = "sa";
65     private String driver = "org.h2.Driver";
66
67     private TransactionRecorderImpl transactionRecorderImpl;
68     private DbLibService dbLibService;
69
70     private DBConnectionPool dbConnectionPool;
71
72
73     /**
74      * Ideally JUnit should grab the SQL to create the transaction table from the same source used in deployments;
75      * however, at the time of writing this that was not possible.  Should it become possible in the future please
76      * update this JUnit test to use the deployment source.
77      * <p>
78      * Please ensure this table create script is identical to the source script used in a deployment.
79      */
80     private String TRANSACTION_CREATE_TABLE = "CREATE TABLE TRANSACTIONS (" +
81             "  TRANSACTION_ID VARCHAR(75) NOT NULL PRIMARY KEY," +
82             "  ORIGIN_TIMESTAMP DATETIME(3) NOT NULL," +
83             "  REQUEST_ID VARCHAR(256) NOT NULL," +
84             "  SUBREQUEST_ID VARCHAR(256) DEFAULT NULL," +
85             "  ORIGINATOR_ID VARCHAR(256) DEFAULT NULL," +
86             "  START_TIME DATETIME(3) NOT NULL," +
87             "  END_TIME DATETIME(3) DEFAULT NULL," +
88             "  TARGET_ID VARCHAR(256) NOT NULL," +
89             "  TARGET_TYPE VARCHAR(256) DEFAULT NULL," +
90             "  OPERATION VARCHAR(256) NOT NULL," +
91             "  RESULT_CODE INT(11) DEFAULT NULL," +
92             "  DESCRIPTION TEXT," +
93             "  STATE VARCHAR(50) NOT NULL," +
94             "  SERVICE_INSTANCE_ID VARCHAR(256) DEFAULT NULL," +
95             "  VNFC_NAME VARCHAR(256) DEFAULT NULL," +
96             "  VSERVER_ID VARCHAR(256) DEFAULT NULL," +
97             "  VF_MODULE_ID VARCHAR(256) DEFAULT NULL," +
98             "  MODE VARCHAR(50) NOT NULL," +
99             ")";
100     private String TRANSACTION_DROP_TABLE = "DROP TABLE IF EXISTS TRANSACTIONS";
101
102     @Before
103     public void setUp() throws Exception {
104         transactionRecorderImpl = new TransactionRecorderImpl();
105         transactionRecorderImpl.setAppcInstanceId("123");
106         dbLibService = Mockito.mock(DbLibService.class);
107         transactionRecorderImpl.setDbLibService(dbLibService);
108         dbConnectionPool = new DBConnectionPool(dbUrl, username, password, driver);
109         executeUpdate(TRANSACTION_CREATE_TABLE);
110
111     }
112
113
114     @After
115     public void shutdown() {
116         if (dbConnectionPool != null) {
117             executeUpdate(TRANSACTION_DROP_TABLE);
118             dbConnectionPool.shutdown();
119         }
120     }
121
122     private void executeUpdate(String updateSQL) {
123         Connection connection = null;
124         Statement stmt = null;
125         try {
126             connection = dbConnectionPool.getConnection();
127             stmt = connection.createStatement();
128             stmt.executeUpdate(updateSQL);
129         } catch (SQLException e) {
130             throw new RuntimeException(e);
131         } finally {
132             DBHelper.close(null, stmt, connection);
133         }
134     }
135
136     /**
137      * Verify the transactionRecorderImpl.sore() store the TransactionRecord correctly in the database.
138      */
139     @Test
140     public void testStore() throws Exception {
141
142         TransactionRecord input = prepareTransactionsInput();
143         Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
144                 testStoreInMemory(invocation.getArguments()));
145         transactionRecorderImpl.store(input);
146
147     }
148
149     @Test
150     public void testGetInProgressRequests() throws SQLException, APPCException {
151         TransactionRecord record1 = prepareTransactionsInput();
152         insertRecord(record1);
153         TransactionRecord input = prepareTransactionsInput();
154         input.setStartTime(Instant.now());
155         Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
156                 inMemoryExecutionWithResultSet(invocation.getArguments()));
157         Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input,0).size());
158
159     }
160
161     @Test
162     public void testGetInProgressRequestsWithinTimeInterval() throws SQLException, APPCException {
163         TransactionRecord record1 = prepareTransactionsInput();
164         record1.setStartTime(Instant.now().minus(4,ChronoUnit.HOURS));
165         insertRecord(record1);
166         TransactionRecord input = prepareTransactionsInput();
167         input.setStartTime(Instant.now());
168         Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
169                 inMemoryExecutionWithResultSet(invocation.getArguments()));
170         List<TransactionRecord> aList= transactionRecorderImpl.getInProgressRequests(input,12);
171         Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input,12).size());
172
173     }
174
175     @Test
176     public void testIsTransactionDuplicate() throws SQLException, APPCException {
177         TransactionRecord input = prepareTransactionsInput();
178         Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
179                 inMemoryExecutionWithResultSet(invocation.getArguments()));
180         Assert.assertFalse(transactionRecorderImpl.isTransactionDuplicate(input));
181
182     }
183
184     @Test
185     public void testGetInProgressRequestsCount() throws SQLException, APPCException {
186         TransactionRecord input = prepareTransactionsInput();
187         Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
188                 inMemoryExecutionWithResultSet(invocation.getArguments()));
189         Assert.assertEquals(0, transactionRecorderImpl.getInProgressRequestsCount().intValue());
190     }
191
192     @Test
193     public void testUpdate() throws APPCException, SQLException {
194         TransactionRecord input = prepareTransactionsInput();
195         insertRecord(input);
196         Map<TransactionConstants.TRANSACTION_ATTRIBUTES, String> updateColumns = new HashMap<>();
197         updateColumns.put(TransactionConstants.TRANSACTION_ATTRIBUTES.TARGET_TYPE, "Firewall");
198         Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
199                 testUpdateInMemory(invocation.getArguments()));
200         transactionRecorderImpl.update(input.getTransactionId(), updateColumns);
201     }
202
203     @Test
204     public void testMarkTransactionsAborted() throws SQLException {
205         TransactionRecord input = prepareTransactionsInput();
206         insertRecord(input);
207         Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation ->
208                 testMarkAbortedInMemory(invocation.getArguments()));
209         transactionRecorderImpl.markTransactionsAborted("123~");
210     }
211
212     private ResultSet inMemoryExecutionWithResultSet(Object[] obj) throws Exception {
213         String query = (String) obj[0];
214         ArrayList<String> args = (ArrayList<String>) obj[1];
215         Connection con = dbConnectionPool.getConnection();
216         PreparedStatement ps = con.prepareStatement(query);
217         for (int i = 1; i <= args.size(); i++) {
218             ps.setString(i, args.get(i - 1));
219         }
220         CachedRowSet rowSet = new CachedRowSetImpl();
221         rowSet.populate(ps.executeQuery());
222         return rowSet;
223     }
224
225     private boolean testMarkAbortedInMemory(Object[] obj) throws Exception {
226         String query = (String) obj[0];
227         ArrayList<String> args = (ArrayList<String>) obj[1];
228         Connection con = dbConnectionPool.getConnection();
229         PreparedStatement ps = con.prepareStatement(query);
230         for (int i = 1; i <= args.size(); i++) {
231             ps.setString(i, args.get(i - 1));
232         }
233         ps.execute();
234         return isTransactionAborted();
235     }
236
237     private boolean isTransactionAborted() throws Exception {
238         String query = "SELECT COUNT(*) FROM  TRANSACTIONS WHERE STATE = ?";
239         Connection con = dbConnectionPool.getConnection();
240         PreparedStatement ps = con.prepareStatement(query);
241         ps.setString(1, RequestStatus.ABORTED.toString());
242         ResultSet rs = ps.executeQuery();
243         while (rs.next()) {
244             int value = rs.getInt(1);
245             if (value == 1) {
246                 System.out.println("Non terminal Transactions are aborted");
247                 return true;
248             }
249         }
250         throw new Exception("Transactions are not aborted");
251     }
252
253     private boolean testUpdateInMemory(Object[] obj) throws Exception {
254         String query = (String) obj[0];
255         ArrayList<String> args = (ArrayList<String>) obj[1];
256         Connection con = dbConnectionPool.getConnection();
257         PreparedStatement ps = con.prepareStatement(query);
258         for (int i = 1; i <= args.size(); i++) {
259             ps.setString(i, args.get(i - 1));
260         }
261         ps.execute();
262         String updatedValue = checkIfValueIsUpdated(args.get(1));
263         System.out.println("updated Value is " + updatedValue);
264         if (updatedValue.equals("Firewall")) {
265             return true;
266         }
267         throw new Exception("Not Updated");
268     }
269
270     private boolean testStoreInMemory(Object[] obj) throws Exception {
271         String query = (String) obj[0];
272         ArrayList<String> args = (ArrayList<String>) obj[1];
273         Connection con = dbConnectionPool.getConnection();
274         PreparedStatement ps = con.prepareStatement(query);
275         for (int i = 1; i <= args.size(); i++) {
276             ps.setString(i, args.get(i - 1));
277         }
278         ps.execute();
279         if (checkIfRowIsPresent(args.get(0))) {
280             return true;
281         }
282         throw new Exception("Failed to update");
283     }
284
285     private TransactionRecord prepareTransactionsInput() {
286         TransactionRecord input = new TransactionRecord();
287         input.setTransactionId(UUID.randomUUID().toString());
288         input.setOriginTimestamp(Instant.parse("2017-09-11T00:00:01.00Z"));
289         input.setRequestId("REQUEST_ID");
290         input.setSubRequestId("SUB_REQUEST_ID");
291         input.setOriginatorId("ORIGINATOR_ID");
292         input.setStartTime(Instant.parse("2017-09-11T00:00:02.00Z"));
293         input.setTargetId("TARGET_ID");
294         input.setTargetType("TARGET_TYPE");
295         input.setServiceInstanceId("SERVICE_INSTANCE_ID");
296         input.setOperation(VNFOperation.ActionStatus);
297         input.setResultCode(200);
298         input.setRequestState(RequestStatus.ACCEPTED);
299         input.setDescription("DESCRIPTION");
300         input.setMode(Flags.Mode.EXCLUSIVE);
301         return input;
302     }
303
304     private void insertRecord(TransactionRecord input) throws SQLException {
305         final String STORE_DATE_QUERY = TransactionConstants.INSERT_INTO + TransactionConstants.TRANSACTIONS +
306                 " values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
307         Connection con = dbConnectionPool.getConnection();
308         PreparedStatement ps = con.prepareStatement(STORE_DATE_QUERY);
309         ArrayList<String> args = prepareArguments(input);
310         args.remove(0);
311         args.add(0, "123~" + input.getTransactionId());
312         for (int i = 1; i <= 18; i++) {
313             ps.setString(i, args.get(i - 1));
314         }
315         ps.execute();
316         if (checkIfRowIsPresent(args.get(0))) {
317             System.out.println("RECORD INSERTED " + args.get(0));
318         }
319
320     }
321
322     private ArrayList<String> prepareArguments(TransactionRecord input) {
323         ArrayList<String> arguments = new ArrayList<>();
324         arguments.add(input.getTransactionId());
325         arguments.add(dateToStringConverterMillis(input.getOriginTimestamp()));
326         arguments.add(input.getRequestId());
327         arguments.add(input.getSubRequestId());
328         arguments.add(input.getOriginatorId());
329         arguments.add(dateToStringConverterMillis(input.getStartTime()));
330         arguments.add(dateToStringConverterMillis(input.getEndTime()));
331         arguments.add(input.getTargetId());
332         arguments.add(input.getTargetType());
333         arguments.add(input.getOperation().name());
334         arguments.add(String.valueOf(input.getResultCode()));
335         arguments.add(input.getDescription());
336         arguments.add(input.getRequestState());
337         arguments.add(input.getServiceInstanceId());
338         arguments.add(input.getVnfcName());
339         arguments.add(input.getVserverId());
340         arguments.add(input.getVfModuleId());
341         arguments.add(input.getMode());
342
343         return arguments;
344     }
345
346     private static String dateToStringConverterMillis(Instant date) {
347         if (date == null) {
348             return null;
349         }
350         DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(ZoneOffset.UTC);
351         return formatter.format(date);
352     }
353
354     private boolean checkIfRowIsPresent(String key) {
355         Connection con = null;
356         ResultSet rs = null;
357         PreparedStatement ps = null;
358         try {
359             con = dbConnectionPool.getConnection();
360             ps = con.prepareStatement("SELECT COUNT(*) FROM  TRANSACTIONS WHERE TRANSACTION_ID = ?");
361             ps.setString(1, key);
362             rs = ps.executeQuery();
363             while (rs.next()) {
364                 int value = rs.getInt(1);
365                 System.out.println("KEY checked is " + key + " COUNT RETURNED IS " + value);
366                 if (value == 1) {
367                     return true;
368                 }
369             }
370         } catch (SQLException e) {
371             e.printStackTrace();
372         } finally {
373             DBHelper.close(rs, ps, con);
374         }
375         return false;
376     }
377
378     private String checkIfValueIsUpdated(String key) throws Exception {
379         Connection con = dbConnectionPool.getConnection();
380         PreparedStatement ps = con.prepareStatement("SELECT TARGET_TYPE FROM  TRANSACTIONS WHERE TRANSACTION_ID = ?");
381         ps.setString(1, key);
382         ResultSet rs = ps.executeQuery();
383         while (rs.next()) {
384             String value = rs.getString("TARGET_TYPE");
385             return value;
386         }
387         throw new Exception("Value not found");
388     }
389
390
391     /**
392      * Verify the transactionRecorderImpl. getRecords () can be fetch with each of the parameter combinations
393      * @throws Exception
394      *//*
395     @Test
396     public void test_api_getRecords() throws Exception {
397
398
399         final int requestId = 0;
400         final int subrequestId = 1;
401         final int originatorId = 2;
402         final int vnfId = 3;
403         final int requestStatus = 4;
404
405
406         String[][] trCreateMatrix = {
407             {"request1", "subrequestId1", "originatorId1", "vnfId1", RequestStatus.UNKNOWN.name()},
408             {"request1", "subrequestId2", "originatorId1", "vnfId1", RequestStatus.RECEIVED.name()},
409             {"request2", "subrequestId1", "originatorId1", "vnfId1", RequestStatus.ACCEPTED.name()},
410             {"request2", "subrequestId2", "originatorId1", "vnfId1", RequestStatus.REJECTED.name()},
411             {"request1", "subrequestId1", "originatorId1", "vnfId2", RequestStatus.SUCCESSFUL.name()},
412             {"request1", "subrequestId2", "originatorId1", "vnfId2", RequestStatus.FAILED.name()},
413             {"request2", "subrequestId1", "originatorId1", "vnfId2", RequestStatus.TIMEOUT.name()},
414             {"request2", "subrequestId2", "originatorId1", "vnfId2", RequestStatus.ABORTED.name()},
415             {"request1", "subrequestId1", "originatorId2", "vnfId1", RequestStatus.UNKNOWN.name()},
416             {"request1", "subrequestId2", "originatorId2", "vnfId1", RequestStatus.RECEIVED.name()},
417             {"request2", "subrequestId1", "originatorId2", "vnfId1", RequestStatus.ACCEPTED.name()},
418             {"request2", "subrequestId2", "originatorId2", "vnfId1", RequestStatus.REJECTED.name()},
419             {"request1", "subrequestId1", "originatorId2", "vnfId2", RequestStatus.SUCCESSFUL.name()},
420             {"request1", "subrequestId2", "originatorId2", "vnfId2", RequestStatus.FAILED.name()},
421             {"request2", "subrequestId1", "originatorId2", "vnfId2", RequestStatus.TIMEOUT.name()},
422             {"request2", "subrequestId2", "originatorId2", "vnfId2", RequestStatus.ABORTED.name()},
423         };
424
425
426         TransactionRecord tr = new TransactionRecord();
427         tr.setTimeStamp(Instant.parse("2017-09-11T00:00:01.00Z"));
428         tr.setStartTime(Instant.parse("2017-09-11T00:00:02.00Z"));
429         tr.setEndTime(Instant.parse("2017-09-11T00:00:03.00Z"));
430         tr.setTargetType("TARGET_TYPE");
431         tr.setSubComponent("SUB_COMPONENT");
432         tr.setOperation(VNFOperation.ActionStatus);
433         tr.setResultCode("RESULT_CODE");
434         tr.setDescription("DESCRIPTION");
435
436         for (int row = 0; row < trCreateMatrix.length; row++) {
437             tr.setRequestID(trCreateMatrix[row][requestId]);
438             tr.setSubRequestID(trCreateMatrix[row][subrequestId]);
439             tr.setOriginatorId(trCreateMatrix[row][originatorId]);
440             tr.setTargetID(trCreateMatrix[row][vnfId]);
441             tr.setRequestStatus(RequestStatus.valueOf(trCreateMatrix[row][requestStatus]));
442             transactionRecorderImpl.store(tr);
443         }
444
445
446         String[][] trSearchMatrix = {
447             {"request1", null, null, "vnfId1"},
448             {"request2", "subrequestId1", null, "vnfId1"},
449             {"request1", null, "originatorId1", "vnfId1"},
450             {"request2", "subrequestId2", "originatorId1", "vnfId1"},
451         };
452
453
454         for (int i = 0; i < trSearchMatrix.length; i++) {
455             final int row = i;
456             List<RequestStatus> actualList = transactionRecorderImpl
457                 .getRecords(trSearchMatrix[row][requestId], trSearchMatrix[row][subrequestId],
458                     trSearchMatrix[row][originatorId], trSearchMatrix[row][vnfId])
459                 .stream()
460                 .sorted()
461                 .collect(Collectors.toList());
462
463             List<RequestStatus> expectedList = Arrays.stream(trCreateMatrix)
464                 .filter(entry -> entry[requestId].equals(trSearchMatrix[row][requestId]))
465                 .filter(entry -> trSearchMatrix[row][subrequestId] == null || entry[subrequestId].equals
466                     (trSearchMatrix[row][subrequestId]))
467                 .filter(entry -> trSearchMatrix[row][originatorId] == null || entry[originatorId].equals
468                     (trSearchMatrix[row][originatorId]))
469                 .filter(entry -> entry[vnfId].equals(trSearchMatrix[row][vnfId]))
470                 .map(entry -> RequestStatus.valueOf(entry[requestStatus]))
471                 .sorted()
472                 .collect(Collectors.toList());
473             System.out.println(expectedList);
474             System.out.println(actualList);
475             Assert.assertEquals("Unexpected results: ", expectedList, actualList);
476
477         }
478
479
480     }*/
481 }