/*- * ============LICENSE_START======================================================= * ONAP : APPC * ================================================================================ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Copyright (C) 2017 Amdocs * ================================================================================ * Modifications Copyright (C) 2019 Ericsson * ============================================================================= * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ============LICENSE_END========================================================= */ package org.onap.appc.transactionrecorder.impl; import com.sun.rowset.CachedRowSetImpl; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.mockito.Mockito; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; import static org.hamcrest.CoreMatchers.isA; import org.onap.appc.dao.util.dbcp.DBConnectionPool; import org.onap.appc.dao.util.helper.DBHelper; import org.onap.appc.domainmodel.lcm.Flags; import org.onap.appc.domainmodel.lcm.RequestStatus; import org.onap.appc.domainmodel.lcm.TransactionRecord; import org.onap.appc.domainmodel.lcm.VNFOperation; import org.onap.appc.exceptions.APPCException; import org.onap.appc.transactionrecorder.objects.TransactionConstants; import org.onap.appc.transactionrecorder.objects.TransactionConstants.TRANSACTION_ATTRIBUTES; import org.onap.ccsdk.sli.core.dblib.DbLibService; import javax.sql.rowset.CachedRowSet; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.time.Instant; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; /** * Test class for TransactionRecorder */ public class TransactionRecorderImplTest { private String dbUrl = "jdbc:h2:mem:test;MODE=MYSQL;DB_CLOSE_DELAY=-1"; private String username = "sa"; private String password = "sa"; private String driver = "org.h2.Driver"; private TransactionRecorderImpl transactionRecorderImpl; private DbLibService dbLibService; private DBConnectionPool dbConnectionPool; /** * Ideally JUnit should grab the SQL to create the transaction table from the same source used in deployments; * however, at the time of writing this that was not possible. Should it become possible in the future please * update this JUnit test to use the deployment source. *

* Please ensure this table create script is identical to the source script used in a deployment. */ private String TRANSACTION_CREATE_TABLE = "CREATE TABLE TRANSACTIONS (" + " TRANSACTION_ID VARCHAR(75) NOT NULL PRIMARY KEY," + " ORIGIN_TIMESTAMP DATETIME(3) NOT NULL," + " REQUEST_ID VARCHAR(256) NOT NULL," + " SUBREQUEST_ID VARCHAR(256) DEFAULT NULL," + " ORIGINATOR_ID VARCHAR(256) DEFAULT NULL," + " START_TIME DATETIME(3) NOT NULL," + " END_TIME DATETIME(3) DEFAULT NULL," + " TARGET_ID VARCHAR(256) NOT NULL," + " TARGET_TYPE VARCHAR(256) DEFAULT NULL," + " OPERATION VARCHAR(256) NOT NULL," + " RESULT_CODE INT(11) DEFAULT NULL," + " DESCRIPTION TEXT," + " STATE VARCHAR(50) NOT NULL," + " SERVICE_INSTANCE_ID VARCHAR(256) DEFAULT NULL," + " VNFC_NAME VARCHAR(256) DEFAULT NULL," + " VSERVER_ID VARCHAR(256) DEFAULT NULL," + " VF_MODULE_ID VARCHAR(256) DEFAULT NULL," + " MODE VARCHAR(50) NOT NULL," + ")"; private String TRANSACTION_DROP_TABLE = "DROP TABLE IF EXISTS TRANSACTIONS"; @Rule public ExpectedException expectedEx = ExpectedException.none(); @Before public void setUp() throws Exception { transactionRecorderImpl = new TransactionRecorderImpl(); transactionRecorderImpl.setAppcInstanceId("123"); dbLibService = Mockito.mock(DbLibService.class); transactionRecorderImpl.setDbLibService(dbLibService); dbConnectionPool = new DBConnectionPool(dbUrl, username, password, driver); executeUpdate(TRANSACTION_CREATE_TABLE); } @After public void shutdown() { if (dbConnectionPool != null) { executeUpdate(TRANSACTION_DROP_TABLE); dbConnectionPool.shutdown(); } } private void executeUpdate(String updateSQL) { Connection connection = null; Statement stmt = null; try { connection = dbConnectionPool.getConnection(); stmt = connection.createStatement(); stmt.executeUpdate(updateSQL); } catch (SQLException e) { throw new RuntimeException(e); } finally { DBHelper.close(null, stmt, connection); } } /** * Verify the transactionRecorderImpl.store() store the TransactionRecord correctly in the database. */ @Test public void testStore() throws Exception { TransactionRecord input = prepareTransactionsInput(); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> testStoreInMemory(invocation.getArguments())); transactionRecorderImpl.store(input); } @Test public void testStoreExceptionFlow() throws SQLException, APPCException { TransactionRecord input = prepareTransactionsInput(); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(APPCException.class); expectedEx.expectMessage(TransactionConstants.ERROR_ACCESSING_DATABASE); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.store(input); } @Test public void testGetInProgressRequests() throws SQLException, APPCException { TransactionRecord record1 = prepareTransactionsInput(); insertRecord(record1); TransactionRecord input = prepareTransactionsInput(); input.setStartTime(Instant.now()); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> inMemoryExecutionWithResultSet(invocation.getArguments())); Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input, 0).size()); } @Test public void testGetInProgressRequestsSqlException() throws SQLException, APPCException { TransactionRecord record1 = prepareTransactionsInput(); insertRecord(record1); TransactionRecord input = prepareTransactionsInput(); input.setStartTime(Instant.now()); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(APPCException.class); expectedEx.expectMessage(TransactionConstants.ERROR_ACCESSING_DATABASE); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.getInProgressRequests(input, 0); } @Test public void testGetInProgressRequestsWithinTimeInterval() throws SQLException, APPCException { TransactionRecord record1 = prepareTransactionsInput(); record1.setStartTime(Instant.now().minus(4, ChronoUnit.HOURS)); insertRecord(record1); TransactionRecord input = prepareTransactionsInput(); input.setStartTime(Instant.now()); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> inMemoryExecutionWithResultSet(invocation.getArguments())); List aList = transactionRecorderImpl.getInProgressRequests(input, 12); Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input, 12).size()); } @Test public void testIsTransactionDuplicate() throws SQLException, APPCException { TransactionRecord input = prepareTransactionsInput(); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> inMemoryExecutionWithResultSet(invocation.getArguments())); Assert.assertFalse(transactionRecorderImpl.isTransactionDuplicate(input)); } @Test public void testIsTransactionDuplicateExceptionFlow() throws SQLException, APPCException { TransactionRecord input = prepareTransactionsInput(); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(APPCException.class); expectedEx.expectMessage(TransactionConstants.ERROR_ACCESSING_DATABASE); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.isTransactionDuplicate(input); } @Test public void testIsTransactionDuplicateAlternativeFlow() throws SQLException, APPCException { TransactionRecord input = prepareTransactionsInput(); input.setSubRequestId(null); input.setOriginatorId(null); CachedRowSetImpl rowset = Mockito.mock(CachedRowSetImpl.class); Mockito.when(rowset.first()).thenReturn(true); Mockito.when(rowset.getString(TransactionConstants.TRANSACTION_ATTRIBUTES.TRANSACTION_ID.getColumnName())) .thenReturn(null); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenReturn(rowset); Assert.assertTrue(transactionRecorderImpl.isTransactionDuplicate(input)); } @Test public void testGetInProgressRequestsCount() throws SQLException, APPCException { TransactionRecord input = prepareTransactionsInput(); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> inMemoryExecutionWithResultSet(invocation.getArguments())); Assert.assertEquals(0, transactionRecorderImpl.getInProgressRequestsCount().intValue()); } @Test public void testGetInProgressRequestsCountSqlException() throws SQLException, APPCException { TransactionRecord input = prepareTransactionsInput(); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(APPCException.class); expectedEx.expectMessage(TransactionConstants.ERROR_ACCESSING_DATABASE); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.getInProgressRequestsCount(); } @Test public void testGetInProgressRequestsCountNoRecords() throws SQLException, APPCException { CachedRowSetImpl rowset = Mockito.mock(CachedRowSetImpl.class); Mockito.when(rowset.first()).thenReturn(false); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenReturn(rowset); expectedEx.expect(APPCException.class); expectedEx.expectMessage(TransactionConstants.ERROR_ACCESSING_DATABASE); transactionRecorderImpl.getInProgressRequestsCount(); } @Test public void testUpdate() throws APPCException, SQLException { TransactionRecord input = prepareTransactionsInput(); insertRecord(input); Map updateColumns = new HashMap<>(); updateColumns.put(TransactionConstants.TRANSACTION_ATTRIBUTES.TARGET_TYPE, "Firewall"); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> returnResult(invocation.getArguments())); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> testUpdateInMemory(invocation.getArguments())); transactionRecorderImpl.update(input.getTransactionId(), input.getRequestId(), updateColumns); Mockito.verify(dbLibService).getData(anyString(), anyObject(), anyString()); Mockito.verify(dbLibService).writeData(anyString(), anyObject(), anyString()); } @Test public void testUpdateExceptionFlow() throws APPCException, SQLException { TransactionRecord input = prepareTransactionsInput(); insertRecord(input); Map updateColumns = new HashMap<>(); updateColumns.put(TransactionConstants.TRANSACTION_ATTRIBUTES.TARGET_TYPE, "Firewall"); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(APPCException.class); expectedEx.expectMessage(TransactionConstants.ERROR_ACCESSING_DATABASE); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.update(input.getTransactionId(), input.getRequestId(), updateColumns); } @Test public void testUpdatewithNullInstance() throws APPCException, SQLException { TransactionRecord input = prepareTransactionsInput(); Map updateColumns = new HashMap<>(); updateColumns.put(TransactionConstants.TRANSACTION_ATTRIBUTES.TARGET_TYPE, "Firewall"); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> returnPositiveResult(invocation.getArguments())); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())) .thenAnswer(invocation -> testUpdateInMemory(invocation.getArguments())); transactionRecorderImpl.update(input.getTransactionId(), input.getRequestId(), updateColumns); Mockito.verify(dbLibService).getData(anyString(), anyObject(), anyString()); Mockito.verify(dbLibService).writeData(anyString(), anyObject(), anyString()); } private Object returnPositiveResult(Object[] obj) throws Exception { String query = (String) obj[0]; ArrayList args = (ArrayList) obj[1]; System.out.println("returnPositiveResult: Query: " + query + "\nArgs: " + args); insertNullInstanceData(args.get(0)); try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps_second = con.prepareStatement(query) ) { for (int i = 1; i <= args.size(); i++) { ps_second.setString(i, args.get(i - 1)); } CachedRowSet rowSet = new CachedRowSetImpl(); rowSet.populate(ps_second.executeQuery()); return rowSet; } } private void insertNullInstanceData(String transactionId) throws Exception { final String nullInstanceQuery = TransactionConstants.INSERT_INTO + TransactionConstants.TRANSACTIONS + " values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(nullInstanceQuery) ) { ArrayList input = new ArrayList(); input.add(transactionId); input.add(dateToStringConverterMillis(Instant.parse("2017-09-12T00:00:01.00Z"))); input.add("REQUEST_ID"); input.add("SUB_REQUEST_ID"); input.add("ORIGINATOR_ID"); input.add(dateToStringConverterMillis(Instant.parse("2018-09-12T00:00:02.00Z"))); input.add(dateToStringConverterMillis(Instant.parse("2018-09-12T20:00:02.00Z"))); input.add("TARGET_ID"); input.add("TARGET_TYPE"); input.add("Audit"); input.add(String.valueOf(200)); input.add("SERVICE_INSTANCE_ID"); input.add("ACCEPTED"); input.add("DESCRIPTION"); input.add("test"); input.add("test"); input.add("test"); input.add("EXCLUSIVE"); for (int i = 1; i <= input.size(); i++) { ps.setString(i, input.get(i-1)); } ps.execute(); if (checkIfRowIsPresent(input.get(0))) { System.out.println("RECORD INSERTED " + input.get(0)); } } } private ResultSet returnResult(Object[] obj) throws Exception { String query = (String) obj[0]; ArrayList args = (ArrayList) obj[1]; System.out.println("Query: " + query + "\nArgs: " + args); try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(query) ) { for (int i = 1; i <= args.size(); i++) { ps.setString(i, args.get(i - 1)); } CachedRowSet rowSet = new CachedRowSetImpl(); rowSet.populate(ps.executeQuery()); return rowSet; } } @Test public void testMarkTransactionsAborted() throws SQLException { TransactionRecord input = prepareTransactionsInput(); insertRecord(input); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> testMarkAbortedInMemory(invocation.getArguments())); transactionRecorderImpl.markTransactionsAborted("123~"); } @Test public void testMarkTransactionsAbortedExceptionFlow() throws SQLException { TransactionRecord input = prepareTransactionsInput(); insertRecord(input); Mockito.when(dbLibService.writeData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(RuntimeException.class); expectedEx.expectMessage("In progress transactions couldn't be marked aborted on server start up"); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.markTransactionsAborted("123~"); } @Test public void testGetRecords() throws SQLException, APPCException { CachedRowSetImpl rowset = Mockito.mock(CachedRowSetImpl.class); Mockito.when(rowset.next()).thenReturn(true).thenReturn(false); Mockito.when(rowset.getString(TRANSACTION_ATTRIBUTES.STATE.getColumnName())).thenReturn("NAME"); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenReturn(rowset); Assert.assertEquals(RequestStatus.UNKNOWN, transactionRecorderImpl.getRecords(null, "SUBREQUEST_ID", "ORIGINATOR_ID", null).get(0)); } @Test public void testGetRecordsSqlException() throws SQLException, APPCException { Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenThrow(new SQLException()); expectedEx.expect(APPCException.class); expectedEx.expectMessage("Error retrieving record for requestID null and vnfId null"); expectedEx.expectCause(isA(SQLException.class)); transactionRecorderImpl.getRecords(null, null, null, null); } private ResultSet inMemoryExecutionWithResultSet(Object[] obj) throws Exception { String query = (String) obj[0]; ArrayList args = (ArrayList) obj[1]; // System.out.println("Query: " + query + "\nArgs: " + args); try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(query) ) { for (int i = 1; i <= args.size(); i++) { ps.setString(i, args.get(i - 1)); } CachedRowSet rowSet = new CachedRowSetImpl(); rowSet.populate(ps.executeQuery()); return rowSet; } } private boolean testMarkAbortedInMemory(Object[] obj) throws Exception { String query = (String) obj[0]; ArrayList args = (ArrayList) obj[1]; try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(query) ) { for (int i = 1; i <= args.size(); i++) { ps.setString(i, args.get(i - 1)); } ps.execute(); return isTransactionAborted(); } } private boolean isTransactionAborted() throws Exception { String query = "SELECT COUNT(*) FROM TRANSACTIONS WHERE STATE = ?"; try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(query) ) { ps.setString(1, RequestStatus.ABORTED.toString()); try ( ResultSet rs = ps.executeQuery() ) { while (rs.next()) { int value = rs.getInt(1); if (value == 1) { System.out.println("Non terminal Transactions are aborted"); return true; } } throw new Exception("Transactions are not aborted"); } } } private boolean testUpdateInMemory(Object[] obj) throws Exception { String query = (String) obj[0]; ArrayList args = (ArrayList) obj[1]; try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(query) ) { for (int i = 1; i <= args.size(); i++) { System.out.println("Value at " + i + ": " + args.get(i - 1)); ps.setString(i, args.get(i - 1)); } ps.execute(); String updatedValue = checkIfValueIsUpdated(args.get(1)); System.out.println("updated Value is " + updatedValue); if (updatedValue.equals("Firewall")) { return true; } throw new Exception("Not Updated"); } } private boolean testStoreInMemory(Object[] obj) throws Exception { String query = (String) obj[0]; ArrayList args = (ArrayList) obj[1]; try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(query) ) { for (int i = 1; i <= args.size(); i++) { ps.setString(i, args.get(i - 1)); } ps.execute(); if (checkIfRowIsPresent(args.get(0))) { return true; } throw new Exception("Failed to update"); } } private TransactionRecord prepareTransactionsInput() { TransactionRecord input = new TransactionRecord(); input.setTransactionId(UUID.randomUUID().toString()); input.setOriginTimestamp(Instant.parse("2017-09-11T00:00:01.00Z")); input.setRequestId("REQUEST_ID"); input.setSubRequestId("SUB_REQUEST_ID"); input.setOriginatorId("ORIGINATOR_ID"); input.setStartTime(Instant.parse("2017-09-11T00:00:02.00Z")); input.setTargetId("TARGET_ID"); input.setTargetType("TARGET_TYPE"); input.setServiceInstanceId("SERVICE_INSTANCE_ID"); input.setOperation(VNFOperation.ActionStatus); input.setResultCode(200); input.setRequestState(RequestStatus.ACCEPTED); input.setDescription("DESCRIPTION"); input.setMode(Flags.Mode.EXCLUSIVE); return input; } private void insertRecord(TransactionRecord input) throws SQLException { final String STORE_DATE_QUERY = TransactionConstants.INSERT_INTO + TransactionConstants.TRANSACTIONS + " values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement(STORE_DATE_QUERY) ) { ArrayList args = prepareArguments(input); args.remove(0); args.add(0, "123~" + input.getTransactionId()); for (int i = 1; i <= 18; i++) { ps.setString(i, args.get(i - 1)); } ps.execute(); if (checkIfRowIsPresent(args.get(0))) { System.out.println("RECORD INSERTED " + args.get(0)); } } } private ArrayList prepareArguments(TransactionRecord input) { ArrayList arguments = new ArrayList<>(); arguments.add(input.getTransactionId()); arguments.add(dateToStringConverterMillis(input.getOriginTimestamp())); arguments.add(input.getRequestId()); arguments.add(input.getSubRequestId()); arguments.add(input.getOriginatorId()); arguments.add(dateToStringConverterMillis(input.getStartTime())); arguments.add(dateToStringConverterMillis(input.getEndTime())); arguments.add(input.getTargetId()); arguments.add(input.getTargetType()); arguments.add(input.getOperation().name()); arguments.add(String.valueOf(input.getResultCode())); arguments.add(input.getDescription()); arguments.add(input.getRequestState()); arguments.add(input.getServiceInstanceId()); arguments.add(input.getVnfcName()); arguments.add(input.getVserverId()); arguments.add(input.getVfModuleId()); arguments.add(input.getMode()); return arguments; } private static String dateToStringConverterMillis(Instant date) { if (date == null) { return null; } DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").withZone(ZoneOffset.UTC); return formatter.format(date); } private boolean checkIfRowIsPresent(String key) { Connection con = null; ResultSet rs = null; PreparedStatement ps = null; try { con = dbConnectionPool.getConnection(); ps = con.prepareStatement("SELECT COUNT(*) FROM TRANSACTIONS WHERE TRANSACTION_ID = ?"); ps.setString(1, key); rs = ps.executeQuery(); while (rs.next()) { int value = rs.getInt(1); System.out.println("KEY checked is " + key + " COUNT RETURNED IS " + value); if (value == 1) { return true; } } } catch (SQLException e) { e.printStackTrace(); } finally { DBHelper.close(rs, ps, con); } return false; } private String checkIfValueIsUpdated(String key) throws Exception { try ( Connection con = dbConnectionPool.getConnection(); PreparedStatement ps = con.prepareStatement( "SELECT TARGET_TYPE, TRANSACTION_ID FROM TRANSACTIONS" + " WHERE TRANSACTION_ID = ?") ) { ps.setString(1, key); try ( ResultSet rs = ps.executeQuery() ) { while (rs.next()) { String value = rs.getString("TARGET_TYPE"); String transactionId = rs.getString("TRANSACTION_ID"); System.out.println("Updated data: TRANSACTION_ID: " + transactionId + " TARGET_TYPE: " + value); return value; } throw new Exception("Value not found"); } } } /** * Verify the transactionRecorderImpl. getRecords () can be fetch with each of the parameter combinations * @throws Exception *//* @Test public void test_api_getRecords() throws Exception { final int requestId = 0; final int subrequestId = 1; final int originatorId = 2; final int vnfId = 3; final int requestStatus = 4; String[][] trCreateMatrix = { {"request1", "subrequestId1", "originatorId1", "vnfId1", RequestStatus.UNKNOWN.name()}, {"request1", "subrequestId2", "originatorId1", "vnfId1", RequestStatus.RECEIVED.name()}, {"request2", "subrequestId1", "originatorId1", "vnfId1", RequestStatus.ACCEPTED.name()}, {"request2", "subrequestId2", "originatorId1", "vnfId1", RequestStatus.REJECTED.name()}, {"request1", "subrequestId1", "originatorId1", "vnfId2", RequestStatus.SUCCESSFUL.name()}, {"request1", "subrequestId2", "originatorId1", "vnfId2", RequestStatus.FAILED.name()}, {"request2", "subrequestId1", "originatorId1", "vnfId2", RequestStatus.TIMEOUT.name()}, {"request2", "subrequestId2", "originatorId1", "vnfId2", RequestStatus.ABORTED.name()}, {"request1", "subrequestId1", "originatorId2", "vnfId1", RequestStatus.UNKNOWN.name()}, {"request1", "subrequestId2", "originatorId2", "vnfId1", RequestStatus.RECEIVED.name()}, {"request2", "subrequestId1", "originatorId2", "vnfId1", RequestStatus.ACCEPTED.name()}, {"request2", "subrequestId2", "originatorId2", "vnfId1", RequestStatus.REJECTED.name()}, {"request1", "subrequestId1", "originatorId2", "vnfId2", RequestStatus.SUCCESSFUL.name()}, {"request1", "subrequestId2", "originatorId2", "vnfId2", RequestStatus.FAILED.name()}, {"request2", "subrequestId1", "originatorId2", "vnfId2", RequestStatus.TIMEOUT.name()}, {"request2", "subrequestId2", "originatorId2", "vnfId2", RequestStatus.ABORTED.name()}, }; TransactionRecord tr = new TransactionRecord(); tr.setTimeStamp(Instant.parse("2017-09-11T00:00:01.00Z")); tr.setStartTime(Instant.parse("2017-09-11T00:00:02.00Z")); tr.setEndTime(Instant.parse("2017-09-11T00:00:03.00Z")); tr.setTargetType("TARGET_TYPE"); tr.setSubComponent("SUB_COMPONENT"); tr.setOperation(VNFOperation.ActionStatus); tr.setResultCode("RESULT_CODE"); tr.setDescription("DESCRIPTION"); for (int row = 0; row < trCreateMatrix.length; row++) { tr.setRequestID(trCreateMatrix[row][requestId]); tr.setSubRequestID(trCreateMatrix[row][subrequestId]); tr.setOriginatorId(trCreateMatrix[row][originatorId]); tr.setTargetID(trCreateMatrix[row][vnfId]); tr.setRequestStatus(RequestStatus.valueOf(trCreateMatrix[row][requestStatus])); transactionRecorderImpl.store(tr); } String[][] trSearchMatrix = { {"request1", null, null, "vnfId1"}, {"request2", "subrequestId1", null, "vnfId1"}, {"request1", null, "originatorId1", "vnfId1"}, {"request2", "subrequestId2", "originatorId1", "vnfId1"}, }; for (int i = 0; i < trSearchMatrix.length; i++) { final int row = i; List actualList = transactionRecorderImpl .getRecords(trSearchMatrix[row][requestId], trSearchMatrix[row][subrequestId], trSearchMatrix[row][originatorId], trSearchMatrix[row][vnfId]) .stream() .sorted() .collect(Collectors.toList()); List expectedList = Arrays.stream(trCreateMatrix) .filter(entry -> entry[requestId].equals(trSearchMatrix[row][requestId])) .filter(entry -> trSearchMatrix[row][subrequestId] == null || entry[subrequestId].equals (trSearchMatrix[row][subrequestId])) .filter(entry -> trSearchMatrix[row][originatorId] == null || entry[originatorId].equals (trSearchMatrix[row][originatorId])) .filter(entry -> entry[vnfId].equals(trSearchMatrix[row][vnfId])) .map(entry -> RequestStatus.valueOf(entry[requestStatus])) .sorted() .collect(Collectors.toList()); System.out.println(expectedList); System.out.println(actualList); Assert.assertEquals("Unexpected results: ", expectedList, actualList); } }*/ }