From: ToineSiebelink Date: Tue, 16 Dec 2025 17:36:52 +0000 (+0000) Subject: Add (error)simulations to DMI Stub ProvMnS Interface X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F75%2F142775%2F4;p=cps%2Fncmp-dmi-plugin.git Add (error)simulations to DMI Stub ProvMnS Interface - Added Controller Test for easier testing of simulation URI patterns (faster then build & PostMan!) - Add Validator Dependency for latest Springboot - Add timeout and http error simulation based on patterns in FDN - Add info level logging to all stub methods (this might affect k6 performance tests!) - Changed ProvMns interface to allow (any) object be returned for all operation incl. Delete (inline with production interfaces updates) Issue-ID: CPS-3094 Signed-off-by: ToineSiebelink Change-Id: I25d1c660d72bbd2ab929cd66d65e304e6255637c --- diff --git a/dmi-stub/dmi-stub-app/pom.xml b/dmi-stub/dmi-stub-app/pom.xml index ae293d9f..f1f8e9b1 100644 --- a/dmi-stub/dmi-stub-app/pom.xml +++ b/dmi-stub/dmi-stub-app/pom.xml @@ -81,6 +81,32 @@ + + + org.spockframework + spock-core + test + + + org.spockframework + spock-spring + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.codehaus.groovy + groovy + test + + + org.codehaus.groovy + groovy-json + test + @@ -165,4 +191,4 @@ - \ No newline at end of file + diff --git a/dmi-stub/dmi-stub-app/src/test/groovy/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubControllerSpec.groovy b/dmi-stub/dmi-stub-app/src/test/groovy/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubControllerSpec.groovy new file mode 100644 index 00000000..c93d5a93 --- /dev/null +++ b/dmi-stub/dmi-stub-app/src/test/groovy/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubControllerSpec.groovy @@ -0,0 +1,127 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 OpenInfra Foundation Europe. All rights reserved. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.rest.stub.controller + +import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.dmi.provmns.model.ResourceOneOf +import org.onap.cps.ncmp.dmi.rest.stub.utils.Sleeper +import org.spockframework.spring.SpringBean +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest +import org.springframework.http.HttpStatus +import org.springframework.http.MediaType +import org.springframework.test.web.servlet.MockMvc +import org.springframework.validation.Validator +import spock.lang.Specification + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put + +@WebMvcTest(controllers = ProvMnsStubController) +class ProvMnsStubControllerSpec extends Specification { + + @Autowired + MockMvc mockMvc + + @SpringBean + Sleeper sleeper = Mock() + + @Autowired + ObjectMapper objectMapper + + @SpringBean + Validator validator = Mock() + + def 'ProvMnS GET request with #scenario.'() { + given: 'url' + def url = "/ProvMnS/v1/someSegment=1/otherSegment=2/${segmentName}=${segmentValue}/finalSegment=3" + when: 'get request is executed' + def response = mockMvc.perform(get(url)).andReturn().response + then: 'response status is #expectedHttpStatus' + assert response.status == expectedHttpStatus.value() + and: 'content contains the expected json (snippet)' + assert response.getContentAsString().contains(expectedContentSnippet) + where: 'following simulations are applied' + scenario | segmentName | segmentValue || expectedHttpStatus || expectedContentSnippet + 'no simulation' | 'anotherSegment' | 'some value' || HttpStatus.OK || '"objectClass":"dummyClass"' + 'delay 1' | 'dmiSimulation' | 'slowResponse_1' || HttpStatus.OK || '"objectClass":"dummyClass"' + 'http error' | 'dmiSimulation' | 'httpError_418' || HttpStatus.I_AM_A_TEAPOT || '"status":"418"' + } + + def 'ProvMnS PUT request with #scenario.'() { + given: 'url and some resource as body' + def url = "/ProvMnS/v1/someSegment=1/otherSegment=2/${segmentName}=${segmentValue}/finalSegment=3" + def requestBody = objectMapper.writeValueAsString(new ResourceOneOf('myId')) + when: 'put request is executed' + def response = mockMvc.perform(put(url) + .contentType(MediaType.APPLICATION_JSON) + .content(requestBody)) + .andReturn().response + then: 'response status is #expectedHttpStatus' + assert response.status == expectedHttpStatus.value() + and: 'content contains the expected json (snippet)' + assert response.getContentAsString().contains(expectedContentSnippet) + where: 'following simulations are applied' + scenario | segmentName | segmentValue || expectedHttpStatus || expectedContentSnippet + 'no simulation' | 'anotherSegment' | 'some value' || HttpStatus.OK || '"id":"myId"' + 'delay 1' | 'dmiSimulation' | 'slowResponse_1' || HttpStatus.OK || '"id":"myId"' + 'http error' | 'dmiSimulation' | 'httpError_418' || HttpStatus.I_AM_A_TEAPOT || '"status":"418"' + } + + def 'ProvMnS PATCH request with #scenario.'() { + given: 'url and some resource as body' + def url = "/ProvMnS/v1/someSegment=1/otherSegment=2/${segmentName}=${segmentValue}/finalSegment=3" + def requestBody = objectMapper.writeValueAsString(new ResourceOneOf('myId')) + when: 'patch request is executed' + def response = mockMvc.perform(patch(url) + .contentType("application/json-patch+json") + .content(requestBody)) + .andReturn().response + then: 'response status is #expectedHttpStatus' + assert response.status == expectedHttpStatus.value() + and: 'content contains the expected json (snippet)' + assert response.getContentAsString().contains(expectedContentSnippet) + where: 'following simulations are applied' + scenario | segmentName | segmentValue || expectedHttpStatus || expectedContentSnippet + 'no simulation' | 'anotherSegment' | 'some value' || HttpStatus.OK || '"id":"myId"' + 'delay 1' | 'dmiSimulation' | 'slowResponse_1' || HttpStatus.OK || '"id":"myId"' + 'http error' | 'dmiSimulation' | 'httpError_418' || HttpStatus.I_AM_A_TEAPOT || '"status":"418"' + } + + def 'ProvMnS DELETE request with #scenario.'() { + given: 'url' + def url = "/ProvMnS/v1/someSegment=1/otherSegment=2/${segmentName}=${segmentValue}/finalSegment=3" + when: 'delete request is executed' + def response = mockMvc.perform(delete(url)).andReturn().response + then: 'response status is #expectedHttpStatus' + assert response.status == expectedHttpStatus.value() + and: 'content only contains anything in case of an http error' + assert response.getContentAsString().contains(expectedContentSnippet) + where: 'following simulations are applied' + scenario | segmentName | segmentValue || expectedHttpStatus || expectedContentSnippet + 'no simulation' | 'anotherSegment' | 'some value' || HttpStatus.OK || '' + 'delay 1' | 'dmiSimulation' | 'slowResponse_1' || HttpStatus.OK || '' + 'http error' | 'dmiSimulation' | 'httpError_418' || HttpStatus.I_AM_A_TEAPOT || '"status":"418"' + } + +} diff --git a/dmi-stub/dmi-stub-service/pom.xml b/dmi-stub/dmi-stub-service/pom.xml index a8d1abd4..58d5d822 100644 --- a/dmi-stub/dmi-stub-service/pom.xml +++ b/dmi-stub/dmi-stub-service/pom.xml @@ -62,6 +62,10 @@ org.springframework.boot spring-boot-starter-actuator + + org.springframework.boot + spring-boot-starter-validation + com.googlecode.json-simple json-simple @@ -138,7 +142,6 @@ groovy-json test - @@ -180,4 +183,4 @@ - \ No newline at end of file + diff --git a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/provmns/api/ProvMnS.java b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/provmns/api/ProvMnS.java index 4ac21518..68a5b3df 100644 --- a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/provmns/api/ProvMnS.java +++ b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/provmns/api/ProvMnS.java @@ -74,7 +74,7 @@ public interface ProvMnS { value = "v1/**", produces = { "application/json" } ) - ResponseEntity deleteMoi(HttpServletRequest httpServletRequest); + ResponseEntity deleteMoi(HttpServletRequest httpServletRequest); /** @@ -127,7 +127,7 @@ public interface ProvMnS { produces = { "application/json"} ) - ResponseEntity getMoi( + ResponseEntity getMoi( HttpServletRequest httpServletRequest, @Parameter(name = "scope", description = "This parameter extends the set of targeted resources beyond the " + "base resource identified with the path component of the URI. " @@ -199,7 +199,7 @@ public interface ProvMnS { consumes = {"application/json-patch+json", "application/3gpp-json-patch+json" } ) - ResponseEntity patchMoi( + ResponseEntity patchMoi( HttpServletRequest httpServletRequest, @Parameter(name = "Resource", description = "The request body describes changes to be made to the target " + "resources. The following patch media types are available " @@ -263,7 +263,7 @@ public interface ProvMnS { consumes = { "application/json" } ) - ResponseEntity putMoi( + ResponseEntity putMoi( HttpServletRequest httpServletRequest, @Parameter(name = "Resource", description = "", required = true) @Valid @RequestBody Resource resource ); diff --git a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java index 33975b0d..9e26d80f 100644 --- a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java +++ b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/DmiRestStubController.java @@ -110,6 +110,7 @@ public class DmiRestStubController { */ @PostMapping("/v1/tagMapping") public ResponseEntity> addTagForMapping(@RequestBody final Map requestBody) { + log.info("tagMapping: add {}", requestBody); moduleSetTagPerCmHandleId.putAll(requestBody); return new ResponseEntity<>(requestBody, HttpStatus.CREATED); } @@ -120,7 +121,8 @@ public class DmiRestStubController { * @return The map represents the module set tag mapping. */ @GetMapping("/v1/tagMapping") - public ResponseEntity> getTagMapping() { + public ResponseEntity> getTagMapping() { + log.info("tagMapping: get"); return ResponseEntity.ok(moduleSetTagPerCmHandleId); } @@ -131,6 +133,7 @@ public class DmiRestStubController { */ @GetMapping("/v1/tagMapping/ch/{cmHandleId}") public ResponseEntity getTagMappingByCmHandleId(@PathVariable final String cmHandleId) { + log.info("tagMapping: get cm handle id: {}", cmHandleId); return ResponseEntity.ok(moduleSetTagPerCmHandleId.get(cmHandleId)); } @@ -145,6 +148,7 @@ public class DmiRestStubController { @PutMapping("/v1/tagMapping") public ResponseEntity> updateTagMapping(@RequestBody final Map requestBody) { + log.info("tagMapping: update: {}", requestBody); moduleSetTagPerCmHandleId.putAll(requestBody); return ResponseEntity.noContent().build(); } @@ -157,6 +161,7 @@ public class DmiRestStubController { */ @DeleteMapping("/v1/tagMapping/ch/{cmHandleId}") public ResponseEntity deleteTagMappingByCmHandleId(@PathVariable final String cmHandleId) { + log.info("tagMapping: remove cm handle id: {}", cmHandleId); moduleSetTagPerCmHandleId.remove(cmHandleId); return ResponseEntity.ok(String.format("Mapping of %s is deleted successfully", cmHandleId)); } @@ -173,6 +178,7 @@ public class DmiRestStubController { @ModuleInitialProcess public ResponseEntity getModuleReferences(@PathVariable("cmHandleId") final String cmHandleId, @RequestBody final Object moduleReferencesRequest) { + log.info("get module references for cm handle id: {}", cmHandleId); return processModuleRequest(moduleReferencesRequest, MODULE_REFERENCE_RESPONSE, moduleReferencesDelayMs); } @@ -189,6 +195,7 @@ public class DmiRestStubController { public ResponseEntity getModuleResources( @PathVariable("cmHandleId") final String cmHandleId, @RequestBody final Object moduleResourcesReadRequest) { + log.info("get module resources for cm handle id: {}", cmHandleId); return processModuleRequest(moduleResourcesReadRequest, MODULE_RESOURCE_RESPONSE, moduleResourcesDelayMs); } @@ -212,6 +219,7 @@ public class DmiRestStubController { @RequestParam(value = "topic", required = false) final String topic, @RequestHeader(value = "Authorization", required = false) final String authorization, @RequestBody final String requestBody) { + log.info("create resource data for cm handle id: {}", cmHandleId); log.debug("DMI AUTH HEADER: {}", authorization); final String passthroughOperationType = getPassthroughOperationType(requestBody); if (passthroughOperationType.equals("read")) { @@ -241,7 +249,7 @@ public class DmiRestStubController { @RequestBody final DmiDataOperationRequest dmiDataOperationRequest) { delay(writeDataForCmHandleDelayMs); try { - log.debug("Request received from the NCMP to DMI Plugin: {}", + log.info("Request received from the NCMP to DMI Plugin: {}", objectMapper.writeValueAsString(dmiDataOperationRequest)); } catch (final JsonProcessingException jsonProcessingException) { log.warn("Unable to process dmi data operation request to json string"); @@ -269,8 +277,9 @@ public class DmiRestStubController { public ResponseEntity consumeWriteSubJobs( @RequestBody final SubjobWriteRequest subJobWriteRequest, @RequestParam("destination") final String destination) { - log.debug("Destination: {}", destination); - log.debug("Request body: {}", subJobWriteRequest); + log.info("cm write (datajob) request"); + log.info("Destination: {}", destination); + log.info("Request body: {}", subJobWriteRequest); return ResponseEntity.ok(new SubjobWriteResponse(String.valueOf(subJobWriteRequestCounter.incrementAndGet()), "some-dmi-service-name", "my-data-producer-id")); } @@ -287,7 +296,7 @@ public class DmiRestStubController { public ResponseEntity> retrieveDataJobStatus( @PathVariable("dataProducerId") final String dataProducerId, @PathVariable("dataProducerJobId") final String dataProducerJobId) { - log.debug("Received request to retrieve data job status. Request ID: {}, Data Producer Job ID: {}", + log.info("Received request to retrieve data job status. Request ID: {}, Data Producer Job ID: {}", dataProducerId, dataProducerJobId); return ResponseEntity.ok(Map.of("status", "FINISHED")); } @@ -305,7 +314,7 @@ public class DmiRestStubController { @PathVariable("dataProducerId") final String dataProducerId, @PathVariable("dataProducerJobId") final String dataProducerJobId, @RequestParam(name = "destination") final String destination) { - log.debug("Received request to retrieve data job result. Data Producer ID: {}, " + log.info("Received request to retrieve data job result. Data Producer ID: {}, " + "Data Producer Job ID: {}, Destination: {}", dataProducerId, dataProducerJobId, destination); return ResponseEntity.ok(Map.of("result", "some status")); diff --git a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubController.java b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubController.java index 435f1eb8..25fb51c4 100644 --- a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubController.java +++ b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/controller/ProvMnsStubController.java @@ -20,15 +20,21 @@ package org.onap.cps.ncmp.dmi.rest.stub.controller; - import jakarta.servlet.http.HttpServletRequest; +import java.util.Collections; import java.util.List; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.dmi.provmns.api.ProvMnS; import org.onap.cps.ncmp.dmi.provmns.model.ClassNameIdGetDataNodeSelectorParameter; +import org.onap.cps.ncmp.dmi.provmns.model.ErrorResponseDefault; import org.onap.cps.ncmp.dmi.provmns.model.Resource; import org.onap.cps.ncmp.dmi.provmns.model.ResourceOneOf; import org.onap.cps.ncmp.dmi.provmns.model.Scope; +import org.onap.cps.ncmp.dmi.rest.stub.utils.Sleeper; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; @@ -37,19 +43,36 @@ import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("${rest.api.provmns-base-path}") @RequiredArgsConstructor +@Slf4j public class ProvMnsStubController implements ProvMnS { + static final ResourceOneOf dummyResource = new ResourceOneOf("some id"); + + static final Pattern PATTERN_SIMULATION = Pattern.compile("dmiSimulation=(\\w+_\\d{1,3})"); + static final Pattern PATTERN_HTTP_ERROR = Pattern.compile("httpError_(\\d{3})"); + static final Pattern PATTERN_SLOW_RESPONSE = Pattern.compile("slowResponse_(\\d{1,3})"); + + private final Sleeper sleeper; + + static { + dummyResource.setObjectClass("dummyClass"); + dummyResource.setObjectInstance("dummyInstance"); + dummyResource.setAttributes(Collections.singletonMap("dummyAttribute", "dummy value")); + } + /** * Replaces a complete single resource or creates it if it does not exist. * * @param httpServletRequest URI request including path * @param resource Resource representation of the resource to be created or replaced - * @return {@code ResponseEntity} The representation of the updated resource is returned in the response + * @return {@code Object} The representation of the updated resource is returned in the response * message body. */ @Override - public ResponseEntity putMoi(final HttpServletRequest httpServletRequest, final Resource resource) { - return new ResponseEntity<>(resource, HttpStatus.OK); + public ResponseEntity putMoi(final HttpServletRequest httpServletRequest, final Resource resource) { + log.info("putMoi: {}", resource); + final Optional> optionalResponseEntity = simulate(httpServletRequest); + return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(resource, HttpStatus.OK)); } /** @@ -73,11 +96,14 @@ public class ProvMnsStubController implements ProvMnS { * in the response message body. */ @Override - public ResponseEntity getMoi(final HttpServletRequest httpServletRequest, final Scope scope, + public ResponseEntity getMoi(final HttpServletRequest httpServletRequest, final Scope scope, final String filter, final List attributes, final List fields, final ClassNameIdGetDataNodeSelectorParameter dataNodeSelector) { - return new ResponseEntity<>(new ResourceOneOf("exampleResourceId"), HttpStatus.OK); + log.info("getMoi: scope: {}, filter: {}, attributes: {}, fields: {}, dataNodeSelector: {}", + scope, filter, attributes, fields, dataNodeSelector); + final Optional> optionalResponseEntity = simulate(httpServletRequest); + return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(dummyResource, HttpStatus.OK)); } /** @@ -88,8 +114,10 @@ public class ProvMnsStubController implements ProvMnS { * @return {@code ResponseEntity} The updated resource representations are returned in the response message body. */ @Override - public ResponseEntity patchMoi(final HttpServletRequest httpServletRequest, final Resource resource) { - return new ResponseEntity<>(resource, HttpStatus.OK); + public ResponseEntity patchMoi(final HttpServletRequest httpServletRequest, final Resource resource) { + log.info("patchMoi: {}", resource); + final Optional> optionalResponseEntity = simulate(httpServletRequest); + return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(resource, HttpStatus.OK)); } /** @@ -99,7 +127,44 @@ public class ProvMnsStubController implements ProvMnS { * @return {@code ResponseEntity} The response body is empty, HTTP status returned. */ @Override - public ResponseEntity deleteMoi(final HttpServletRequest httpServletRequest) { - return new ResponseEntity<>(HttpStatus.OK); + public ResponseEntity deleteMoi(final HttpServletRequest httpServletRequest) { + log.info("deleteMoi:"); + final Optional> optionalResponseEntity = simulate(httpServletRequest); + return optionalResponseEntity.orElseGet(() -> new ResponseEntity<>(HttpStatus.OK)); } + + private Optional> simulate(final HttpServletRequest httpServletRequest) { + Matcher matcher = PATTERN_SIMULATION.matcher(httpServletRequest.getRequestURI()); + if (matcher.find()) { + final String simulation = matcher.group(1); + matcher = PATTERN_SLOW_RESPONSE.matcher(simulation); + if (matcher.matches()) { + haveALittleRest(Integer.parseInt(matcher.group(1))); + } + matcher = PATTERN_HTTP_ERROR.matcher(simulation); + if (matcher.matches()) { + return Optional.of(createErrorRsponseEntity(Integer.parseInt(matcher.group(1)))); + } + } + return Optional.empty(); + } + + private void haveALittleRest(final int durationInSeconds) { + log.warn("Stub is mocking slow response; delay {} seconds", durationInSeconds); + try { + sleeper.haveALittleRest(durationInSeconds); + } catch (final InterruptedException e) { + log.trace("Sleep interrupted, re-interrupting the thread"); + Thread.currentThread().interrupt(); + } + } + + private static ResponseEntity createErrorRsponseEntity(final int errorCode) { + log.warn("Stub is mocking an error response, code: {}", errorCode); + final ErrorResponseDefault errorResponseDefault = new ErrorResponseDefault("ERROR_FROM_STUB"); + errorResponseDefault.setTitle("Title set by Stub"); + errorResponseDefault.setStatus(String.valueOf(errorCode)); + return new ResponseEntity<>(errorResponseDefault, HttpStatus.valueOf(errorCode)); + } + } diff --git a/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/Sleeper.java b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/Sleeper.java new file mode 100644 index 00000000..c100e314 --- /dev/null +++ b/dmi-stub/dmi-stub-service/src/main/java/org/onap/cps/ncmp/dmi/rest/stub/utils/Sleeper.java @@ -0,0 +1,35 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 OpenInfra Foundation Europe + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.cps.ncmp.dmi.rest.stub.utils; + +import java.util.concurrent.TimeUnit; +import org.springframework.stereotype.Component; + +/** + * This class is to extract out sleep functionality so the interrupted exception handling can + * be covered with a test (e.g. using spy on Sleeper) and help to get too 100% code coverage. + */ +@Component +public class Sleeper { + public void haveALittleRest(final int durationInSeconds) throws InterruptedException { + TimeUnit.SECONDS.sleep(durationInSeconds); + } +}