From 924616740bdf5f596bd6f32dac32c1a8e5504650 Mon Sep 17 00:00:00 2001 From: Patrick Brady Date: Wed, 27 Feb 2019 13:41:53 -0800 Subject: Fix failing powermock tests The version of javassist coming from opendaylight is not working correctly with powermock. Adding a test scoped dependency for a working version of javassist. Test classes added in this commit are not new, they were temporarily removed as part of https://gerrit.onap.org/r/#/c/79046/ Change-Id: I193873c0d4abd7b11592a95bff9a6b07cf2d7191 Signed-off-by: Patrick Brady Issue-ID: APPC-1277 --- .../test/java/org/onap/appc/oam/AppcOamTest.java | 235 ++++++++ .../onap/appc/oam/processor/BaseCommonTest.java | 185 ++++++ .../onap/appc/oam/processor/BaseProcessorTest.java | 175 ++++++ .../onap/appc/oam/util/AsyncTaskHelperTest.java | 663 +++++++++++++++++++++ 4 files changed, 1258 insertions(+) create mode 100644 appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/AppcOamTest.java create mode 100644 appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseCommonTest.java create mode 100644 appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseProcessorTest.java create mode 100644 appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/util/AsyncTaskHelperTest.java (limited to 'appc-oam/appc-oam-bundle/src') diff --git a/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/AppcOamTest.java b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/AppcOamTest.java new file mode 100644 index 000000000..c3aac5635 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/AppcOamTest.java @@ -0,0 +1,235 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Modifications (C) 2018 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.oam; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.spy; +import java.util.Collection; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.onap.appc.exceptions.APPCException; +import org.onap.appc.i18n.Msg; +import org.onap.appc.metricservice.MetricRegistry; +import org.onap.appc.metricservice.MetricService; +import org.onap.appc.metricservice.metric.Metric; +import org.onap.appc.metricservice.metric.MetricType; +import org.onap.appc.metricservice.metric.impl.DefaultPrimitiveCounter; +import org.onap.appc.metricservice.metric.impl.DispatchingFuntionMetricImpl; +import org.onap.appc.oam.processor.OamMmodeProcessor; +import org.onap.appc.oam.processor.OamRestartProcessor; +import org.onap.appc.oam.processor.OamStartProcessor; +import org.onap.appc.oam.processor.OamStopProcessor; +import org.onap.appc.oam.util.AsyncTaskHelper; +import org.onap.appc.oam.util.ConfigurationHelper; +import org.onap.appc.oam.util.OperationHelper; +import org.onap.appc.oam.util.StateHelper; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.AppcState; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.GetAppcStateInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.GetAppcStateOutput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.GetMetricsInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.GetMetricsOutput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.MaintenanceModeInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.MaintenanceModeOutput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.RestartInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.RestartOutput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.StartInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.StartOutput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.StopInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.StopOutput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.status.Status; +import org.opendaylight.yangtools.yang.common.RpcError; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.powermock.reflect.Whitebox; +import com.att.aft.dme2.internal.google.common.collect.Iterables; +import com.att.eelf.configuration.EELFLogger; +import com.google.common.collect.ImmutableMap; + + +public class AppcOamTest { + + private AppcOam appcOam; + private CommonHeader mockCommonHeader = mock(CommonHeader.class); + private Status mockStatus = mock(Status.class); + private OperationHelper mockOperationHelper = mock(OperationHelper.class); + private StateHelper mockStateHelper = mock(StateHelper.class); + + @Before + public void setUp() throws Exception { + appcOam = spy(new AppcOam(null, null, null)); + + Whitebox.setInternalState(appcOam, "stateHelper", mockStateHelper); + Whitebox.setInternalState(appcOam, "operationHelper", mockOperationHelper); + } + + @Test + public void testMaintenanceMode() throws Exception { + // mock processor creation + OamMmodeProcessor mockProcessor = mock(OamMmodeProcessor.class); + Mockito.doReturn(mockProcessor).when(appcOam).getOamMmodeProcessor(Mockito.any(EELFLogger.class), + Mockito.any(ConfigurationHelper.class), Mockito.any(StateHelper.class), + Mockito.any(AsyncTaskHelper.class), Mockito.any(OperationHelper.class)); + // mock input + MaintenanceModeInput mockInput = mock(MaintenanceModeInput.class); + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + // mock processor result + Mockito.doReturn(mockStatus).when(mockProcessor).processRequest(mockInput); + + Future> response = appcOam.maintenanceMode(mockInput); + + Assert.assertEquals("Should have common header", mockCommonHeader, + response.get().getResult().getCommonHeader()); + Assert.assertEquals("Should have status", mockStatus, response.get().getResult().getStatus()); + } + + @Test + public void testStart() throws Exception { + // mock processor creation + OamStartProcessor mockProcessor = mock(OamStartProcessor.class); + Mockito.doReturn(mockProcessor).when(appcOam).getOamStartProcessor(Mockito.any(EELFLogger.class), + Mockito.any(ConfigurationHelper.class), Mockito.any(StateHelper.class), + Mockito.any(AsyncTaskHelper.class), Mockito.any(OperationHelper.class)); + // mock input + StartInput mockInput = mock(StartInput.class); + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + // mock processor result + Mockito.doReturn(mockStatus).when(mockProcessor).processRequest(mockInput); + + Future> response = appcOam.start(mockInput); + + Assert.assertEquals("Should have common header", mockCommonHeader, + response.get().getResult().getCommonHeader()); + Assert.assertEquals("Should have status", mockStatus, response.get().getResult().getStatus()); + } + + @Test + public void testStop() throws Exception { + // mock processor creation + OamStopProcessor mockProcessor = mock(OamStopProcessor.class); + //Mockito.doNothing().when(mockProcessor).setInitialLogProperties(); + Mockito.doReturn(mockProcessor).when(appcOam).getOamStopProcessor(Mockito.any(EELFLogger.class), + Mockito.any(ConfigurationHelper.class), Mockito.any(StateHelper.class), + Mockito.any(AsyncTaskHelper.class), Mockito.any(OperationHelper.class)); + // mock input + StopInput mockInput = mock(StopInput.class); + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + // mock processor result + Mockito.doReturn(mockStatus).when(mockProcessor).processRequest(mockInput); + + Future> response = appcOam.stop(mockInput); + + Assert.assertEquals("Should have common header", mockCommonHeader, + response.get().getResult().getCommonHeader()); + Assert.assertEquals("Should have status", mockStatus, response.get().getResult().getStatus()); + } + + @Test + public void testRestart() throws Exception { + // mock processor creation + OamRestartProcessor mockProcessor = mock(OamRestartProcessor.class); + Mockito.doReturn(mockProcessor).when(appcOam).getOamRestartProcessor(Mockito.any(EELFLogger.class), + Mockito.any(ConfigurationHelper.class), Mockito.any(StateHelper.class), + Mockito.any(AsyncTaskHelper.class), Mockito.any(OperationHelper.class)); + // mock input + RestartInput mockInput = mock(RestartInput.class); + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + // mock processor result + Mockito.doReturn(mockStatus).when(mockProcessor).processRequest(mockInput); + + Future> response = appcOam.restart(mockInput); + + Assert.assertEquals("Should have common header", mockCommonHeader, + response.get().getResult().getCommonHeader()); + Assert.assertEquals("Should have status", mockStatus, response.get().getResult().getStatus()); + } + + @Test + public void testGetAppcState() throws Exception { + AppcState appcState = AppcState.Started; + Mockito.doReturn(appcState).when(mockStateHelper).getCurrentOamYangState(); + GetAppcStateInput getAppcStateInput = mock(GetAppcStateInput.class); + Future> state = appcOam.getAppcState(getAppcStateInput); + Assert.assertEquals("Should return the same state", + appcState, state.get().getResult().getState()); + } + + @Test + public void testGetMetricsMetricDisabled() throws InterruptedException, ExecutionException { + Whitebox.setInternalState(appcOam, "isMetricEnabled", false); + GetMetricsInput getMetricsInput = mock(GetMetricsInput.class); + Future> result = appcOam.getMetrics(getMetricsInput); + assertEquals("Metric Service not enabled", Iterables.get(result.get().getErrors(), 0).getMessage()); + } + + @Test + public void testGetMetricsNoMetricsService() throws InterruptedException, ExecutionException, APPCException { + Whitebox.setInternalState(appcOam, "isMetricEnabled", true); + Mockito.doThrow(new APPCException()).when(mockOperationHelper).getService(MetricService.class); + GetMetricsInput getMetricsInput = mock(GetMetricsInput.class); + Future> result = appcOam.getMetrics(getMetricsInput); + assertEquals("Metric Service not found", Iterables.get(result.get().getErrors(), 0).getMessage()); + } + + @Test + public void testGetMetricsNoMetrics() throws InterruptedException, ExecutionException, APPCException { + Whitebox.setInternalState(appcOam, "isMetricEnabled", true); + MetricService mockMetricService = mock(MetricService.class); + Mockito.doReturn(mockMetricService).when(mockOperationHelper).getService(MetricService.class); + GetMetricsInput getMetricsInput = mock(GetMetricsInput.class); + Future> result = appcOam.getMetrics(getMetricsInput); + assertEquals("No metrics Registered", Iterables.get(result.get().getErrors(), 0).getMessage()); + } + + @Test + public void testGetMetricsWithMetricRegistry() throws InterruptedException, ExecutionException, APPCException { + Whitebox.setInternalState(appcOam, "isMetricEnabled", true); + MetricService mockMetricService = mock(MetricService.class); + MetricRegistry mockMetricRegistry = mock(MetricRegistry.class); + Mockito.doReturn(mockMetricService).when(mockOperationHelper).getService(MetricService.class); + Mockito.doReturn(ImmutableMap.of("TEST REGISTRY NAME", mockMetricRegistry)).when(mockMetricService).getAllRegistry(); + Metric metric = new DispatchingFuntionMetricImpl("TEST METRIC NAME", MetricType.COUNTER, 0, 0); + Mockito.doReturn(new Metric[] {metric}).when(mockMetricRegistry).metrics(); + GetMetricsInput getMetricsInput = mock(GetMetricsInput.class); + Future> result = appcOam.getMetrics(getMetricsInput); + assertEquals(1, result.get().getResult().getMetrics().size()); + } + + @Test + public void testClose() throws Exception { + ConfigurationHelper mockConfigurationHelper = mock(ConfigurationHelper.class); + Mockito.doReturn("TEST APP NAME").when(mockConfigurationHelper).getAppcName(); + Whitebox.setInternalState(appcOam, "configurationHelper", mockConfigurationHelper); + EELFLogger mockLogger = Mockito.mock(EELFLogger.class); + Whitebox.setInternalState(appcOam, "logger", mockLogger); + appcOam.close(); + Mockito.verify(mockLogger).info(Msg.COMPONENT_TERMINATED, "TEST APP NAME", "oam"); + } +} diff --git a/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseCommonTest.java b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseCommonTest.java new file mode 100644 index 000000000..60d9e3c92 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseCommonTest.java @@ -0,0 +1,185 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Modifications (C) 2018 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.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.status.Status; +import org.onap.appc.exceptions.InvalidInputException; +import org.onap.appc.exceptions.InvalidStateException; +import org.onap.appc.oam.AppcOam; +import org.onap.appc.oam.OAMCommandStatus; +import org.onap.appc.oam.util.ConfigurationHelper; +import org.onap.appc.oam.util.OperationHelper; +import org.onap.appc.oam.util.StateHelper; +import org.onap.appc.statemachine.impl.readers.AppcOamStates; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; +import org.slf4j.MDC; +import java.util.Map; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({BaseCommon.class, MDC.class}) +public class BaseCommonTest { + private class TestAbc extends BaseCommon { + + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelperIn for property reading + * @param stateHelperIn for APP-C OAM state checking + * @param operationHelperIn for operational helper + */ + TestAbc(EELFLogger eelfLogger, + ConfigurationHelper configurationHelperIn, + StateHelper stateHelperIn, + OperationHelper operationHelperIn) { + super(eelfLogger, configurationHelperIn, stateHelperIn, operationHelperIn); + } + } + + private TestAbc testBaseCommon; + private ConfigurationHelper mockConfigHelper = mock(ConfigurationHelper.class); + private StateHelper mockStateHelper = mock(StateHelper.class); + private CommonHeader mockCommonHeader = mock(CommonHeader.class); + + @Before + public void setUp() throws Exception { + testBaseCommon = spy(new TestAbc(null, mockConfigHelper, mockStateHelper, null)); + + Whitebox.setInternalState(testBaseCommon, "commonHeader", mockCommonHeader); + Whitebox.setInternalState(testBaseCommon, "rpc", AppcOam.RPC.maintenance_mode); + + // to avoid operation on logger fail, mock up the logger + EELFLogger mockLogger = mock(EELFLogger.class); + Whitebox.setInternalState(testBaseCommon, "logger", mockLogger); + } + + @Test + public void testSetStatus() throws Exception { + OAMCommandStatus oamCommandStatus = OAMCommandStatus.ACCEPTED; + testBaseCommon.setStatus(oamCommandStatus); + Status status = testBaseCommon.status; + Assert.assertEquals("Should have code", oamCommandStatus.getResponseCode(), status.getCode().intValue()); + Assert.assertEquals("Should have message", oamCommandStatus.getResponseMessage(), status.getMessage()); + } + + @Test + public void testSetStatusWithParams() throws Exception { + String message = "testing"; + OAMCommandStatus oamCommandStatus = OAMCommandStatus.REJECTED; + testBaseCommon.setStatus(oamCommandStatus, message); + Status status = testBaseCommon.status; + Assert.assertEquals("Should have code", oamCommandStatus.getResponseCode(), status.getCode().intValue()); + Assert.assertTrue("Should have message", status.getMessage().endsWith(message)); + } + + @Test + public void testSetErrorStatus() throws Exception { + Mockito.doReturn("testName").when(mockConfigHelper).getAppcName(); + Mockito.doReturn(AppcOamStates.Started).when(mockStateHelper).getCurrentOamState(); + Mockito.doReturn("testRequestId").when(mockCommonHeader).getRequestId(); + Mockito.doReturn("testOrigId").when(mockCommonHeader).getOriginatorId(); + Mockito.doReturn("SOME HOST NAME").when(testBaseCommon).getHostInfo(Mockito.anyString()); + + String exceptionMessage = "testing"; + + OAMCommandStatus oamCommandStatus = OAMCommandStatus.INVALID_PARAMETER; + Throwable t = new InvalidInputException(exceptionMessage); + testBaseCommon.setErrorStatus(t); + Status status = testBaseCommon.status; + Assert.assertEquals("Should have code", oamCommandStatus.getResponseCode(), status.getCode().intValue()); + Mockito.verify(testBaseCommon, times(1)).resetLogProperties(false); + Mockito.verify(testBaseCommon, times(1)).resetLogProperties(true); + + oamCommandStatus = OAMCommandStatus.REJECTED; + t = new InvalidStateException(exceptionMessage); + testBaseCommon.setErrorStatus(t); + status = testBaseCommon.status; + Assert.assertEquals("Should have code", oamCommandStatus.getResponseCode(), status.getCode().intValue()); + Mockito.verify(testBaseCommon, times(2)).resetLogProperties(false); + Mockito.verify(testBaseCommon, times(2)).resetLogProperties(true); + + oamCommandStatus = OAMCommandStatus.UNEXPECTED_ERROR; + t = new NullPointerException(exceptionMessage); + testBaseCommon.setErrorStatus(t); + status = testBaseCommon.status; + Assert.assertEquals("Should have code", oamCommandStatus.getResponseCode(), status.getCode().intValue()); + Mockito.verify(testBaseCommon, times(3)).resetLogProperties(false); + Mockito.verify(testBaseCommon, times(3)).resetLogProperties(true); + } + + @Test + public void testSetInitialLogProperties() throws Exception { + mockStatic(MDC.class); + Mockito.doReturn("SOME HOST NAME").when(testBaseCommon).getHostInfo(Mockito.anyString()); + testBaseCommon.setInitialLogProperties(); + PowerMockito.verifyStatic(times(5)); + } + + @Test + public void testClearRequestLogProperties() throws Exception { + mockStatic(MDC.class); + testBaseCommon.clearRequestLogProperties(); + PowerMockito.verifyStatic(times(5)); + } + + @Test + public void testResetLogProperties() throws Exception { + Mockito.doReturn("SOME HOST NAME").when(testBaseCommon).getHostInfo(Mockito.anyString()); + testBaseCommon.setInitialLogProperties(); + + testBaseCommon.resetLogProperties(false); + Mockito.verify(mockCommonHeader, times(2)).getRequestId(); + Mockito.verify(mockCommonHeader, times(2)).getOriginatorId(); + Map oldMdcMap = Whitebox.getInternalState(testBaseCommon, "oldMdcContent"); + Assert.assertTrue("Should have 5 entries in persisted map", oldMdcMap.size() == 5); + + testBaseCommon.resetLogProperties(false); + Mockito.verify(mockCommonHeader, times(3)).getRequestId(); + Mockito.verify(mockCommonHeader, times(3)).getOriginatorId(); + + // test oldMdcMap is cleared + testBaseCommon.resetLogProperties(false); + Mockito.verify(mockCommonHeader, times(4)).getRequestId(); + Mockito.verify(mockCommonHeader, times(4)).getOriginatorId(); + oldMdcMap = Whitebox.getInternalState(testBaseCommon, "oldMdcContent"); + Assert.assertTrue("Should have 5 entries in persisted map", oldMdcMap.size() == 5); + } +} diff --git a/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseProcessorTest.java b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseProcessorTest.java new file mode 100644 index 000000000..55ae11b8d --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/processor/BaseProcessorTest.java @@ -0,0 +1,175 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ================================================================================ + * Modifications (C) 2018 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.oam.processor; + +import com.att.eelf.configuration.EELFLogger; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.StartInput; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.common.header.CommonHeader; +import org.opendaylight.yang.gen.v1.org.onap.appc.oam.rev170303.status.Status; +import org.onap.appc.exceptions.APPCException; +import org.onap.appc.exceptions.InvalidInputException; +import org.onap.appc.exceptions.InvalidStateException; +import org.onap.appc.i18n.Msg; +import org.onap.appc.oam.AppcOam; +import org.onap.appc.oam.OAMCommandStatus; +import org.onap.appc.oam.util.AsyncTaskHelper; +import org.onap.appc.oam.util.ConfigurationHelper; +import org.onap.appc.oam.util.OperationHelper; +import org.onap.appc.oam.util.StateHelper; +import org.onap.appc.statemachine.impl.readers.AppcOamStates; +import org.powermock.reflect.Whitebox; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; + +@SuppressWarnings("ResultOfMethodCallIgnored") +public class BaseProcessorTest { + private AppcOam.RPC testRpc = AppcOam.RPC.start; + private AppcOamStates currentState = AppcOamStates.Stopped; + + private class TestAbc extends BaseProcessor { + + /** + * Constructor + * + * @param eelfLogger for logging + * @param configurationHelperIn for property reading + * @param stateHelperIn for APP-C OAM state checking + * @param asyncTaskHelperIn for scheduling async task + * @param operationHelperIn for operational helper + */ + TestAbc(EELFLogger eelfLogger, + ConfigurationHelper configurationHelperIn, + StateHelper stateHelperIn, + AsyncTaskHelper asyncTaskHelperIn, + OperationHelper operationHelperIn) { + super(eelfLogger, configurationHelperIn, stateHelperIn, asyncTaskHelperIn, operationHelperIn); + + // must set rpc and auditMsg + rpc = testRpc; + auditMsg = Msg.OAM_OPERATION_STARTING; + } + } + + private TestAbc testBaseProcessor; + private ConfigurationHelper mockConfigHelper = mock(ConfigurationHelper.class); + private StateHelper mockStateHelper = mock(StateHelper.class); + private AsyncTaskHelper mockTaskHelper = mock(AsyncTaskHelper.class); + private OperationHelper mockOperHelper = mock(OperationHelper.class); + + private StartInput mockInput = mock(StartInput.class); + private CommonHeader mockCommonHeader = mock(CommonHeader.class); + + @Before + public void setUp() throws Exception { + Mockito.doReturn(mockCommonHeader).when(mockOperHelper).getCommonHeader(mockInput); + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + + testBaseProcessor = spy( + new TestAbc(null, mockConfigHelper, mockStateHelper, mockTaskHelper, mockOperHelper)); + Mockito.doReturn("SOME HOST NAME").when(testBaseProcessor).getHostInfo(Mockito.anyString()); + Whitebox.setInternalState(testBaseProcessor, "commonHeader", mockCommonHeader); + + // to avoid operation on logger fail, mock up the logger + EELFLogger mockLogger = mock(EELFLogger.class); + Whitebox.setInternalState(testBaseProcessor, "logger", mockLogger); + } + + @Test + public void testProcessRequestError() throws Exception { + Mockito.doReturn(currentState).when(mockStateHelper).getCurrentOamState(); + Mockito.doThrow(new InvalidInputException("test")).when(mockOperHelper).isInputValid(mockInput); + Status status = testBaseProcessor.processRequest(mockInput); + Assert.assertEquals("Should return reject", + OAMCommandStatus.INVALID_PARAMETER.getResponseCode(), status.getCode().intValue()); + } + + @Test + public void testProcessRequest() throws Exception { + Mockito.doReturn(currentState).when(mockStateHelper).getCurrentOamState(); + Mockito.doReturn(AppcOamStates.Starting).when(mockOperHelper).getNextState(any(), any()); + Mockito.doReturn(mockCommonHeader).when(mockInput).getCommonHeader(); + Status status = testBaseProcessor.processRequest(mockInput); + Assert.assertEquals("Should return success", + OAMCommandStatus.ACCEPTED.getResponseCode(), status.getCode().intValue()); + } + + @Test(expected = InvalidInputException.class) + public void testPreProcessWithInvalidInput() throws Exception { + Mockito.doThrow(new InvalidInputException("test")).when(mockOperHelper).isInputValid(mockInput); + testBaseProcessor.preProcess(mockInput); + } + + @Test(expected = InvalidStateException.class) + public void testPreProcessWithInvalidState() throws Exception { + Mockito.doReturn(currentState).when(mockStateHelper).getCurrentOamState(); + Mockito.doThrow(new InvalidStateException("test")) + .when(mockOperHelper).getNextState(testRpc.getAppcOperation(), currentState); + testBaseProcessor.preProcess(mockInput); + } + + @Test(expected = APPCException.class) + public void testPreProcessWithAppcException() throws Exception { + Mockito.doReturn(currentState).when(mockStateHelper).getCurrentOamState(); + Mockito.doThrow(new APPCException("test")) + .when(mockOperHelper).getNextState(testRpc.getAppcOperation(), currentState); + testBaseProcessor.preProcess(mockInput); + } + + @Test + public void testPreProcess() throws Exception { + Mockito.doReturn(currentState).when(mockStateHelper).getCurrentOamState(); + AppcOamStates nextState = AppcOamStates.Starting; + Mockito.doReturn(nextState) + .when(mockOperHelper).getNextState(testRpc.getAppcOperation(), currentState); + testBaseProcessor.preProcess(mockInput); + Mockito.verify(mockOperHelper, times(1)).isInputValid(mockInput); + Mockito.verify(mockOperHelper, times(1)).getNextState(testRpc.getAppcOperation(), currentState); + Mockito.verify(mockStateHelper, times(1)).setState(nextState); + } + + @Test + public void testScheduleAsyncTask() throws Exception { + // test no runnable + testBaseProcessor.scheduleAsyncTask(); + Assert.assertTrue(Whitebox.getInternalState(testBaseProcessor, "runnable") == null); + Assert.assertTrue(Whitebox.getInternalState(testBaseProcessor, "scheduledRunnable") == null); + + BaseActionRunnable mockRunnable = mock(BaseActionRunnable.class); + Whitebox.setInternalState(testBaseProcessor, "runnable", mockRunnable); + testBaseProcessor.scheduleAsyncTask(); + // scheduledRunnable should still be null, there's no mock done + // as I have trouble to make mockTaskHelper.scheduleBaseRunnable to return a proper Future + Assert.assertTrue(Whitebox.getInternalState(testBaseProcessor, "scheduledRunnable") == null); + } + +} diff --git a/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/util/AsyncTaskHelperTest.java b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/util/AsyncTaskHelperTest.java new file mode 100644 index 000000000..319b0c796 --- /dev/null +++ b/appc-oam/appc-oam-bundle/src/test/java/org/onap/appc/oam/util/AsyncTaskHelperTest.java @@ -0,0 +1,663 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP : APPC + * ================================================================================ + * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Copyright (C) 2017 Amdocs + * ============================================================================= + * 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.oam.util; + +import com.att.eelf.configuration.EELFLogger; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.onap.appc.oam.AppcOam; +import org.onap.appc.statemachine.impl.readers.AppcOamStates; +import org.osgi.framework.Bundle; +import org.osgi.framework.FrameworkUtil; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +import java.util.LinkedList; +import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; + +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({FrameworkUtil.class}) +public class AsyncTaskHelperTest { + private AsyncTaskHelper asyncTaskHelper; + + private long initialDelayMillis = 0; + private long delayMillis = 10; + + + @Before + public void setUp() throws Exception { + + // to avoid operation on logger fail, mock up the logger + EELFLogger mockLogger = mock(EELFLogger.class); + + + mockStatic(FrameworkUtil.class); + Bundle myBundle = mock(Bundle.class); + Mockito.doReturn("TestBundle").when(myBundle).getSymbolicName(); + PowerMockito.when(FrameworkUtil.getBundle(any())).thenReturn(myBundle); + + asyncTaskHelper = new AsyncTaskHelper(mockLogger); + + + } + + + @After + public void shutdown(){ + asyncTaskHelper.close(); + } + + + /** + * Test that Base Runnable + * + * Runs at a fix rate; + * Only one Base Runnable can be scheduled at time; + * Future.cancle stops the Base Runnable; + * That another Base Runnable can be scheduled once the previous isDone. + */ + @Test + public void test_scheduleBaseRunnable_Base_isDone() throws Exception{ + + + + //loop is to test we can run consecutive Base Runnable + for(int testIteration = 0; testIteration < 3;testIteration++){ + final ExecuteTest et = new ExecuteTest(); + + Future future = asyncTaskHelper.scheduleBaseRunnable( + et::test + , s -> { } + ,initialDelayMillis + ,delayMillis + ); + + //make sure it is running at a fix rate + Assert.assertTrue("It should be iterating", et.waitForTestExec(5000)); + Assert.assertFalse("It Should not be Done", future.isDone()); + Assert.assertTrue("It should be iterating", et.waitForTestExec(5000)); + Assert.assertFalse("It Should not be Done", future.isDone()); + + + //make sure a seconds Runnable cannot be scheduled when one is already running + try { + asyncTaskHelper.scheduleBaseRunnable(et::test + , s -> {} + ,initialDelayMillis + ,delayMillis + ); + Assert.fail("scheduling should have been prevented. "); + } catch (IllegalStateException e) { + //IllegalStateException means the second scheduling was not allowed. + } + + + //let it cancel itself + et.cancelSelfOnNextExecution(future); + + //it should be done after it executes itself one more time. + Assert.assertTrue("it should be done", waitFor(future::isDone, 5000)); + Assert.assertTrue("The test failed to execute", et.isExecuted); + } + + + } + + + /** + * Makes sure the Future.isDone one only returns true if its runnable is not currently executing and will not + * execute in the future. Default implementation of isDone() returns true immediately after the future is + * canceled -- Even if is there is still a thread actively executing the runnable + */ + @Test + public void test_scheduleBaseRunnable_Base_isDone_Ignore_Interrupt() throws Exception{ + + + final ExecuteTest et = new ExecuteTest(); + + //configure test to run long and ignore interrupt + et.isContinuous = true; + et.isIgnoreInterrupt = true; + + + + Future future = asyncTaskHelper.scheduleBaseRunnable( + et::test + , s->{} + ,initialDelayMillis + ,delayMillis + ); + + //make sure it is running + Assert.assertTrue("It should be running",waitFor(et::isExecuting,1000)); + Assert.assertTrue("It should be running",et.waitForTestExec(1000)); + Assert.assertFalse("It Should not be Done", future.isDone()); + + //cancel it and make sure it is still running + future.cancel(true); + Assert.assertTrue("It should be running",waitFor(et::isExecuting,1000)); + Assert.assertTrue("It should be running",et.waitForTestExec(1000)); + Assert.assertFalse("It Should not be Done", future.isDone()); + + //let the thread die and then make sure its done + et.isContinuous = false; + Assert.assertTrue("It should not be running",waitForNot(et::isExecuting,1000)); + Assert.assertTrue("It Should be Done", future.isDone()); + + } + + + + + /** + * Make sure the base Future.isDone returns false until the sub callable has completed execution. + */ + @Test + public void test_scheduleBaseRunnable_SubTask_isDone_Ignore_Interrupt() throws Exception{ + + + final ExecuteTest baseET = new ExecuteTest(); + final ExecuteTest subET = new ExecuteTest(); + + //configure sub test to run long and ignore interrupt + subET.isContinuous = true; + subET.isIgnoreInterrupt = true; + + + //schedule the Base test to run and make sure it is running. + Future baseFuture = asyncTaskHelper.scheduleBaseRunnable( + baseET::test + ,s->{} + ,initialDelayMillis + ,delayMillis + ); + Assert.assertTrue("baseET should be running",waitFor(baseET::isExecuted,1000)); + Assert.assertFalse("baseET Should not be Done because it runs at a fix rate", baseFuture.isDone()); + + + //schedule the sub task and make sure it is running + Future subFuture = asyncTaskHelper.submitBaseSubCallable(subET::test); + Assert.assertTrue("subET should be running",waitFor(subET::isExecuting,1000)); + Assert.assertTrue("subET should be running",subET.waitForTestExec(1000)); + Assert.assertFalse("subET Should not be Done", subFuture.isDone()); + Assert.assertFalse("baseET Should not be Done", baseFuture.isDone()); + + //cancel the base task and make sure isDone is still false + baseFuture.cancel(true); + Assert.assertTrue("subET should be running",waitFor(subET::isExecuting,1000)); + Assert.assertTrue("subET should be running",subET.waitForTestExec(1000)); + Assert.assertFalse("subET Should not be Done",subFuture.isDone()); + Assert.assertFalse("baseET Should not be Done", baseFuture.isDone()); + + + //let the sub task die and and make sure the base is now finally done + subET.isContinuous = false; + Assert.assertTrue("subET should not be running",waitForNot(subET::isExecuting,1000)); + Assert.assertTrue("subET Should be Done", subFuture.isDone()); + Assert.assertTrue("baseET Should be Done", baseFuture.isDone()); + + } + + + /** + * Make sure the base Future.isDone returns false until the 3 sub callable has completed execution. + * Each sub callable will be shutdown one at a time. + */ + public void test_scheduleBaseRunnable_SubTasks_isDone() throws Exception { + + + //loop is to test we can run consecutive Base Runnable + for (int testIteration = 0; testIteration < 3; testIteration++) { + final ExecuteTest baseET = new ExecuteTest(); + final LinkedList subList = new LinkedList<>(); + for (int i = 0; i < 3; i++) { + Sub sub = new Sub(); + sub.et.isContinuous = true; + subList.add(sub); + } + + + //schedule the base runnable and make sure it is running + Future baseFuture = asyncTaskHelper.scheduleBaseRunnable( + baseET::test + , s -> { + } + , initialDelayMillis + , delayMillis + ); + Assert.assertTrue("baseET should be running", waitFor(baseET::isExecuted, 1000)); + Assert.assertFalse("baseET Should not be Done because it runs at a fix rate", baseFuture.isDone()); + + + //schedule the sub Callables and make sure these are running + subList.forEach(sub -> sub.future = asyncTaskHelper.submitBaseSubCallable(sub.et::test)); + for (Sub sub : subList) { + Assert.assertTrue("subET should be running", waitFor(sub.et::isExecuting, 100)); + Assert.assertTrue("subET should be running", sub.et.waitForTestExec(1000)); + Assert.assertFalse("subET Should not be Done", sub.future.isDone()); + } + Assert.assertFalse("baseET Should not be Done", baseFuture.isDone()); + + + //On each iteration shut down a sub callable. Make sure it stops, the others are still running and the + // //base is still running. + while (!subList.isEmpty()) { + + //stop one sub and make sure it stopped + { + Sub sub = subList.removeFirst(); + Assert.assertTrue("subET should be running", waitFor(sub.et::isExecuting, 1000)); + sub.et.isContinuous = false; + Assert.assertTrue("subET should not be running", waitForNot(sub.et::isExecuting,1000)); + Assert.assertTrue("subET Should not be Done", sub.future.isDone()); + } + + //make sure the other are still running + for (Sub sub : subList) { + Assert.assertTrue("subET should be running", waitFor(sub.et::isExecuting, 1000)); + Assert.assertTrue("subET should be running", sub.et.waitForTestExec(1000)); + Assert.assertFalse("subET Should not be Done", sub.future.isDone()); + } + + //Make sure the Base is still running + Assert.assertFalse("baseET Should not be Done", baseFuture.isDone()); + } + + //let the base cancel itself and make sure it stops + baseET.cancelSelfOnNextExecution(baseFuture); + Assert.assertTrue("baseET should be done", waitFor(baseFuture::isDone, 1000)); + } + } + + + /** + * Make sure SubCallable cannot be scheduled when there is not BaseRunnable + */ + @Test(expected=IllegalStateException.class) + public void test_SubTasksScheduleFailWhenNoBase() throws Exception { + asyncTaskHelper.submitBaseSubCallable(()->null); + } + + + + /** + * Make sure SubCallable cannot be scheduled when BaseRunnable is cancelled but is still actively running. + */ + @Test(expected=IllegalStateException.class) + public void test_SubTasksScheduleFailWhenBaseCanceledBeforeisDone() throws Exception { + + final ExecuteTest et = new ExecuteTest(); + et.isContinuous = true; + + Future future = asyncTaskHelper.scheduleBaseRunnable( + et::test + , s -> { } + ,initialDelayMillis + ,delayMillis + ); + + Assert.assertTrue("It should be running",waitFor(et::isExecuting,1000)); + future.cancel(false); + Assert.assertTrue("It should be running",waitFor(et::isExecuting,1000)); + + try { + asyncTaskHelper.submitBaseSubCallable(() -> null); + } finally { + et.isContinuous = false; + } + + + + } + + + /** + * Make sure SubCallable cannot be scheduled after a BaseRunnable has completed + */ + @Test(expected=IllegalStateException.class) + public void test_SubTasksScheduleFailAfterBaseDone() throws Exception { + + final ExecuteTest et = new ExecuteTest(); + + Future future = asyncTaskHelper.scheduleBaseRunnable( + et::test + , s -> { } + ,initialDelayMillis + ,delayMillis + ); + + + future.cancel(false); + Assert.assertTrue("It should not be running",waitFor(future::isDone,1000)); + + try { + asyncTaskHelper.submitBaseSubCallable(() -> null); + } finally { + et.isContinuous = false; + } + + } + + + /** + * Test {@link AsyncTaskHelper#cancelBaseActionRunnable(AppcOam.RPC, AppcOamStates, long, TimeUnit)}} + * Test cancel does not block when BaseRunnable is not scheduled + */ + @Test + public void test_cancel_noBlockingWhenBaseRunnableNotScheduled() throws Exception{ + //nothing is running so this should return immediately without TimeoutException + asyncTaskHelper.cancelBaseActionRunnable(AppcOam.RPC.stop , AppcOamStates.Started , 1, TimeUnit.MILLISECONDS); + } + + + + /** + * Test {@link AsyncTaskHelper#cancelBaseActionRunnable(AppcOam.RPC, AppcOamStates, long, TimeUnit)}} + * Test cancel does blocks until BaseRunnable is done scheduled + */ + @Test() + public void test_cancel_BlockingWhenBaseRunnableNotDone() throws Exception { + + + final ExecuteTest et = new ExecuteTest(); + et.isContinuous = true; + et.isIgnoreInterrupt = true; + asyncTaskHelper.scheduleBaseRunnable( + et::test + , s -> { + } + , initialDelayMillis + , delayMillis + ); + + Assert.assertTrue("It should be running", waitFor(et::isExecuting, 1000)); + + + //we should get a timeout + try { + asyncTaskHelper.cancelBaseActionRunnable( + AppcOam.RPC.stop, + AppcOamStates.Started, + 1, + TimeUnit.MILLISECONDS); + Assert.fail("Should have gotten TimeoutException"); + } catch (TimeoutException e) { + //just ignore as it is expected + } + + + //release the test thread + et.isContinuous = false; + + + //we should not get a timeout + asyncTaskHelper.cancelBaseActionRunnable( + AppcOam.RPC.stop, + AppcOamStates.Started, + 1000, + TimeUnit.MILLISECONDS); + + } + + + + /** + * Test {@link AsyncTaskHelper#cancelBaseActionRunnable(AppcOam.RPC, AppcOamStates, long, TimeUnit)}} + * Test cancel does not block when BaseRunnable is not scheduled + */ + @Test + public void test_BaseRunnableCancelCallback() throws Exception{ + + AtomicReference cancelCallback = new AtomicReference<>(null); + + final ExecuteTest et = new ExecuteTest(); + et.isContinuous = true; + Future future = asyncTaskHelper.scheduleBaseRunnable( + et::test + , cancelCallback::set + , initialDelayMillis + , delayMillis + ); + + Assert.assertTrue("It should be running", waitFor(et::isExecuting, 1000)); + Assert.assertTrue("It should be running", waitForNot(future::isDone, 1000)); + + + try { + asyncTaskHelper.cancelBaseActionRunnable( + AppcOam.RPC.stop, + AppcOamStates.Started, + 1, + TimeUnit.MILLISECONDS); + Assert.fail("Should have gotten TimeoutException"); + } catch (TimeoutException e) { + //just ignore as it is expected + } + + + Assert.assertEquals("Unexpected rpc in call back",AppcOam.RPC.stop,cancelCallback.get()); + } + + + + + + + + + /** + * @return true if the negation of the expected value is returned from the supplier within the specified + * amount of time + */ + private static boolean waitForNot(Supplier s,long timeoutMillis)throws Exception{ + return waitFor(()->!s.get(),timeoutMillis); + } + + + /** + * @return true if the expected value is returned from the supplier within the specified + * amount of time + */ + private static boolean waitFor(Supplier s,long timeoutMillis) throws Exception { + long timeout = TimeUnit.MILLISECONDS.toMillis(timeoutMillis); + long expiryTime = System.currentTimeMillis() + timeout; + long elapsedTime; + while(!s.get()){ + elapsedTime = expiryTime - System.currentTimeMillis(); + if(elapsedTime < 1) { + break; + } + Thread.sleep(10); + } + return s.get(); + } + + + /** + * This class is used control a thread executed in th {@link #test()} + */ + @SuppressWarnings("unused") + private static class ExecuteTest { + + + /** A fail safe to insure this TEst does not run indefinitely */ + private final long EXPIRY_TIME = System.currentTimeMillis() + 10000; + + + + /** A thread sets this value to true when it has completed the execution the of executes {@link #test()} */ + private volatile boolean isExecuted = false; + + /** + * A thread sets this value to true when it is actively executing {@link #test()} and back to false when + * it is not + */ + private volatile boolean isExecuting = false; + + /** + * While this value is true, a thread will not be allowed to return from {@link #test()} It will simulate a + * long execution. + */ + private volatile boolean isContinuous = false; + + /** + * When this value is set to true, an ongoing simulation of a long execution of {@link #test()} cannot be force + * to abort via a {@link Thread#interrupt()} + */ + private volatile boolean isIgnoreInterrupt = false; + + + + /** Use to send a signal to the thread executing {@link #notifyTestExcuted(long)} */ + private Semaphore inner = new Semaphore(0); + + /** Use to send a signal to the thread executing {@link #waitForTestExec(long)} */ + private Semaphore outer = new Semaphore(0); + + /** The {@link Future} of the Thread executing {@link #test()}*/ + private volatile Future future; + + /** + * When set the Thread executing {@link #test()} will cancel itself + * @param future - The {@link Future} of the Thread executing {@link #test()} + */ + private void cancelSelfOnNextExecution(Future future) { + this.future = future; + } + + + private boolean isExecuted() { + return isExecuted; + } + + private boolean isExecuting() { + return isExecuting; + } + + + private boolean isContinuous() { + return isContinuous; + } + + + private boolean isIgnoreInterrupt() { + return isIgnoreInterrupt; + } + + + + /** + * The thread executing this method if blocked from returning until the thread executing + * {@link #test()} invokes {@link #notifyTestExcuted(long)} or the specified time elapses + * @param timeoutMillis - the amount of time to wait for a execution iteration. + * @return true if the Thread is released because of an invocation of {@link #notifyTestExcuted(long)} + * @throws InterruptedException - If the Caller thread is interrupted. + */ + private boolean waitForTestExec(long timeoutMillis) throws InterruptedException { + inner.release(); + return outer.tryAcquire(timeoutMillis,TimeUnit.MILLISECONDS); + } + + + /** + * Test simulator + * @return Always returns true. + */ + private Boolean test() { + isTestExpired(); + System.out.println("started"); + isExecuting = true; + try { + if (future != null) { + future.cancel(false); + } + if(!isContinuous){ + notifyTestExcuted(1); + } + + while(isContinuous){ + notifyTestExcuted(100); + isTestExpired(); + } + + } finally { + isExecuting = false; + isExecuted = true; + } + return true; + } + + + /** @throws RuntimeException if the test has bee running too long */ + private void isTestExpired(){ + if(System.currentTimeMillis() > EXPIRY_TIME){ + throw new RuntimeException("Something went wrong the test expired."); + } + } + + + /** + * The thread executing {@link #test()} if blocked from returning until another thread invokes + * {@link #waitForTestExec(long)} or the specified time elapses + * @param timeoutMillis - the amount of time to wait for a execution iteration. + * @return true if the Thread is released because of an invocation of {@link #waitForTestExec(long)} + */ + private boolean notifyTestExcuted(long timeoutMillis){ + try { + boolean acquire = inner.tryAcquire(timeoutMillis,TimeUnit.MILLISECONDS); + if(acquire){ + outer.release(); + System.out.println("release"); + } + } catch (InterruptedException e) { + if(!isIgnoreInterrupt){ + return false; + } + } + return true; + } + } + + + static class Sub { + ExecuteTest et = new ExecuteTest(); + Future future = null; + } + +} -- cgit 1.2.3-korg