From f1b353074c937b473e23e717966d97602bc981f8 Mon Sep 17 00:00:00 2001 From: "Balaji, Ramya (rb111y)" Date: Fri, 7 Sep 2018 16:00:46 -0400 Subject: In progress trxns criteria fix Changed the criteria for inprogress transactions to the last X hours. This will eliminate stale transactions causing an incorrect scope overlap error. Issue-ID: APPC-1194 Change-Id: I2f3147503f4202e8e8931b2615e626e3b9af8261 Signed-off-by: Balaji, Ramya (rb111y) --- .../transactionrecorder/TransactionRecorder.java | 9 +-- .../impl/TransactionRecorderImpl.java | 16 +++-- .../impl/TransactionRecorderImplTest.java | 24 +++++-- .../requesthandler/impl/RequestValidatorImpl.java | 73 +++++++++++++++++++--- .../impl/RequestValidatorImplTest.java | 43 ++++++++++--- 5 files changed, 135 insertions(+), 30 deletions(-) (limited to 'appc-dispatcher') diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java index 299115d99..17e0e2575 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/TransactionRecorder.java @@ -9,15 +9,15 @@ * 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========================================================= */ @@ -62,10 +62,11 @@ public interface TransactionRecorder { * Fetch list of Transactions which are in non-terminal state i.e. ACCEPTED or RECEIVED for particular TargetId. * @param record Transactions object from which TargetId and StartTime is extracted to fetch list of in progress * requests which APPC received before the current request. + * @param interval Number of hours - Time window to consider requests as being in progress * @return List of Transactions in non terminal state. * @throws APPCException */ - List getInProgressRequests(TransactionRecord record) throws APPCException; + List getInProgressRequests(TransactionRecord record, int interval) throws APPCException; /** * Checks whether the incoming request is duplicate. diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java index 7c1581f57..98ea1b538 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/main/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImpl.java @@ -9,15 +9,15 @@ * 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========================================================= */ @@ -45,6 +45,7 @@ import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.time.temporal.ChronoUnit; import static org.onap.appc.transactionrecorder.objects.TransactionConstants.TRANSACTION_ATTRIBUTES.*; import static org.onap.appc.transactionrecorder.objects.TransactionConstants.*; @@ -165,19 +166,24 @@ public class TransactionRecorderImpl implements TransactionRecorder { } @Override - public List getInProgressRequests(TransactionRecord record) throws APPCException { + public List getInProgressRequests(TransactionRecord record, int interval) throws APPCException { - final String IN_PROGRESS_REQUESTS_QUERY = "SELECT * FROM " + + String IN_PROGRESS_REQUESTS_QUERY = "SELECT * FROM " + TransactionConstants.TRANSACTIONS + WHERE + TARGET_ID + " = ? AND " + STATE.getColumnName() + " IN (?,?) AND " + START_TIME.getColumnName() + " < ?"; ArrayList inProgressQueryParams = new ArrayList<>(); + Instant window = record.getStartTime().minus(interval, ChronoUnit.HOURS); inProgressQueryParams.add(record.getTargetId()); inProgressQueryParams.add(RequestStatus.RECEIVED.name()); inProgressQueryParams.add(RequestStatus.ACCEPTED.name()); inProgressQueryParams.add(dateToStringConverterMillis(record.getStartTime())); + if (interval > 0) { + IN_PROGRESS_REQUESTS_QUERY += " AND " + START_TIME.getColumnName() + " > ? "; + inProgressQueryParams.add(dateToStringConverterMillis(window)); + } try (CachedRowSet rowSet = dbLibService.getData(IN_PROGRESS_REQUESTS_QUERY, inProgressQueryParams, SCHEMA)) { List inProgressRecords = new ArrayList<>(); diff --git a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java index fd1790d49..1418e89c6 100644 --- a/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java +++ b/appc-dispatcher/appc-dispatcher-common/transaction-recorder/src/test/java/org/onap/appc/transactionrecorder/impl/TransactionRecorderImplTest.java @@ -9,15 +9,15 @@ * 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========================================================= */ @@ -45,8 +45,10 @@ import java.sql.*; 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; @@ -152,7 +154,21 @@ public class TransactionRecorderImplTest { input.setStartTime(Instant.now()); Mockito.when(dbLibService.getData(anyString(), anyObject(), anyString())).thenAnswer(invocation -> inMemoryExecutionWithResultSet(invocation.getArguments())); - Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input).size()); + Assert.assertEquals(1, transactionRecorderImpl.getInProgressRequests(input,0).size()); + + } + + @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()); } diff --git a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/impl/RequestValidatorImpl.java b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/impl/RequestValidatorImpl.java index 53f15a092..e97f7c05f 100644 --- a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/impl/RequestValidatorImpl.java +++ b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/main/java/org/onap/appc/requesthandler/impl/RequestValidatorImpl.java @@ -9,15 +9,15 @@ * 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========================================================= */ @@ -93,21 +93,26 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { private RequestValidationPolicy requestValidationPolicy; private RestClientInvoker client; private String path; + private int transactionWindowInterval=0; static final String SCOPE_OVERLAP_ENDPOINT = "appc.LCM.scopeOverlap.endpoint"; static final String ODL_USER = "appc.LCM.provider.user"; static final String ODL_PASS = "appc.LCM.provider.pass"; - + static final String TRANSACTION_WINDOW_HOURS = "appc.inProgressTransactionWindow.hours"; + public void initialize() throws APPCException { logger.info("Initializing RequestValidatorImpl."); String endpoint = null; String user = null; String pass =null; + String transactionWindow = null; + Properties properties = configuration.getProperties(); if (properties != null) { endpoint = properties.getProperty(SCOPE_OVERLAP_ENDPOINT); user = properties.getProperty(ODL_USER); pass = properties.getProperty(ODL_PASS); + transactionWindow = properties.getProperty(TRANSACTION_WINDOW_HOURS); } if (endpoint == null) { String message = "End point is not defined for scope over lap service in appc.properties."; @@ -122,12 +127,24 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { return; } + if (StringUtils.isNotBlank(transactionWindow)) { + logger.info("RequestValidatorImpl::TransactionWindow defined !!!"); + try { + transactionWindowInterval = Integer.parseInt(transactionWindow); + } + catch (NumberFormatException e) { + String message = "RequestValidatorImpl:::Error parsing transaction window interval!"; + logger.error(message, e); + throw new APPCException(message); + } + } + try { URL url = new URL(endpoint); client = new RestClientInvoker(url); client.setAuthentication(user, pass); - path = url.getPath(); - + path = url.getPath(); + } catch (MalformedURLException e) { String message = "Invalid endpoint " + endpoint; logger.error(message, e); @@ -199,10 +216,22 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { return; } + List inProgressTransactionsAll = transactionRecorder + .getInProgressRequests(runtimeContext.getTransactionRecord(),0); List inProgressTransactions = transactionRecorder - .getInProgressRequests(runtimeContext.getTransactionRecord()); + .getInProgressRequests(runtimeContext.getTransactionRecord(),transactionWindowInterval); + + long inProgressTransactionsAllCount = inProgressTransactionsAll.size(); + long inProgressTransactionsRelevant = inProgressTransactions.size(); logger.debug("In progress requests " + inProgressTransactions.toString()); + if ( inProgressTransactions.isEmpty()){ //No need to check for scope overlap + return; + } + + logInProgressTransactions(inProgressTransactions,inProgressTransactionsAllCount, + inProgressTransactionsRelevant ); + Long exclusiveRequestCount = inProgressTransactions.stream() .filter(record -> record.getMode().equals(Flags.Mode.EXCLUSIVE.name())).count(); if (exclusiveRequestCount > 0) { @@ -319,7 +348,7 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { ObjectMapper objectMapper = new ObjectMapper(); ScopeOverlapModel scopeOverlapModel = getScopeOverlapModel(requestContext, inProgressTransactions); // Added for change in interface for action level - + JsonNode jsonObject = objectMapper.valueToTree(scopeOverlapModel); return jsonObject; @@ -375,7 +404,7 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { Request request = new Request(); Date date = new Date(); - request.setRequestID("RequestId-ScopeOverlap " + date.toString()); + request.setRequestID("RequestId-ScopeOverlap " + date.toString()); request.setAction("isScopeOverlap"); ObjectMapper objectMapper = new ObjectMapper(); JsonNode json = objectMapper.valueToTree(requestData); @@ -383,7 +412,7 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { Input input = new Input(); input.setRequest(request); scopeOverlapModel.setInput(input); - + return scopeOverlapModel; } @@ -497,4 +526,28 @@ public class RequestValidatorImpl extends AbstractRequestValidatorImpl { } return workflowRequest; } + + public String logInProgressTransactions(List inProgressTransactions, + long inProgressTransactionsAllCount, long inProgressTransactionsRelevant) { + if (inProgressTransactionsAllCount > inProgressTransactionsRelevant) { + logger.info("Found Stale Transactions! Ignoring Stale Transactions for target, only considering " + + "transactions within the last " + transactionWindowInterval + " hours as transactions in-progress"); + } + String logMsg=""; + for (TransactionRecord tr: inProgressTransactions) { + logMsg = ("In Progress transaction for Target ID - "+ tr.getTargetId() + + " in state " + tr.getRequestState() + + " with Start time " + tr.getStartTime().toString() + + " for more than configurable time period " + transactionWindowInterval + + " hours [transaction details - Request ID - " + tr.getTransactionId() + + ", Service Instance Id -" + tr.getServiceInstanceId() + + ", Vserver_id - " + tr.getVserverId() + + ", VNFC_name - "+ tr.getVnfcName() + + ", VF module Id - " + tr.getVfModuleId() + + " Start time " + tr.getStartTime().toString() + + "]" ); + } + return logMsg; + + } } diff --git a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/impl/RequestValidatorImplTest.java b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/impl/RequestValidatorImplTest.java index e1c10dae1..8e3d77cd3 100644 --- a/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/impl/RequestValidatorImplTest.java +++ b/appc-dispatcher/appc-request-handler/appc-request-handler-core/src/test/java/org/onap/appc/requesthandler/impl/RequestValidatorImplTest.java @@ -25,6 +25,7 @@ package org.onap.appc.requesthandler.impl; +import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyBoolean; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.anyString; @@ -37,10 +38,13 @@ import com.att.eelf.configuration.EELFManager; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.net.MalformedURLException; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.ProtocolVersion; import org.apache.http.entity.BasicHttpEntity; @@ -60,6 +64,7 @@ import org.onap.appc.domainmodel.lcm.CommonHeader; import org.onap.appc.domainmodel.lcm.Flags; import org.onap.appc.domainmodel.lcm.Flags.Mode; import org.onap.appc.domainmodel.lcm.RequestContext; +import org.onap.appc.domainmodel.lcm.RequestStatus; import org.onap.appc.domainmodel.lcm.ResponseContext; import org.onap.appc.domainmodel.lcm.RuntimeContext; import org.onap.appc.domainmodel.lcm.TransactionRecord; @@ -184,7 +189,7 @@ public class RequestValidatorImplTest implements LocalRequestHanlderTestHelper { } - @Test(expected = RequestValidationException.class) + @Test (expected = RequestValidationException.class) public void testValidateRequest() throws Exception { RuntimeContext runtimeContext = createRequestValidatorInput(); logger = Mockito.spy(EELFManager.getInstance().getLogger(LCMStateManager.class)); @@ -193,9 +198,15 @@ public class RequestValidatorImplTest implements LocalRequestHanlderTestHelper { lcmStateManager.enableLCMOperations(); transactionRecorder = Mockito.mock(TransactionRecorder.class); Mockito.when(transactionRecorder.isTransactionDuplicate(anyObject())).thenReturn(false); + List transactionRecordList = new ArrayList(1); TransactionRecord transactionRecord = new TransactionRecord(); transactionRecord.setMode(Mode.EXCLUSIVE); + transactionRecord.setStartTime(Instant.now().minus(5, ChronoUnit.HOURS)); + transactionRecord.setRequestState(RequestStatus.ACCEPTED); runtimeContext.setTransactionRecord(transactionRecord); + transactionRecordList.add(transactionRecord); + Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class),Mockito.any(int.class))) + .thenReturn(transactionRecordList); impl.setTransactionRecorder(transactionRecorder); WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(true, true); WorkFlowManager workflowManager = Mockito.mock(WorkFlowManagerImpl.class); @@ -244,8 +255,10 @@ public class RequestValidatorImplTest implements LocalRequestHanlderTestHelper { List transactionRecordList = new ArrayList(1); TransactionRecord inProgressTransaction = new TransactionRecord(); inProgressTransaction.setMode(Mode.EXCLUSIVE); + inProgressTransaction.setStartTime(Instant.now().minus(5, ChronoUnit.HOURS)); + inProgressTransaction.setRequestState(RequestStatus.ACCEPTED); transactionRecordList.add(inProgressTransaction); - Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class))) + Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class),Mockito.any(int.class))) .thenReturn(transactionRecordList); runtimeContext.setTransactionRecord(inProgressTransaction); impl.setTransactionRecorder(transactionRecorder); @@ -277,18 +290,21 @@ public class RequestValidatorImplTest implements LocalRequestHanlderTestHelper { RuntimeContext runtimeContext = createRequestValidatorInput(); lcmStateManager.enableLCMOperations(); transactionRecorder = Mockito.mock(TransactionRecorder.class); - Mockito.when(transactionRecorder.isTransactionDuplicate(anyObject())).thenReturn(false); + List transactionRecordList = new ArrayList(1); TransactionRecord inProgressTransaction = new TransactionRecord(); inProgressTransaction.setMode(Mode.NORMAL); inProgressTransaction.setOperation(VNFOperation.ActionStatus); + inProgressTransaction.setRequestState(RequestStatus.ACCEPTED); + inProgressTransaction.setStartTime(Instant.now().minus(48, ChronoUnit.HOURS)); transactionRecordList.add(inProgressTransaction); - runtimeContext.setTransactionRecord(inProgressTransaction); - Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class))) - .thenReturn(transactionRecordList); + Mockito.when(transactionRecorder.getInProgressRequests(Mockito.any(TransactionRecord.class),Mockito.any(int.class))) + .thenReturn(transactionRecordList); + Mockito.when(transactionRecorder.isTransactionDuplicate(anyObject())).thenReturn(false); impl.setTransactionRecorder(transactionRecorder); - WorkflowExistsOutput workflowExistsOutput = new WorkflowExistsOutput(true, true); + runtimeContext.setTransactionRecord(inProgressTransaction); WorkFlowManager workflowManager = Mockito.mock(WorkFlowManagerImpl.class); + WorkflowExistsOutput workflowExistsOutput = Mockito.spy(new WorkflowExistsOutput(true, true)); Mockito.when(workflowManager.workflowExists(Mockito.any(WorkflowRequest.class))) .thenReturn(workflowExistsOutput); impl.setWorkflowManager(workflowManager); @@ -384,6 +400,19 @@ public class RequestValidatorImplTest implements LocalRequestHanlderTestHelper { impl.validateRequest(runtimeContext); } + @Test + public void testLogInProgressTransactions() { + ArrayList trArray = new ArrayList(); + TransactionRecord tr = new TransactionRecord(); + tr.setRequestState(RequestStatus.ACCEPTED); + tr.setStartTime(Instant.now().minus(48, ChronoUnit.HOURS)); + tr.setTargetId("Vnf001"); + trArray.add(tr); + String loggedMessage = impl.logInProgressTransactions(trArray, 1, 1); + String partMessage = "In Progress transaction for Target ID - Vnf001 in state ACCEPTED"; + assertTrue(StringUtils.contains(loggedMessage, partMessage)); + } + private RuntimeContext createRequestValidatorInput() { return createRequestHandlerRuntimeContext("VSCP", "{\"request-id\":\"request-id\"}"); } -- cgit 1.2.3-korg