diff options
Diffstat (limited to 'vid-automation/src/main/java/org/onap/vid/api')
6 files changed, 1256 insertions, 0 deletions
diff --git a/vid-automation/src/main/java/org/onap/vid/api/AsyncInstantiationBase.java b/vid-automation/src/main/java/org/onap/vid/api/AsyncInstantiationBase.java new file mode 100644 index 000000000..2a6b012fe --- /dev/null +++ b/vid-automation/src/main/java/org/onap/vid/api/AsyncInstantiationBase.java @@ -0,0 +1,573 @@ +package org.onap.vid.api; + +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; +import static java.util.Collections.emptyList; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toMap; +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.hasSize; +import static org.onap.simulator.presetGenerator.presets.mso.PresetMSOServiceInstanceGen2WithNames.Keys; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertEquals; +import static org.testng.AssertJUnit.assertTrue; +import static vid.automation.test.utils.ExtendedHamcrestMatcher.hasItemsFromCollection; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.util.concurrent.Uninterruptibles; +import java.time.Instant; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import org.hamcrest.BaseMatcher; +import org.hamcrest.CoreMatchers; +import org.hamcrest.Description; +import org.hamcrest.MatcherAssert; +import org.onap.simulator.presetGenerator.presets.BasePresets.BaseMSOPreset; +import org.onap.simulator.presetGenerator.presets.BasePresets.BasePreset; +import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetCloudOwnersByCloudRegionId; +import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetSubscribersGet; +import org.onap.simulator.presetGenerator.presets.ecompportal_att.PresetGetSessionSlotCheckIntervalGet; +import org.onap.simulator.presetGenerator.presets.mso.PresetMSOBaseCreateInstancePost; +import org.onap.simulator.presetGenerator.presets.mso.PresetMSOBaseDelete; +import org.onap.simulator.presetGenerator.presets.mso.PresetMSOCreateServiceInstanceGen2WithNames; +import org.onap.simulator.presetGenerator.presets.mso.PresetMSOOrchestrationRequestGet; +import org.onap.vid.model.asyncInstantiation.JobAuditStatus; +import org.onap.vid.model.asyncInstantiation.ServiceInfo; +import org.onap.vid.model.mso.MsoResponseWrapper2; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import vid.automation.test.infra.Features; +import vid.automation.test.infra.Wait; +import vid.automation.test.model.JobStatus; +import vid.automation.test.model.ServiceAction; +import vid.automation.test.services.AsyncJobsService; +import vid.automation.test.services.SimulatorApi; + +public class AsyncInstantiationBase extends BaseMsoApiTest { + + public static final String CREATE_BULK_OF_ALACARTE_REQUEST_WITH_VNF = "asyncInstantiation/vidRequestCreateALaCarteWithVnf.json"; + protected static final String CREATE_BULK_OF_MACRO_REQUEST = "asyncInstantiation/vidRequestCreateBulkOfMacro.json"; + + protected static final String MSO_BASE_ERROR = + "Received error from SDN-C: java.lang.IllegalArgumentException: All keys must be specified for class org."+ + "opendaylight.yang.gen.v1.org.onap.sdnc.northbound.generic.resource.rev170824.vf.module.assignments.vf."+ + "module.assignments.vms.VmKey. Missing key is getVmType. Supplied key is VmKey []."; + protected static final String MSO_ERROR = MSO_BASE_ERROR + StringUtils.repeat(" and a lot of sentences for long message", 60); + + @BeforeClass + protected void muteAndDropNameCounter() { + AsyncJobsService asyncJobsService = new AsyncJobsService(); + asyncJobsService.muteAllAsyncJobs(); + asyncJobsService.dropAllFromNameCounter(); + } + + @AfterMethod + protected void muteAllAsyncJobs() { + AsyncJobsService asyncJobsService = new AsyncJobsService(); + asyncJobsService.muteAllAsyncJobs(); + } + + @DataProvider + public static Object[][] trueAndFalse() { + return new Object[][]{{TRUE},{FALSE}}; + } + + protected String getCreateBulkUri() { + return uri.toASCIIString() + "/asyncInstantiation/bulk"; + } + + protected String getHideServiceUri(String jobId) { + return uri.toASCIIString() + "/asyncInstantiation/hide/"+jobId; + } + + protected String getServiceInfoUrl() { + return uri.toASCIIString() + "/asyncInstantiation"; + } + + protected String getJobAuditUrl() { + return uri.toASCIIString() + "/asyncInstantiation/auditStatus/{JOB_ID}?source={SOURCE}"; + } + + protected String getMsoJobAuditUrl() { + return uri.toASCIIString() + "/asyncInstantiation/auditStatus/{JOB_ID}/mso"; + } + + protected String getDeleteServiceUrl(String uuid) { + return uri.toASCIIString() + "/asyncInstantiation/job/" + uuid; + } + + protected String getInstanceAuditInfoUrl() { + return uri.toASCIIString() + "/asyncInstantiation/auditStatus/{TYPE}/{INSTANCE_ID}/mso"; + } + + protected String getRetryJobUrl() { + return uri.toASCIIString() + "/asyncInstantiation/retry/{JOB_ID}"; + } + protected String getTopologyForRetryUrl() { + return uri.toASCIIString() + "/asyncInstantiation/bulkForRetry/{JOB_ID}"; + } + + + protected String getRetryJobWithChangedDataUrl() { + return uri.toASCIIString() + "/asyncInstantiation/retryJobWithChangedData/{JOB_ID}"; + } + + protected boolean getExpectedRetryEnabled(JobStatus jobStatus) { + return Features.FLAG_1902_RETRY_JOB.isActive() && (jobStatus==JobStatus.FAILED || jobStatus==JobStatus.COMPLETED_WITH_ERRORS); + } + + public List<BasePreset> getPresets(List<PresetMSOBaseDelete> presetOnDeleteList, List<PresetMSOBaseCreateInstancePost> presetOnCreateList, List<PresetMSOOrchestrationRequestGet> presetInProgressList) { + + final ImmutableList.Builder<BasePreset> basePresetBuilder = new ImmutableList.Builder<>(); + basePresetBuilder + .add(new PresetGetSessionSlotCheckIntervalGet()) + .add(new PresetAAIGetSubscribersGet()) + .addAll(presetOnDeleteList) + .addAll(presetOnCreateList) + .addAll(presetInProgressList); + return basePresetBuilder.build(); + } + + public List<BasePreset> getDeletePresets(List<PresetMSOBaseDelete> presetOnDeleteList, List<PresetMSOOrchestrationRequestGet> presetInProgressList) { + return getPresets(presetOnDeleteList, emptyList(), presetInProgressList); + } + + public List<BasePreset> getPresets(List<PresetMSOBaseCreateInstancePost> presetOnCreateList, List<PresetMSOOrchestrationRequestGet> presetInProgressList) { + return getPresets(emptyList(), presetOnCreateList, presetInProgressList); + } + + public void assertServiceInfoSpecific1(String jobId, JobStatus jobStatus, String serviceInstanceName, String userName) { + assertServiceInfoSpecific1(jobId, jobStatus, serviceInstanceName, userName, null, ServiceAction.INSTANTIATE); + } + + public void assertServiceInfoSpecific1(String jobId, JobStatus jobStatus, String serviceInstanceName, String userName, String instanceId, ServiceAction action) { + assertExpectedStatusAndServiceInfo(jobStatus, jobId, new ServiceInfo( + userName, jobStatus, false, + "038d99af-0427-42c2-9d15-971b99b9b489", "Lucine Sarika", "zasaki", + "de738e5f-3704-4a14-b98f-3bf86ac0c0a0", "voloyakane-senamo", + "c85f0e80-0636-44a4-8cb2-4ec00d056e79", "Hedvika Wendelin", + "a93f8383-707e-43fa-8191-a6e69a1aab17", null, + "TYLER SILVIA", "SILVIA ROBBINS", + instanceId, serviceInstanceName, + "e3c34d88-a216-4f1d-a782-9af9f9588705", "gayawabawe", "5.1", + jobId, null, action, false) + ); + } + + public void assertServiceInfoSpecific1(String jobId, JobStatus jobStatus, String serviceInstanceName) { + assertServiceInfoSpecific1(jobId, jobStatus, serviceInstanceName, "us16807000"); + } + + protected void assertAuditStatuses(String jobId, List<JobAuditStatus> expectedVidStatuses, List<JobAuditStatus> expectedMsoStatuses) { + assertAuditStatuses(jobId, expectedVidStatuses, expectedMsoStatuses, 15); + } + + protected void assertAuditStatuses(String jobId, List<JobAuditStatus> expectedVidStatuses, List<JobAuditStatus> expectedMsoStatuses, long timeoutInSeconds) { + assertAndRetryIfNeeded(() -> { + final List<JobAuditStatus> auditVidStatuses = getAuditStatuses(jobId, JobAuditStatus.SourceStatus.VID.name()); + assertThat(auditVidStatuses, hasItemsFromCollection(expectedVidStatuses)); + if (expectedMsoStatuses!=null) { + final List<JobAuditStatus> auditMsoStatuses = getAuditStatuses(jobId, JobAuditStatus.SourceStatus.MSO.name()); + assertThat(auditMsoStatuses, containsInAnyOrder(expectedMsoStatuses.toArray())); + } + }, timeoutInSeconds); + } + + protected void assertAndRetryIfNeeded(Runnable asserter, long timeoutInSeconds) { + final Instant expiry = Instant.now().plusSeconds(timeoutInSeconds); + while (true) { + try { + asserter.run(); + break; // we're cool, assertion passed + } catch (AssertionError fail) { + Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS); + if (Instant.now().isAfter(expiry)) { + throw fail; + } else { + System.out.println("retrying after: " + fail); + } + } + } + } + + protected ImmutableList<JobAuditStatus> vidAuditStatusesCompletedWithErrors(String jobId) { + return ImmutableList.of( + vidAuditStatus(jobId, "PENDING", false), + vidAuditStatus(jobId, "IN_PROGRESS", false), + vidAuditStatus(jobId, "COMPLETED_WITH_ERRORS", true) + ); + } + + protected ImmutableList<JobAuditStatus> vidAuditStatusesFailed(String jobId) { + return ImmutableList.of( + vidAuditStatus(jobId, "PENDING", false), + vidAuditStatus(jobId, "IN_PROGRESS", false), + vidAuditStatus(jobId, "FAILED", true) + ); + } + + protected JobAuditStatus vidAuditStatus(String jobId, String jobStatus, boolean isFinal) { + return new JobAuditStatus(UUID.fromString(jobId), jobStatus, JobAuditStatus.SourceStatus.VID, null, null, isFinal); + } + + public static class JobIdAndStatusMatcher extends BaseMatcher<ServiceInfo> { + protected String expectedJobId; + + public JobIdAndStatusMatcher(String expectedJobId) { + this.expectedJobId = expectedJobId; + } + + @Override + public boolean matches(Object item) { + if (!(item instanceof ServiceInfo)) { + return false; + } + ServiceInfo serviceInfo = (ServiceInfo) item; + return expectedJobId.equals(serviceInfo.jobId); + } + + @Override + public void describeTo(Description description) { + description.appendText("failed to find job with uuid ") + .appendValue(expectedJobId); + } + } + + + + protected Map<Keys,String> generateNames() { + return Stream.of(Keys.values()).collect( + Collectors.toMap(x->x, x -> UUID.randomUUID().toString().replace("-",""))); + } + + protected ImmutableList<BasePreset> addPresetsForCreateBulkOfCreateInstances(int bulkSize, Map<Keys, String> names){ + ImmutableList<BasePreset> msoBulkPresets = generateMsoCreateBulkPresets(bulkSize, names); + ImmutableList<BasePreset> presets = new ImmutableList.Builder<BasePreset>() + .add(new PresetGetSessionSlotCheckIntervalGet()) + .add(new PresetAAIGetSubscribersGet()) + .add(PresetAAIGetCloudOwnersByCloudRegionId.PRESET_MTN3_TO_ATT_SABABA) + .addAll(msoBulkPresets) + .add(new PresetMSOOrchestrationRequestGet()) + .build(); + return presets; + + } + + protected ImmutableList<BasePreset> generateMsoCreateBulkPresets(int bulkSize, Map<Keys, String> names) { + return IntStream.rangeClosed(0, bulkSize-1). + mapToObj(i-> new PresetMSOCreateServiceInstanceGen2WithNames(names, i)) + .collect(ImmutableList.toImmutableList()); + } + + protected ResponseEntity<List<JobAuditStatus>> auditStatusCall(String url) { + return restTemplate.exchange( + url, + org.springframework.http.HttpMethod.GET, + null, + new ParameterizedTypeReference<List<JobAuditStatus>>() {}); + } + + @DataProvider + public static Object[][] auditSources() { + return new Object[][]{{JobAuditStatus.SourceStatus.VID},{JobAuditStatus.SourceStatus.MSO}}; + } + + + + protected List<String> createBulkAndWaitForBeCompleted(int bulkSize){ + Map<Keys, String> names = generateNames(); + ImmutableList<BasePreset> presets = addPresetsForCreateBulkOfCreateInstances(bulkSize, names); + final List<String> jobIds = createBulkOfMacroInstances(presets, false, bulkSize, names); + Assert.assertEquals(jobIds.size(),bulkSize); + + assertTrue(String.format("Not all services with ids: %s are in state completed after 30 sec", + jobIds.stream().collect(joining(","))), + + Wait.waitFor(y-> serviceListCall().getBody().stream() + .filter(si -> jobIds.contains(si.jobId)) + .filter(si -> si.jobStatus==JobStatus.COMPLETED) + .count() == bulkSize, + null, 30, 1 )); + return jobIds; + } + + protected List<JobAuditStatus> getJobMsoAuditStatusForAlaCarte(String jobUUID, String requestId, String serviceInstanceId){ + String url = getMsoJobAuditUrl().replace("{JOB_ID}",jobUUID); + + if(!StringUtils.isEmpty(requestId)) { + url = url + "?requestId=" + requestId; + if(!StringUtils.isEmpty(serviceInstanceId)) { + url = url + "&serviceInstanceId=" + serviceInstanceId; + } + } + return callAuditStatus(url); + } + + protected List<JobAuditStatus> getAuditStatuses(String jobUUID, String source){ + String url = getJobAuditUrl().replace("{JOB_ID}",jobUUID).replace("{SOURCE}", source); + return callAuditStatus(url); + } + + protected List<JobAuditStatus> getAuditStatusesForInstance(String type, String instanceId){ + String url = getInstanceAuditInfoUrl().replace("{TYPE}",type).replace("{INSTANCE_ID}", instanceId); + return callAuditStatus(url); + } + + private List<JobAuditStatus> callAuditStatus(String url) { + ResponseEntity<List<JobAuditStatus>> statusesResponse = auditStatusCall(url); + assertThat(statusesResponse.getStatusCode(), CoreMatchers.equalTo(HttpStatus.OK)); + return statusesResponse.getBody(); + } + + protected Map<String, JobStatus> addBulkAllPendingButOneInProgress(){ + return addBulkAllPendingButOneInProgress(3); + } + + protected Map<String, JobStatus> addBulkAllPendingButOneInProgress(int bulkSize){ + Map<Keys, String> names = generateNames(); + ImmutableList<BasePreset> msoBulkPresets = generateMsoCreateBulkPresets(bulkSize, names); + ImmutableList<BasePreset> presets = new ImmutableList.Builder<BasePreset>() + .add(new PresetGetSessionSlotCheckIntervalGet()) + .add(new PresetAAIGetSubscribersGet()) + .add(PresetAAIGetCloudOwnersByCloudRegionId.PRESET_MTN3_TO_ATT_SABABA) + .addAll(msoBulkPresets) + .add(new PresetMSOOrchestrationRequestGet("IN_PROGRESS")) + .build(); + final List<String> jobIds = createBulkOfMacroInstances(presets, false, bulkSize, names); + + // wait for single IN_PROGRESS, so statuses will stop from changing + Wait.waitFor(foo -> serviceListCall().getBody().stream() + .filter(si -> jobIds.contains(si.jobId)) + .anyMatch(si -> si.jobStatus.equals(JobStatus.IN_PROGRESS)), + null, 20, 1); + + final Map<String, JobStatus> statusMapBefore = serviceListCall().getBody().stream() + .filter(si -> jobIds.contains(si.jobId)) + .collect(toMap(si -> si.jobId, si -> si.jobStatus)); + + assertThat(jobIds, hasSize(bulkSize)); + + + return statusMapBefore; + } + + protected String deleteOneJobHavingTheStatus(Map<String, JobStatus> jobIdToStatus, JobStatus jobStatus) { + final String jobToDelete = jobIdToStatus.entrySet().stream() + .filter(entry -> entry.getValue().equals(jobStatus)) + .map(Map.Entry::getKey) + .findFirst().orElseThrow(() -> new AssertionError("no job in " + jobStatus + " state: " + jobIdToStatus)); + + + restTemplate.delete(getDeleteServiceUrl(jobToDelete)); + + return jobToDelete; + } + + + protected MsoResponseWrapper2 hideService(String jobId) { + MsoResponseWrapper2 responseWrapper2 = callMsoForResponseWrapper(org.springframework.http.HttpMethod.POST, getHideServiceUri(jobId), ""); + return responseWrapper2; + } + + protected List<String> createBulkOfInstancesAndAssert(ImmutableList<BasePreset> presets, boolean isPause, int bulkSize, JobStatus finalState, Map<Keys, String> names){ + List<String> jobIds = createBulkOfMacroInstances(presets, isPause, bulkSize, names); + Assert.assertEquals(jobIds.size(), bulkSize); + for(String jobId: jobIds) { + assertExpectedStatusAndServiceInfo(isPause, finalState, names, jobId); + } + + return jobIds; + } + + protected void assertExpectedStatusAndServiceInfo(boolean isPause, JobStatus finalState, Map<Keys, String> names, String jobId) { + assertExpectedStatusAndServiceInfo(finalState, jobId, new ServiceInfo("us16807000", JobStatus.IN_PROGRESS, isPause, "someID", + "someName", "myProject", "NFT1", "NFTJSSSS-NFT1", "greatTenant", "greatTenant", "hvf3", null, + "mySubType", "a9a77d5a-123e-4ca2-9eb9-0b015d2ee0fb", null, names.get(Keys.SERVICE_NAME), + "5c9e863f-2716-467b-8799-4a67f378dcaa", "AIM_TRANSPORT_00004", "1.0", jobId, null, ServiceAction.INSTANTIATE, false)); + } + + protected void assertExpectedStatusAndServiceInfo(JobStatus finalState, String jobId, ServiceInfo expectedServiceInfo) { + assertExpectedStatusAndServiceInfo(finalState, jobId, false, expectedServiceInfo); + } + + protected void assertExpectedStatusAndServiceInfo(JobStatus finalState, String jobId, boolean longWait, ServiceInfo expectedServiceInfo) { + JobInfoChecker<Integer> jobInfoChecker = new JobInfoChecker<>( + restTemplate, ImmutableSet.of(JobStatus.PENDING, JobStatus.IN_PROGRESS, finalState), jobId, expectedServiceInfo); + boolean result = jobInfoChecker.test(null); + assertTrue("service info of jobId: " + jobId + " was in status: " + jobInfoChecker.lastStatus, result); + + jobInfoChecker.setExpectedJobStatus(ImmutableSet.of(finalState)); + if (ImmutableList.of(JobStatus.COMPLETED, JobStatus.PAUSE).contains(finalState) && expectedServiceInfo.serviceInstanceId==null) { + expectedServiceInfo.serviceInstanceId = BaseMSOPreset.DEFAULT_INSTANCE_ID; + } + result = Wait.waitFor(jobInfoChecker, null, 30, longWait ? 2 : 1); + assertTrue("service info of jobId: " + jobId + " was in status: " + jobInfoChecker.lastStatus, result); + } + + protected List<String> createBulkOfMacroInstances(ImmutableList<BasePreset> presets, boolean isPause, int bulkSize, Map<Keys, String> names) { + SimulatorApi.registerExpectationFromPresets(presets, SimulatorApi.RegistrationStrategy.CLEAR_THEN_SET); + return createBulkOfInstances(isPause, bulkSize, names, CREATE_BULK_OF_MACRO_REQUEST); + } + + public List<String> createBulkOfInstances(boolean isPause, int bulkSize, Map<Keys, String> names, String requestDetailsFileName){ + + String requestBody = TestUtils.convertRequest(objectMapper, requestDetailsFileName); + requestBody = requestBody.replace("\"IS_PAUSE_VALUE\"", String.valueOf(isPause)).replace("\"BULK_SIZE\"", String.valueOf(bulkSize)); + for (Map.Entry<Keys, String> e : names.entrySet()) { + requestBody = requestBody.replace(e.getKey().name(), e.getValue()); + } + MsoResponseWrapper2 responseWrapper2 = callMsoForResponseWrapper(org.springframework.http.HttpMethod.POST, getCreateBulkUri(), requestBody); + assertNotNull(responseWrapper2); + return (List<String>)responseWrapper2.getEntity(); + } + + protected List<String> retryJob(String jobId) { + ResponseEntity<String> retryBulkPayload = getRetryBulk(jobId); + return retryJobWithChangedData(jobId, retryBulkPayload.getBody()); + } + + protected List<String> retryJobWithChangedData(String jobId, String requestBody) { + String retryUri = getRetryJobWithChangedDataUrl(); + retryUri = retryUri.replace("{JOB_ID}", jobId); + MsoResponseWrapper2 responseWrapper2 = callMsoForResponseWrapper(HttpMethod.POST, retryUri, requestBody); + assertNotNull(responseWrapper2); + return (List<String>)responseWrapper2.getEntity(); + } + + protected ResponseEntity<String> getRetryBulk(String jobId) { + String retryUri = getTopologyForRetryUrl(); + retryUri = retryUri.replace("{JOB_ID}", jobId); + return restTemplateErrorAgnostic.getForEntity(retryUri, String.class); + } + + protected Object getResourceAuditInfo(String trackById) { + return restTemplate.getForObject(buildUri("/asyncInstantiation/auditStatusForRetry/{trackById}"), Object.class, trackById); + } + + public class JobInfoChecker<Integer> implements Predicate<Integer> { + + protected final RestTemplate restTemplate; + protected Set<JobStatus> expectedJobStatus; + protected ServiceInfo expectedServiceInfo; + protected final String jobId; + protected JobStatus lastStatus; + + public JobInfoChecker(RestTemplate restTemplate, Set<JobStatus> expectedJobStatus, String jobId, ServiceInfo expectedServiceInfo) { + this.restTemplate = restTemplate; + this.expectedJobStatus = expectedJobStatus; + this.jobId = jobId; + this.expectedServiceInfo = expectedServiceInfo; + } + + public void setExpectedJobStatus(Set<JobStatus> expectedJobStatus) { + this.expectedJobStatus = expectedJobStatus; + } + + @Override + public boolean test(Integer integer) { + ResponseEntity<List<ServiceInfo>> serviceListResponse = serviceListCall(); + assertThat(serviceListResponse.getStatusCode(), CoreMatchers.equalTo(HttpStatus.OK)); + assertThat(serviceListResponse.getBody(), hasItem(new JobIdAndStatusMatcher(jobId))); + ServiceInfo serviceInfoFromDB = serviceListResponse.getBody().stream() + .filter(serviceInfo -> serviceInfo.jobId.equals(jobId)) + .findFirst().orElse(null); + Assert.assertNotNull(serviceInfoFromDB); + Assert.assertEquals(serviceInfoDataReflected(expectedServiceInfo), serviceInfoDataReflected(serviceInfoFromDB)); + assertTrue("actual service instance doesn't contain template service name:" + expectedServiceInfo.serviceInstanceName, + serviceInfoFromDB.serviceInstanceName.contains(expectedServiceInfo.serviceInstanceName)); + + if (expectedServiceInfo.serviceInstanceId != null && ImmutableList.of(JobStatus.COMPLETED, JobStatus.PAUSE, JobStatus.COMPLETED_WITH_ERRORS).contains(serviceInfoFromDB.jobStatus)) { + MatcherAssert.assertThat("service instance id is wrong", serviceInfoFromDB.serviceInstanceId, CoreMatchers.is(expectedServiceInfo.serviceInstanceId)); + } + if (expectedJobStatus.size()==1) { + assertEquals("job status is wrong", getExpectedRetryEnabled((JobStatus)(expectedJobStatus.toArray()[0])), serviceInfoFromDB.isRetryEnabled); + } + lastStatus = serviceInfoFromDB.jobStatus; + return expectedJobStatus.contains(serviceInfoFromDB.jobStatus); + } + } + + protected ResponseEntity<List<ServiceInfo>> serviceListCall() { + return restTemplate.exchange( + getServiceInfoUrl(), + org.springframework.http.HttpMethod.GET, + null, + new ParameterizedTypeReference<List<ServiceInfo>>() {}); + } + + //serialize fields except of fields we cannot know ahead of time + protected static String serviceInfoDataReflected(ServiceInfo service1) { + return new ReflectionToStringBuilder(service1, ToStringStyle.SHORT_PREFIX_STYLE) + .setExcludeFieldNames("jobStatus", "templateId", "statusModifiedDate", "createdBulkDate", "serviceInstanceId", "serviceInstanceName", "isRetryEnabled") + .toString(); + } + + protected void addBulkPendingWithCustomList(List<BasePreset> customPresets){ + Map<Keys, String> names = generateNames(); + final int bulkSize = 2 + customPresets.size(); + + List<BasePreset> msoBulkPresets = generateMsoCreateBulkPresets(bulkSize, names); + ImmutableList<BasePreset> presets = new ImmutableList.Builder<BasePreset>() + .add(new PresetGetSessionSlotCheckIntervalGet()) + .add(new PresetAAIGetSubscribersGet()) + .addAll(msoBulkPresets) + .addAll(customPresets) + .build(); + + List<String> jobIds = createBulkOfMacroInstances(presets, false, bulkSize, names); + Assert.assertEquals(jobIds.size(),bulkSize); + } + + protected void verifyAuditStatuses(String jobId, List<String> statuses, JobAuditStatus.SourceStatus source) { + int statusesSize = statuses.size(); + AtomicReference<List<JobAuditStatus>> actualAudits = new AtomicReference<>(); + if (source.equals(JobAuditStatus.SourceStatus.VID)) { + actualAudits.set(getAuditStatuses(jobId, JobAuditStatus.SourceStatus.VID.name())); + org.junit.Assert.assertEquals("Received number of VID statuses is not as expected", statusesSize, actualAudits.get().size()); + } else { + boolean isStatusedSizeAsExpected = Wait.waitFor(x-> { + actualAudits.set(getAuditStatuses(jobId, JobAuditStatus.SourceStatus.MSO.name())); + return actualAudits.get().size() == statusesSize; + },null,5,1); + org.junit.Assert.assertTrue("Received number of MSO statuses is not as expected. Expected: " + statusesSize + ". Received: " + actualAudits.get().size(), isStatusedSizeAsExpected); + } + IntStream.range(0, statusesSize).forEach(i-> org.junit.Assert.assertEquals(source + " status #" + i + " is not as expected", statuses.get(i), actualAudits.get().get(i).getJobStatus())); + } + + protected void verifyInstanceAuditStatuses(List<JobAuditStatus> expectedStatuses, List<JobAuditStatus> actualStatuses) { + final int expectedSize = expectedStatuses.size(); + assertTrue("Expected statuses size is "+ expectedSize +", actual size is "+actualStatuses.size(), new Integer(expectedSize).equals(actualStatuses.size())); + IntStream.range(0, expectedSize).forEach(i-> { + + final JobAuditStatus expectedStatus = expectedStatuses.get(i); + final JobAuditStatus actualStatus = actualStatuses.get(i); + org.junit.Assert.assertEquals("MSO status #" + i + " is not as expected", expectedStatus.getJobStatus(), actualStatus.getJobStatus()); + org.junit.Assert.assertEquals("MSO requestId #" + i + " is not as expected", expectedStatus.getRequestId(), actualStatus.getRequestId()); + org.junit.Assert.assertEquals("MSO additionalInfo #" + i + " is not as expected", expectedStatus.getAdditionalInfo(), actualStatus.getAdditionalInfo()); + org.junit.Assert.assertEquals("MSO jobID #" + i + " is not as expected", expectedStatus.getJobId(), actualStatus.getJobId()); + org.junit.Assert.assertEquals("MSO instanceName #" + i + " is not as expected", expectedStatus.getInstanceName(), actualStatus.getInstanceName()); + org.junit.Assert.assertEquals("MSO instanceType #" + i + " is not as expected", expectedStatus.getInstanceType(), actualStatus.getInstanceType()); + }); + } +} diff --git a/vid-automation/src/main/java/org/onap/vid/api/BaseApiTest.java b/vid-automation/src/main/java/org/onap/vid/api/BaseApiTest.java new file mode 100644 index 000000000..5b7b1b214 --- /dev/null +++ b/vid-automation/src/main/java/org/onap/vid/api/BaseApiTest.java @@ -0,0 +1,163 @@ +package org.onap.vid.api; + +import static java.util.Collections.singletonList; +import static net.javacrumbs.jsonunit.JsonMatchers.jsonEquals; +import static net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER; +import static org.apache.commons.text.StringEscapeUtils.unescapeJson; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isEmptyOrNullString; +import static org.hamcrest.Matchers.not; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; +import java.util.List; +import java.util.Properties; +import java.util.Random; +import java.util.TimeZone; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import org.apache.commons.io.IOUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.glassfish.jersey.client.ClientProperties; +import org.glassfish.jersey.uri.internal.JerseyUriBuilder; +import org.onap.sdc.ci.tests.datatypes.UserCredentials; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.HttpStatusCodeException; +import org.springframework.web.client.RestTemplate; +import org.testng.annotations.BeforeClass; +import vid.automation.test.infra.FeaturesTogglingConfiguration; +import vid.automation.test.services.UsersService; +import vid.automation.test.utils.CookieAndJsonHttpHeadersInterceptor; + +public class BaseApiTest { + protected static final Logger LOGGER = LogManager.getLogger(BaseApiTest.class); + + @SuppressWarnings("WeakerAccess") + protected URI uri; + @SuppressWarnings("WeakerAccess") + protected ObjectMapper objectMapper = new ObjectMapper(); + @SuppressWarnings("WeakerAccess") + protected Client client; + protected Random random; + protected final RestTemplate restTemplate = new RestTemplate(); + + protected final UsersService usersService = new UsersService(); + protected final RestTemplate restTemplateErrorAgnostic = new RestTemplate(); + + @BeforeClass + public void init() { + uri = getUri(); + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + client = ClientBuilder.newClient(); + client.property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true); + random = new Random(System.currentTimeMillis()); + FeaturesTogglingConfiguration.initializeFeatureManager(); + } + + private URI getUri() { + String host = System.getProperty("VID_HOST", "10.0.0.10"); + int port = Integer.valueOf(System.getProperty("VID_PORT", "8080")); + return new JerseyUriBuilder().host(host).port(port).scheme("http").path("vid").build(); + } + + public void login() { + login(getUserCredentials()); + } + + public void login(UserCredentials userCredentials) { + final List<ClientHttpRequestInterceptor> interceptors = singletonList(new CookieAndJsonHttpHeadersInterceptor(getUri(), userCredentials)); + restTemplate.setInterceptors(interceptors); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + try { + super.handleError(response); + } catch (HttpStatusCodeException e) { + LOGGER.error("HTTP {}: {}", e.getStatusCode(), e.getResponseBodyAsString(), e); + throw e; + } + } + }); + + restTemplateErrorAgnostic.setInterceptors(interceptors); + restTemplateErrorAgnostic.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public boolean hasError(ClientHttpResponse response) { + return false; + } + }); + } + + + //set time zone to UTC so clock will go closely with VID app + @BeforeClass + public void setDefaultTimeZoneToUTC() { + System.setProperty("user.timezone", "UTC"); + TimeZone.setDefault(TimeZone.getTimeZone("UTC")); //since TimeZone cache previous user.timezone + } + + public UserCredentials getUserCredentials() { + final Properties configProp = new Properties(); + try { + InputStream input = ClassLoader.getSystemResourceAsStream("test_config.properties"); + configProp.load(input); + } catch (IOException e) { + throw new RuntimeException(e); + } + + String loginId = configProp.getProperty("test.loginId", "i'm illegal"); + String loginPassword = configProp.getProperty("test.loginPassword", "i'm illegal"); + return new UserCredentials(loginId, loginPassword, null, null, null); + } + + + + + protected String getCleanJsonString(String jsonString) { + // remove leading/trailing double-quotes and unescape + String res = unescapeJson(jsonString.replaceAll("^\"|\"$", "")); + LOGGER.debug("getCleanJsonString: " + jsonString + " ==> " + res); + return res; + } + + protected String getCleanJsonString(Object object) throws JsonProcessingException { + if (object instanceof String) { + return getCleanJsonString((String) object); + } else { + return new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(object); + } + } + + protected String buildUri(String path) { + return uri + "/" + path; + } + + public static String getResourceAsString(String resourcePath) { + // load expected result + final URL resource = BaseApiTest.class.getClassLoader().getResource(resourcePath); + if (resource == null) throw new RuntimeException("resource file not found: " + resourcePath); + try { + return IOUtils.toString(resource, "UTF-8"); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + protected void assertJsonEquals(String actual, String expected) { + LOGGER.info(actual); + assertThat(actual, not(isEmptyOrNullString())); + + assertThat(actual, jsonEquals(expected) + .when(IGNORING_ARRAY_ORDER) + ); + } + +} diff --git a/vid-automation/src/main/java/org/onap/vid/api/BaseMsoApiTest.java b/vid-automation/src/main/java/org/onap/vid/api/BaseMsoApiTest.java new file mode 100644 index 000000000..175638008 --- /dev/null +++ b/vid-automation/src/main/java/org/onap/vid/api/BaseMsoApiTest.java @@ -0,0 +1,108 @@ +package org.onap.vid.api; + +import com.google.common.collect.ImmutableMap; +import org.json.JSONException; +import org.onap.simulator.presetGenerator.presets.BasePresets.BaseMSOPreset; +import org.onap.simulator.presetGenerator.presets.BasePresets.BasePreset; +import org.onap.vid.model.mso.MsoResponseWrapper2; +import org.skyscreamer.jsonassert.JSONAssert; +import org.skyscreamer.jsonassert.JSONCompareMode; +import org.springframework.http.HttpMethod; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import vid.automation.test.services.SimulatorApi; +import vid.automation.test.services.SimulatorApi.RegistrationStrategy; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.List; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class BaseMsoApiTest extends BaseApiTest { + + @BeforeClass + public void login() { + super.login(); + } + + protected void callMsoWithSimulatedErrorResponse(String expectationJsonFileName, ImmutableMap<String, Object> replacementsForJson, String targetUri, String basicRequestBody, int expectedErrorCode, String expectedResult, HttpMethod method) throws IOException { + SimulatorApi.registerExpectation(expectationJsonFileName, replacementsForJson, RegistrationStrategy.CLEAR_THEN_SET); + callMsoAndAssertError(targetUri, basicRequestBody, expectedErrorCode, expectedResult, method); + } + + protected void callMsoWithSimulatedErrorResponse(BaseMSOPreset expectation, String targetUri, String basicRequestBody, int expectedErrorCode, String expectedResult, HttpMethod method) throws IOException { + SimulatorApi.registerExpectationFromPreset(expectation, RegistrationStrategy.CLEAR_THEN_SET); + callMsoAndAssertError(targetUri, basicRequestBody, expectedErrorCode, expectedResult, method); + } + + protected void callMsoWithSimulatedErrorResponse(List<BasePreset> expectations, String targetUri, String basicRequestBody, int expectedErrorCode, String expectedResult, HttpMethod method) throws IOException { + SimulatorApi.registerExpectationFromPresets(expectations, RegistrationStrategy.CLEAR_THEN_SET); + callMsoAndAssertError(targetUri, basicRequestBody, expectedErrorCode, expectedResult, method); + } + + private void callMsoAndAssertError(String targetUri, String basicRequestBody, int expectedErrorCode, String expectedResult, HttpMethod method) throws IOException { + try { + MsoResponseWrapper2 responseWrapper = callMsoForResponseWrapper(method, targetUri, basicRequestBody); + + assertThat("Wrong propagated status from MSO", responseWrapper.getStatus(), is(expectedErrorCode)); + assertThat("Wrong propagated body from MSO", getCleanJsonString(responseWrapper.getEntity()), is(expectedResult)); + }catch(HttpClientErrorException | HttpServerErrorException e) { + assertThat("Wrong propagated status from MSO", e.getStatusCode().value(), is(expectedErrorCode)); + } + } + + + protected void callMsoWithFineRequest(String expectationJsonFileName, ImmutableMap<String, Object> replacementsForJson, String targetUri, String requestBody, int expectedStatusCode, String expectedResult, HttpMethod method) throws IOException { + SimulatorApi.registerExpectation(expectationJsonFileName, replacementsForJson, RegistrationStrategy.CLEAR_THEN_SET); + callMsoAndAssertSuccess(targetUri, requestBody, expectedStatusCode, expectedResult, method); + } + + protected void callMsoWithFineRequest(BaseMSOPreset expectation, String targetUri, String requestBody, int expectedStatusCode, String expectedResult, HttpMethod method) throws IOException { + SimulatorApi.registerExpectationFromPreset(expectation, RegistrationStrategy.CLEAR_THEN_SET); + callMsoAndAssertSuccess(targetUri, requestBody, expectedStatusCode, expectedResult, method); + } + + protected void callMsoWithFineRequest(List<BasePreset> expectations, String targetUri, String requestBody, int expectedStatusCode, String expectedResult, HttpMethod method) throws IOException { + SimulatorApi.registerExpectationFromPresets(expectations, RegistrationStrategy.CLEAR_THEN_SET); + callMsoAndAssertSuccess(targetUri, requestBody, expectedStatusCode, expectedResult, method); + } + + private void callMsoAndAssertSuccess(String targetUri, String requestBody, int expectedStatusCode, String expectedResult, HttpMethod method) throws IOException { + MsoResponseWrapper2 responseWrapper = callMsoForResponseWrapper(method, targetUri, requestBody); + + assertThat("Wrong propagated status from MSO", responseWrapper.getStatus(), is(expectedStatusCode)); + try { + JSONAssert.assertEquals("Wrong propagated body from MSO", expectedResult, getCleanJsonString(responseWrapper.getEntity()), JSONCompareMode.NON_EXTENSIBLE); + } catch (JSONException e) { + throw new RuntimeException(e); + } + } + + protected MsoResponseWrapper2 callMsoForResponseWrapper(HttpMethod method, String uri, String body) { + MsoResponseWrapper2 responseWrapper; + switch (method) { + case POST: + responseWrapper = restTemplate.postForObject(uri, body, MsoResponseWrapper2.class); + break; + case GET: + default: + responseWrapper = restTemplate.getForObject(uri, MsoResponseWrapper2.class); + break; + } + + System.out.println("response: " + responseWrapper); + + return responseWrapper; + } + + @DataProvider + public static Object[][] errorCodes(Method test) { + return new Object[][]{ + {500},{505}, {400}, {401}, {404}, {405} + }; + } +} diff --git a/vid-automation/src/main/java/org/onap/vid/api/CreateInstanceWithFailedService.java b/vid-automation/src/main/java/org/onap/vid/api/CreateInstanceWithFailedService.java new file mode 100644 index 000000000..6c8f3fade --- /dev/null +++ b/vid-automation/src/main/java/org/onap/vid/api/CreateInstanceWithFailedService.java @@ -0,0 +1,87 @@ +package org.onap.vid.api; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.onap.simulator.presetGenerator.presets.BasePresets.BasePreset; +import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetCloudOwnersByCloudRegionId; +import org.onap.simulator.presetGenerator.presets.mso.*; +import org.springframework.http.ResponseEntity; +import vid.automation.test.model.JobStatus; +import vid.automation.test.model.ServiceAction; +import vid.automation.test.services.SimulatorApi; + +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.onap.simulator.presetGenerator.presets.mso.PresetMSOServiceInstanceGen2WithNames.Keys.SERVICE_NAME; +import static org.onap.vid.api.AsyncInstantiationBase.CREATE_BULK_OF_ALACARTE_REQUEST_WITH_VNF; +import static org.onap.vid.api.TestUtils.hasOrLacksOfEntry; +import static vid.automation.test.services.SimulatorApi.registerExpectationFromPreset; +import static vid.automation.test.services.SimulatorApi.registerExpectationFromPresets; + +public class CreateInstanceWithFailedService { + private CreateServiceWithFailedVnf.ResourceIds firstIds = new CreateServiceWithFailedVnf.ResourceIds(); + private AsyncInstantiationBase asyncInstantiationBase; + private List<PresetMSOBaseCreateInstancePost> createPresets; + private String serviceInstanceName = TestUtils.generateRandomAlphaNumeric(10); + private ImmutableMap<PresetMSOServiceInstanceGen2WithNames.Keys, String> names; + private List<PresetMSOOrchestrationRequestGet> inProgressPresets; + private List<String> uuids; + private String originalJobId; + ObjectMapper objectMapper = new ObjectMapper(); + + + public CreateInstanceWithFailedService(AsyncInstantiationBase asyncInstantiationALaCarteApiTest) { + this.asyncInstantiationBase = asyncInstantiationALaCarteApiTest; + } + + private CreateInstanceWithFailedService createInstanceWithFailedService() { + + names = ImmutableMap.of(SERVICE_NAME, serviceInstanceName); + + final String serviceFailedStatusMessage = "The service instantiation is failed."; + createPresets = ImmutableList.of( + new PresetMSOCreateServiceInstanceGen2WithNamesAlacarteService(names, 0, firstIds.serviceReqId, firstIds.serviceId) + ); + inProgressPresets = ImmutableList.of( + new PresetMSOOrchestrationRequestGet("FAILED", firstIds.serviceReqId, serviceFailedStatusMessage) + ); + List<BasePreset> presets = asyncInstantiationBase.getPresets(createPresets, inProgressPresets); + + registerExpectationFromPresets(presets, SimulatorApi.RegistrationStrategy.CLEAR_THEN_SET); + registerExpectationFromPreset(PresetAAIGetCloudOwnersByCloudRegionId.PRESET_MDT1_TO_ATT_NC, SimulatorApi.RegistrationStrategy.APPEND); + + uuids = asyncInstantiationBase.createBulkOfInstances(false, 1, names, CREATE_BULK_OF_ALACARTE_REQUEST_WITH_VNF); + return this; + } + + protected void deployServiceFailedInstance() { + createInstanceWithFailedService(); + firstTimeAssertion(); + prepareAndAssertJsonFileForCypressTest(); + } + + private void prepareAndAssertJsonFileForCypressTest() { + final ResponseEntity<String> responseEntity = asyncInstantiationBase.getRetryBulk(originalJobId); + String expected = TestUtils.convertRequest(objectMapper, "asyncInstantiation/ServiceWithFailedServiceInstance.json"); + expected = expected + .replace("SERVICE_NAME", serviceInstanceName); + String originalResponse = responseEntity.getBody(); + String responseToCompare = originalResponse.replaceFirst("(instanceName\":\")(.*?)(\")", "$1INSTANCE_NAME$3").replaceAll("(trackById\":\")(.*?)(\")", "$1TRACK_BY_ID$3"); + asyncInstantiationBase.assertJsonEquals(responseToCompare, expected); + } + + private void firstTimeAssertion() { + assertThat(uuids, hasSize(1)); + originalJobId = uuids.get(0); + asyncInstantiationBase.assertServiceInfoSpecific1(originalJobId, JobStatus.FAILED, names.get(SERVICE_NAME), "us16807000", firstIds.serviceId, ServiceAction.INSTANTIATE); + asyncInstantiationBase.assertAuditStatuses(originalJobId, asyncInstantiationBase.vidAuditStatusesFailed(originalJobId), null); + assertThat(SimulatorApi.retrieveRecordedRequestsPathCounter(), allOf( + hasOrLacksOfEntry(createPresets.get(0).getReqPath(), 1L), + hasOrLacksOfEntry(inProgressPresets.get(0).getReqPath(), 1L) + )); + } +} diff --git a/vid-automation/src/main/java/org/onap/vid/api/CreateServiceWithFailedVnf.java b/vid-automation/src/main/java/org/onap/vid/api/CreateServiceWithFailedVnf.java new file mode 100644 index 000000000..30076a964 --- /dev/null +++ b/vid-automation/src/main/java/org/onap/vid/api/CreateServiceWithFailedVnf.java @@ -0,0 +1,226 @@ +package org.onap.vid.api; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import org.hamcrest.Matchers; +import org.onap.simulator.presetGenerator.presets.BasePresets.BasePreset; +import org.onap.simulator.presetGenerator.presets.aai.PresetAAIGetCloudOwnersByCloudRegionId; +import org.onap.simulator.presetGenerator.presets.mso.*; +import org.onap.simulator.presetGenerator.presets.sdc.PresetSDCGetServiceMetadataGet; +import org.onap.simulator.presetGenerator.presets.sdc.PresetSDCGetServiceToscaModelGet; +import org.onap.vid.model.asyncInstantiation.ServiceInfo; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import vid.automation.test.infra.ModelInfo; +import vid.automation.test.model.JobStatus; +import vid.automation.test.model.ServiceAction; +import vid.automation.test.services.SimulatorApi; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.*; +import static org.hamcrest.collection.IsCollectionWithSize.hasSize; +import static org.onap.simulator.presetGenerator.presets.mso.PresetMSOServiceInstanceGen2WithNames.Keys.SERVICE_NAME; +import static org.onap.simulator.presetGenerator.presets.mso.PresetMSOServiceInstanceGen2WithNames.Keys.VNF_NAME; +import static org.onap.vid.api.TestUtils.hasOrLacksOfEntry; +import static org.testng.Assert.assertTrue; +import static org.testng.AssertJUnit.assertFalse; +import static vid.automation.test.services.SimulatorApi.registerExpectationFromPreset; +import static vid.automation.test.services.SimulatorApi.registerExpectationFromPresets; + +//CreateServiceWithFailedVnf is common for API test and UI test, +//so if you change it, make sure both test are compatible with your changes +public class CreateServiceWithFailedVnf { + private AsyncInstantiationBase asyncInstantiationBase; + private ImmutableMap<PresetMSOServiceInstanceGen2WithNames.Keys, String> names; + private List<PresetMSOBaseCreateInstancePost> createPresets; + private List<PresetMSOOrchestrationRequestGet> inProgressPresets; + private List<String> uuids; + private List<String> retryUuids; + private String originalJobId; + private String serviceInstanceName = TestUtils.generateRandomAlphaNumeric(10); + private ResourceIds firstIds = new ResourceIds(); + private ResourceIds retryIds = new ResourceIds(); + private String vnfEditedName = TestUtils.generateRandomAlphaNumeric(10); + ObjectMapper objectMapper = new ObjectMapper(); + public final ModelInfo serviceComplexService = new ModelInfo("e3c34d88-a216-4f1d-a782-9af9f9588705", "0367689e-d41e-483f-b200-eab17e4a7f8d", "service-Complexservice-aLaCarte-csar-2.zip"); + + public CreateServiceWithFailedVnf(AsyncInstantiationBase asyncInstantiationALaCarteApiTest) { + this.asyncInstantiationBase = asyncInstantiationALaCarteApiTest; + } + + public ImmutableMap<PresetMSOServiceInstanceGen2WithNames.Keys, String> getNames() { + return names; + } + + public ResourceIds getFirstIds() { + return firstIds; + } + + public static class ResourceIds { + public String serviceId =UUID.randomUUID().toString(); + public String serviceReqId =UUID.randomUUID().toString(); + public String vnfId =UUID.randomUUID().toString(); + public String vnfReqId =UUID.randomUUID().toString(); + } + + + public CreateServiceWithFailedVnf createServicesWithVnfCompletedWithError() { +/* +Legit Preset || deploy 1 Service, 1 VNF which will fail + -> JobStatus of service is COMPLETED_WITH_ERRORS, audit + is adequate; strict simulator comapre + */ + + names = ImmutableMap.of(SERVICE_NAME, serviceInstanceName, VNF_NAME, serviceInstanceName+"_vnf"); + + + + final String vnfFailedStatusMessage = "Vnf failed."; + createPresets = ImmutableList.of( + new PresetMSOCreateServiceInstanceGen2WithNamesAlacarteService(names, 0, firstIds.serviceReqId, firstIds.serviceId), + new PresetMSOCreateVNFInstanceOnlyRelatedServiceInstance(names.get(VNF_NAME),firstIds.vnfReqId , firstIds.serviceId, firstIds.vnfId, 0) + ); + inProgressPresets = ImmutableList.of( + new PresetMSOOrchestrationRequestGet("COMPLETE", firstIds.serviceReqId), + new PresetMSOOrchestrationRequestGet("FAILED", firstIds.vnfReqId, vnfFailedStatusMessage) + ); + List<BasePreset> presets = asyncInstantiationBase.getPresets(createPresets, inProgressPresets); + + registerExpectationFromPresets(presets, SimulatorApi.RegistrationStrategy.CLEAR_THEN_SET); + registerExpectationFromPreset(PresetAAIGetCloudOwnersByCloudRegionId.PRESET_MDT1_TO_ATT_NC, SimulatorApi.RegistrationStrategy.APPEND); + + uuids = asyncInstantiationBase.createBulkOfInstances(false, 1, names, AsyncInstantiationBase.CREATE_BULK_OF_ALACARTE_REQUEST_WITH_VNF); + return this; + } + + public void firstTimeAssertion() { + assertThat(uuids, hasSize(1)); + originalJobId = uuids.get(0); + + asyncInstantiationBase.assertServiceInfoSpecific1(originalJobId, JobStatus.COMPLETED_WITH_ERRORS, names.get(SERVICE_NAME), "us16807000", firstIds.serviceId, ServiceAction.INSTANTIATE); + asyncInstantiationBase.assertAuditStatuses(originalJobId, asyncInstantiationBase.vidAuditStatusesCompletedWithErrors(originalJobId),null); + assertThat(SimulatorApi.retrieveRecordedRequestsPathCounter(), allOf( + hasOrLacksOfEntry(createPresets.get(0).getReqPath(), 1L), + hasOrLacksOfEntry(createPresets.get(1).getReqPath(), 1L), + hasOrLacksOfEntry(inProgressPresets.get(0).getReqPath(), 1L), + hasOrLacksOfEntry(inProgressPresets.get(1).getReqPath(), 1L) + )); + } + + public String getBulkForRetry(){ + final ResponseEntity<String> responseEntity= asyncInstantiationBase.getRetryBulk(originalJobId); + String expected = TestUtils.convertRequest(objectMapper, "asyncInstantiation/ServiceTreeForRetry_serviceInstance.json"); + expected = expected + .replace("SERVICE_NAME", serviceInstanceName); + String originalResponse = responseEntity.getBody(); + String responseToCompare = originalResponse.replaceFirst( "(instanceId\":\")(.*?)(\")", "$1INSTANCE_ID$3") + .replaceAll( "(trackById\":\")(.*?)(\")", "$1TRACK_BY_ID$3"); + asyncInstantiationBase.assertJsonEquals(responseToCompare, expected); + return originalResponse; + } + + public void getBulkForRetryNotFound() { + UUID jobId= UUID.randomUUID(); + final ResponseEntity<String> response = asyncInstantiationBase.getRetryBulk(jobId.toString()); + assertThat(response.getStatusCode(), is(HttpStatus.NOT_FOUND)); + assertThat(response.getBody(),containsString("Failed to retrieve class org.onap.vid.dao.JobRequest with JOB_ID "+jobId+" from table. no resource found")); + } + + private void secondRegistration(String vnfName) { + createPresets = ImmutableList.of( + new PresetMSOCreateVNFInstanceOnlyRelatedServiceInstance(vnfName, retryIds.vnfReqId, firstIds.serviceId, retryIds.vnfId, 0) + ); + inProgressPresets = ImmutableList.of( + new PresetMSOOrchestrationRequestGet("COMPLETE", retryIds.vnfReqId) + ); + + registerExpectationFromPresets(asyncInstantiationBase.getPresets(createPresets, inProgressPresets), SimulatorApi.RegistrationStrategy.CLEAR_THEN_SET); + registerExpectationFromPresets(ImmutableList.of( + PresetAAIGetCloudOwnersByCloudRegionId.PRESET_MDT1_TO_ATT_NC, + new PresetSDCGetServiceMetadataGet(serviceComplexService), + new PresetSDCGetServiceToscaModelGet(serviceComplexService)), + SimulatorApi.RegistrationStrategy.APPEND); + + + } + + public String deployService1FailedVnf(){ + createServicesWithVnfCompletedWithError(); + firstTimeAssertion(); + return getBulkForRetry(); + } + + public void assertResourceAuditStatus(String bulkForRetry) { + String vnfTrackById = extractVnfTrackById(bulkForRetry); + + Map<String, Object> auditStatus = (Map) asyncInstantiationBase.getResourceAuditInfo(vnfTrackById); + assertThat(auditStatus.get("jobStatus"), equalTo("FAILED")); + assertThat(auditStatus.get("additionalInfo"), equalTo("Vnf failed.")); + assertThat(auditStatus.get("requestId"), equalTo(firstIds.vnfReqId)); + } + + private String extractVnfTrackById(String bulk) { + Map<String, Object> serviceInstantiation = null; + try { + serviceInstantiation = objectMapper.readValue(bulk, new TypeReference<Map<String, Object>>(){}); + Map<String, Object> vnf = (Map) ((Map) serviceInstantiation.get("vnfs")).get("vSAMP12 1"); + return vnf.get("trackById").toString(); + } catch (IOException e) { + return null; + } + } + + + public void secondRegistration() { + secondRegistration(names.get(VNF_NAME)); + } + + public void retryJob() { + //retry the previous job + retryUuids = asyncInstantiationBase.retryJob(originalJobId); + } + + public void retryJobWithOtherDataAndAssert(String requestBody){ + retryUuids = asyncInstantiationBase.retryJobWithChangedData(originalJobId, requestBody); + retryAssertion(); + simulatorCallsAssertion(); + } + + public String changeSomeDataAndRegisterToSimulator(String payload){ + payload = payload.replace(names.get(VNF_NAME), vnfEditedName); + secondRegistration(vnfEditedName); + return payload; + } + + + public void retryAssertion() { + + assertThat(retryUuids, Matchers.hasSize(1)); + String retryJobId = retryUuids.get(0); + assertThat(retryJobId, not(equalTo(originalJobId))); + asyncInstantiationBase.assertServiceInfoSpecific1(retryJobId, JobStatus.COMPLETED, names.get(SERVICE_NAME), "us16807000", firstIds.serviceId, ServiceAction.UPDATE); + + //make sure original job is retry is disabled. + Optional<ServiceInfo> optionalServiceInfo = asyncInstantiationBase.serviceListCall().getBody().stream().filter(si -> originalJobId.equals(si.jobId)).findFirst(); + assertTrue(optionalServiceInfo.isPresent()); + assertFalse(optionalServiceInfo.get().isRetryEnabled); + } + + public void simulatorCallsAssertion() { + assertThat(SimulatorApi.retrieveRecordedRequestsPathCounter(), allOf( + hasOrLacksOfEntry(createPresets.get(0).getReqPath(), 1L), + hasOrLacksOfEntry(inProgressPresets.get(0).getReqPath(), 1L) + )); + } + + +} diff --git a/vid-automation/src/main/java/org/onap/vid/api/TestUtils.java b/vid-automation/src/main/java/org/onap/vid/api/TestUtils.java new file mode 100644 index 000000000..a2fe82e9d --- /dev/null +++ b/vid-automation/src/main/java/org/onap/vid/api/TestUtils.java @@ -0,0 +1,99 @@ +package org.onap.vid.api; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import org.apache.commons.text.RandomStringGenerator; +import org.hamcrest.Matcher; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.http.HttpStatus; + +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; +import java.io.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.Scanner; + +import static org.apache.commons.text.CharacterPredicates.DIGITS; +import static org.apache.commons.text.CharacterPredicates.LETTERS; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.Matchers.*; +import static vid.automation.test.utils.RegExMatcher.matchesRegEx; + +public class TestUtils { + + protected static ObjectMapper objectMapper = new ObjectMapper(); + + public static void assertStatusOK(Object request, WebTarget webTarget, Response response) throws IOException { + assertHttpStatus(request, webTarget, response, HttpStatus.OK); + } + + public static void assertHttpStatus(Object request, WebTarget webTarget, Response response, HttpStatus exceptedHttpStatus) throws IOException { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + + org.testng.Assert.assertEquals(response.getStatus(), exceptedHttpStatus.value(), + String.format("Failed post URI: %s with request %s. Got Status:%d and body: %s", + webTarget.getUri(), + objectMapper.writeValueAsString(request), + response.getStatus(), + objectMapper.writeValueAsString(response.getEntity()))); + } + + public static String convertRequest(ObjectMapper objectMapper, String msoRequestDetailsFileName) { + + ClassLoader cl = TestUtils.class.getClassLoader(); + ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(cl); + Resource[] resources; + try { + resources = resolver.getResources(msoRequestDetailsFileName); + //using InputStream and not file. see https://stackoverflow.com/questions/14876836/file-inside-jar-is-not-visible-for-spring/51131841#51131841 + InputStream inputStream = resources[0].getInputStream(); + String content = new Scanner(inputStream).useDelimiter("\\Z").next(); + objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); + return objectMapper.writeValueAsString(objectMapper.readValue(content, Object.class)); + } + catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + public static String getNestedPropertyInMap(Object item, String path) { + return getNestedPropertyInMap(item, path, String.class, "/"); + } + + public static <T> T getNestedPropertyInMap(Object item, String path, Class<T> valueType) { + return getNestedPropertyInMap(item, path, valueType, "/"); + } + + /* + Use this method to extract item from Map that represent Json hierarchy (Map<String,Map>) + */ + public static <T> T getNestedPropertyInMap(Object item, String path, Class<T> valueType, String delimeter) { + String[] pathes = path.split(delimeter); + return valueType.cast(getNestedPropertyInMap(item,pathes,0)); + } + + private static Object getNestedPropertyInMap(Object item, String[] pathes, int index) { + if (index==pathes.length) { + return item; + } + return getNestedPropertyInMap(((Map<String,Object>)item).get(pathes[index]), pathes, ++index); + } + + static Matcher hasOrLacksOfEntry(String pathRegex, Long expectedCounter) { + return expectedCounter.equals(0L) ? not(hasKey(matchesRegEx(pathRegex))) : hasEntry(matchesRegEx(pathRegex), is(expectedCounter)); + } + + private static RandomStringGenerator generator = new RandomStringGenerator.Builder() + .withinRange('0', 'z') + .filteredBy(LETTERS, DIGITS) + .build(); + + public static String generateRandomAlphaNumeric(int length) { + return generator.generate(length); + } +} |