diff options
30 files changed, 1755 insertions, 321 deletions
diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml b/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml index 8eafc4abf..828ff2ef2 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/pom.xml @@ -49,16 +49,6 @@ <artifactId>httpclient</artifactId> <version>${apache.httpcomponents.client.version}</version> </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> - <scope>test</scope> - </dependency> - <dependency> - <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-security</artifactId> - <scope>test</scope> - </dependency> </dependencies> </project> diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt index f145d9677..63998dd29 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutor.kt @@ -47,17 +47,20 @@ import org.springframework.stereotype.Component */ @Component("component-remote-ansible-executor") @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE) -open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertyService: BluePrintRestLibPropertyService) +open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertyService: BluePrintRestLibPropertyService, + private val mapper: ObjectMapper) : AbstractComponentFunction() { - private val log = LoggerFactory.getLogger(ComponentRemoteAnsibleExecutor::class.java)!! - // HTTP related constants private val HTTP_SUCCESS = 200..202 private val GET = HttpMethod.GET.name private val POST = HttpMethod.POST.name + var checkDelay: Long = 1_000 + companion object { + private val log = LoggerFactory.getLogger(ComponentRemoteAnsibleExecutor::class.java) + // input fields names accepted by this executor const val INPUT_ENDPOINT_SELECTOR = "endpoint-selector" const val INPUT_JOB_TEMPLATE_NAME = "job-template-name" @@ -71,8 +74,6 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe const val ATTRIBUTE_EXEC_CMD_STATUS = "ansible-command-status" const val ATTRIBUTE_EXEC_CMD_LOG = "ansible-command-logs" const val ATTRIBUTE_EXEC_CMD_STATUS_ERROR = "error" - - const val CHECKDELAY: Long = 10000 } override suspend fun processNB(executionRequest: ExecutionServiceInput) { @@ -131,8 +132,6 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe * Finds the job template ID based on the job template name provided in the request */ private fun lookupJobTemplateIDByName(awxClient : BlueprintWebClientService, job_template_name: String?): String { - val mapper = ObjectMapper() - val encodedJTName = URI(null,null, "/api/v2/job_templates/${job_template_name}/", null,null).rawPath @@ -150,12 +149,11 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe * The status and output attributes are populated in the process. */ private fun runJobTemplateOnAWX(awxClient : BlueprintWebClientService, job_template_name: String?, jtId: String) { - val mapper = ObjectMapper() - setNodeOutputProperties( "preparing".asJsonPrimitive(), "".asJsonPrimitive()) // Get Job Template requirements var response = awxClient.exchangeResource(GET, "/api/v2/job_templates/${jtId}/launch/","") + // FIXME: handle non-successful SC val jtLaunchReqs: JsonNode = mapper.readTree(response.body) var payload = prepareLaunchPayload(awxClient, jtLaunchReqs) log.info("Running job with $payload, for requestId $processId.") @@ -182,7 +180,7 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe val jobLaunched: JsonNode = mapper.readTree(response.body) jobStatus = jobLaunched.at("/status").asText() jobEndTime = jobLaunched.at("/finished").asText() - Thread.sleep(CHECKDELAY) + Thread.sleep(checkDelay) } log.info("Execution of job template $job_template_name in job #$jobId finished with status ($jobStatus) for requestId $processId") @@ -255,8 +253,6 @@ open class ComponentRemoteAnsibleExecutor(private val blueprintRestLibPropertySe val encoded = URLEncoder.encode(inventoryProp) val response = awxClient.exchangeResource(GET,"/api/v2/inventories/?name=$encoded","") if (response.status in HTTP_SUCCESS) { - val mapper = ObjectMapper() - // Extract the inventory ID from response val invDetails = mapper.readTree(response.body) val nbInvFound = invDetails.at("/count").asInt() diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt index b7f1ed5f9..b60290268 100644 --- a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/ansible/executor/ComponentRemoteAnsibleExecutorTest.kt @@ -21,223 +21,1362 @@ import com.fasterxml.jackson.databind.ObjectMapper import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.runBlocking -import org.junit.Ignore +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith -import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties -import org.onap.ccsdk.cds.blueprintsprocessor.core.BlueprintPropertyConfiguration import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData -import org.onap.ccsdk.cds.blueprintsprocessor.rest.BluePrintRestLibConfiguration import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService +import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService.WebClientResponse import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants -import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement -import org.onap.ccsdk.cds.controllerblueprints.core.service.DefaultBluePrintRuntimeService +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils -import org.slf4j.LoggerFactory -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.autoconfigure.EnableAutoConfiguration -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner @RunWith(SpringRunner::class) -@EnableAutoConfiguration(exclude = [DataSourceAutoConfiguration::class]) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) -@ContextConfiguration(classes = [BluePrintRestLibConfiguration::class, - BlueprintPropertyConfiguration::class, - BluePrintProperties::class, - BluePrintProperties::class]) -@TestPropertySource(properties = -[ - "server.port=8443", - "server.ssl.enabled=true", - "server.ssl.key-store=classpath:keystore.p12", - "server.ssl.key-store-password=changeit", - "server.ssl.keyStoreType=PKCS12", - "server.ssl.keyAlias=tomcat", - "blueprintsprocessor.restclient.awx.type=token-auth", - "blueprintsprocessor.restclient.awx.url=http://142.44.184.236", - "blueprintsprocessor.restclient.awx.token=Bearer J9gEtMDqf7P4YsJ74fioY9VAhLDIs1", - "blueprintsprocessor.restclient.future.keyStoreInstance=PKCS12", - "blueprintsprocessor.restclient.future.sslTrust=src/test/resources/keystore.p12", - "blueprintsprocessor.restclient.future.sslTrustPassword=changeit" -]) +@TestPropertySource(locations = ["classpath:application-test.properties"]) +@Suppress("SameParameterValue") class ComponentRemoteAnsibleExecutorTest { - @Autowired - lateinit var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService + private val webClientService = mockk<BlueprintWebClientService>() - @Transient - private val log = LoggerFactory.getLogger(ComponentRemoteAnsibleExecutorTest::class.java) + companion object { + private const val jtId = 9 + private const val jobId = 223 + + private val mapper = ObjectMapper() + + // IMPORTANT: must match the corresponding properties blueprintsprocessor.restclient.awx.* on + // "application-test.properties" + private const val endpointSelector = """{ + "type": "token-auth", + "url": "http://142.44.184.236", + "token": "Bearer J9gEtMDqf7P4YsJ7444fioY9VAhLDIs1" + }""" + } @Test - @Ignore fun testComponentRemoteAnsibleExecutor() { - runBlocking { - val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") + } returns WebClientResponse(200, getJobTemplates(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") + } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") + } returns WebClientResponse(200, getInventory()) + every { + webClientService.exchangeResource("POST", "/api/v2/job_templates/$jtId/launch/", + """{"inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}""") + } returns WebClientResponse(201, newJobTemplateLaunch(jtId, jobId)) + every { + webClientService.exchangeResource("GET", "/api/v2/jobs/$jobId/", "") + } returnsMany listOf( + WebClientResponse(200, getJobStatus1(jtId, jobId)), + WebClientResponse(200, getJobStatus2(jtId, jobId)), + WebClientResponse(200, getJobStatus3(jtId, jobId)), + WebClientResponse(200, getJobStatus4(jtId, jobId)) + ) + every { + webClientService.exchangeResource("GET", "/api/v2/jobs/$jobId/stdout/?format=txt", "", + mapOf("Content-Type" to "text/plain ;utf-8")) + } returns WebClientResponse(200, getReport()) + val selector = mapper.readTree(endpointSelector) + val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>() + every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService + val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper) + awxRemoteExecutor.checkDelay = 1 - val executionServiceInput = JacksonUtils.readValueFromClassPathFile( - "payload/requests/sample-remote-ansible-request.json", - ExecutionServiceInput::class.java)!! + val executionServiceInput = JacksonUtils.readValueFromClassPathFile( + "payload/requests/sample-remote-ansible-request.json", + ExecutionServiceInput::class.java)!! - log.info("Request Inputs : " + executionServiceInput.payload) + val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput) - val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("123456-1000", - "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_ansible") - awxRemoteExecutor.bluePrintRuntimeService = bluePrintRuntimeService + // when + runBlocking { + awxRemoteExecutor.applyNB(executionServiceInput) + } + + // then + assertTrue(bluePrintRuntimeService.getBluePrintError().errors.isEmpty()) + } - val workflowName = executionServiceInput.actionIdentifiers.actionName + @Test + fun `handle unknown inventory`() { - // Assign Workflow inputs - val input = executionServiceInput.payload.get("$workflowName-request") - bluePrintRuntimeService.assignWorkflowInputs(workflowName, input) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") + } returns WebClientResponse(200, getJobTemplates(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") + } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") + } returns WebClientResponse(404, "") + val selector = mapper.readTree(endpointSelector) + val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>() + every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService + val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper) + awxRemoteExecutor.checkDelay = 1 - val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible") - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor") - stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") + val executionServiceInput = JacksonUtils.readValueFromClassPathFile( + "payload/requests/remote-ansible-request-full.json", + ExecutionServiceInput::class.java)!! - val stepInputData = StepData().apply { - name = "execute-remote-ansible" - properties = stepMetaData - } - executionServiceInput.stepData = stepInputData + val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput) + // when + runBlocking { awxRemoteExecutor.applyNB(executionServiceInput) } + + // then + val errors = bluePrintRuntimeService.getBluePrintError().errors + assertEquals(1, errors.size) } - /** - * Test cases for Ansible executor to work with the process NB of remote - * executor. - */ @Test - @Ignore - fun testComponentRemoteAnsibleExecutorProcessNB() { + fun `handle failure on job submission`() { + + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/hello_world_job_template/", "") + } returns WebClientResponse(200, getJobTemplates(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/job_templates/$jtId/launch/", "") + } returns WebClientResponse(200, getJobTemplateLaunch(jtId)) + every { + webClientService.exchangeResource("GET", "/api/v2/inventories/?name=Demo+Inventory", "") + } returns WebClientResponse(200, getInventory()) + every { + webClientService.exchangeResource("POST", "/api/v2/job_templates/$jtId/launch/", + """{"limit":"123","tags":"some-tag","skip_tags":"some-skip-tag","inventory":1,"extra_vars":{"site_id":"3 - Belmont","tor_group":"vEPC"}}""") + } returns WebClientResponse(500, "") + val selector = mapper.readTree(endpointSelector) + val bluePrintRestLibPropertyService = mockk<BluePrintRestLibPropertyService>() + every { bluePrintRestLibPropertyService.blueprintWebClientService(selector) } returns webClientService + val awxRemoteExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService, mapper) + awxRemoteExecutor.checkDelay = 1 + + val executionServiceInput = JacksonUtils.readValueFromClassPathFile( + "payload/requests/remote-ansible-request-full.json", + ExecutionServiceInput::class.java)!! + + val bluePrintRuntimeService = createBlueprintRuntimeService(awxRemoteExecutor, executionServiceInput) + + // when runBlocking { - // val remoteScriptExecutionService = MockRemoteScriptExecutionService(bluePrintRestLibPropertyService) - val componentRemoteAnsibleExecutor = ComponentRemoteAnsibleExecutor(bluePrintRestLibPropertyService) - val bluePrintRuntime = mockk<DefaultBluePrintRuntimeService>("123456-1000") - val input = getMockedOutput(bluePrintRuntime) - componentRemoteAnsibleExecutor.bluePrintRuntimeService = bluePrintRuntime - componentRemoteAnsibleExecutor.applyNB(input) + awxRemoteExecutor.applyNB(executionServiceInput) } + + // then + val errors = bluePrintRuntimeService.getBluePrintError().errors + assertEquals(1, errors.size) } - /** - * Mocked input information for remote Ansible executor. - */ - fun getMockedOutput(svc: DefaultBluePrintRuntimeService): - ExecutionServiceInput { - val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() + private fun createBlueprintRuntimeService(awxRemoteExecutor: ComponentRemoteAnsibleExecutor, executionServiceInput: ExecutionServiceInput): BluePrintRuntimeService<MutableMap<String, JsonNode>> { + val bluePrintRuntimeService = BluePrintMetadataUtils.getBluePrintRuntime("123456-1000", + "./../../../../components/model-catalog/blueprint-model/test-blueprint/remote_ansible") + awxRemoteExecutor.bluePrintRuntimeService = bluePrintRuntimeService + + val workflowName = executionServiceInput.actionIdentifiers.actionName + // Assign Workflow inputs + val input = executionServiceInput.payload.get("$workflowName-request") + bluePrintRuntimeService.assignWorkflowInputs(workflowName, input) + + val stepMetaData: MutableMap<String, JsonNode> = hashMapOf() stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible") stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor") stepMetaData.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") - val mapper = ObjectMapper() - val rootNode = mapper.createObjectNode() - rootNode.put("ip-address", "0.0.0.0") - rootNode.put("type", "rest") - - val operationalInputs: MutableMap<String, JsonNode> = hashMapOf() - operationalInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, "execute-remote-ansible") - operationalInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, "ComponentRemoteAnsibleExecutor") - operationalInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, "process") - operationalInputs.putJsonElement("endpoint-selector", "aai") -// operationalInputs.putJsonElement("dynamic-properties", rootNode) -// operationalInputs.putJsonElement("command", "./run.sh") - operationalInputs.putJsonElement("job-template-name", "CDS_job_template2") - - every { - svc.resolveNodeTemplateInterfaceOperationInputs( - "execute-remote-ansible", - "ComponentRemoteAnsibleExecutor", "process") - } returns operationalInputs - val stepInputData = StepData().apply { name = "execute-remote-ansible" properties = stepMetaData } - - val executionServiceInput = JacksonUtils - .readValueFromClassPathFile( - "payload/requests/sample-remote-ansible-request.json", - ExecutionServiceInput::class.java)!! executionServiceInput.stepData = stepInputData + return bluePrintRuntimeService + } - val operationOutputs = hashMapOf<String, JsonNode>() - every { - svc.resolveNodeTemplateInterfaceOperationOutputs( - "execute-remote-ansible", - "ComponentRemoteAnsibleExecutor", "process") - } returns operationOutputs - val bluePrintRuntimeService = BluePrintMetadataUtils - .getBluePrintRuntime("123456-1000", - "./../../../../components/model-" + - "catalog/blueprint-model/test-blueprint/" + - "remote_ansible") -// every { -// svc.resolveNodeTemplateArtifactDefinition("execute-remote-ansible", "component-script") -// } returns bluePrintRuntimeService.resolveNodeTemplateArtifactDefinition("execute-remote-ansible", -// "component-script") - every { - svc.setNodeTemplateAttributeValue( - "execute-remote-ansible", - "execute-command-status", - "successful".asJsonPrimitive()) - } returns Unit + private fun getJobTemplates(jtId: Int) = """{ + "id": $jtId, + "type": "job_template", + "url": "/api/v2/job_templates/$jtId/", + "related": { + "named_url": "/api/v2/job_templates/hello_world_job_template/", + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "labels": "/api/v2/job_templates/$jtId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/job_templates/$jtId/extra_credentials/", + "credentials": "/api/v2/job_templates/$jtId/credentials/", + "last_job": "/api/v2/jobs/222/", + "jobs": "/api/v2/job_templates/$jtId/jobs/", + "schedules": "/api/v2/job_templates/$jtId/schedules/", + "activity_stream": "/api/v2/job_templates/$jtId/activity_stream/", + "launch": "/api/v2/job_templates/$jtId/launch/", + "notification_templates_any": "/api/v2/job_templates/$jtId/notification_templates_any/", + "notification_templates_success": "/api/v2/job_templates/$jtId/notification_templates_success/", + "notification_templates_error": "/api/v2/job_templates/$jtId/notification_templates_error/", + "access_list": "/api/v2/job_templates/$jtId/access_list/", + "survey_spec": "/api/v2/job_templates/$jtId/survey_spec/", + "object_roles": "/api/v2/job_templates/$jtId/object_roles/", + "instance_groups": "/api/v2/job_templates/$jtId/instance_groups/", + "slice_workflow_jobs": "/api/v2/job_templates/$jtId/slice_workflow_jobs/", + "copy": "/api/v2/job_templates/$jtId/copy/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "last_job": { + "id": 222, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "finished": "2019-06-12T11:20:27.892787Z", + "status": "successful", + "failed": false + }, + "last_update": { + "id": 222, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "status": "successful", + "failed": false + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "object_roles": { + "admin_role": { + "description": "Can manage all aspects of the job template", + "name": "Admin", + "id": 51 + }, + "execute_role": { + "description": "May run the job template", + "name": "Execute", + "id": 52 + }, + "read_role": { + "description": "May view settings for the job template", + "name": "Read", + "id": 53 + } + }, + "user_capabilities": { + "edit": true, + "delete": true, + "start": true, + "schedule": true, + "copy": true + }, + "labels": { + "count": 0, + "results": [] + }, + "survey": { + "title": "", + "description": "" + }, + "recent_jobs": [ + { + "id": 222, + "status": "successful", + "finished": "2019-06-12T11:20:27.892787Z", + "type": "job" + }, + { + "id": 65, + "status": "successful", + "finished": "2019-06-03T18:27:19.114796Z", + "type": "job" + }, + { + "id": 64, + "status": "successful", + "finished": "2019-06-03T18:26:53.606618Z", + "type": "job" + }, + { + "id": 63, + "status": "successful", + "finished": "2019-06-03T18:24:36.072943Z", + "type": "job" + }, + { + "id": 62, + "status": "successful", + "finished": "2019-06-03T18:17:50.616528Z", + "type": "job" + }, + { + "id": 61, + "status": "successful", + "finished": "2019-06-03T18:04:42.995611Z", + "type": "job" + }, + { + "id": 60, + "status": "successful", + "finished": "2019-06-03T17:47:13.983951Z", + "type": "job" + }, + { + "id": 50, + "status": "successful", + "finished": "2019-05-30T15:47:55.700161Z", + "type": "job" + }, + { + "id": 49, + "status": "successful", + "finished": "2019-05-29T14:46:51.615926Z", + "type": "job" + }, + { + "id": 47, + "status": "successful", + "finished": "2019-05-27T20:23:58.656709Z", + "type": "job" + } + ], + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-05-21T19:28:05.953730Z", + "modified": "2019-05-21T20:06:55.728697Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "last_job_run": "2019-06-12T11:20:27.892787Z", + "last_job_failed": false, + "next_job_run": null, + "status": "successful", + "host_config_key": "", + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "survey_enabled": true, + "become_enabled": false, + "diff_mode": false, + "allow_simultaneous": false, + "custom_virtualenv": null, + "job_slice_count": 1, + "credential": null, + "vault_credential": null + }""" - every { - svc.setNodeTemplateAttributeValue( - "execute-remote-ansible", - "execute-command-logs", "N/A".asJsonPrimitive()) - } returns Unit + private fun getJobTemplateLaunch(jtId: Int) = """{ + "can_start_without_user_input": false, + "passwords_needed_to_start": [], + "ask_variables_on_launch": true, + "ask_tags_on_launch": true, + "ask_diff_mode_on_launch": false, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_limit_on_launch": true, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "survey_enabled": true, + "variables_needed_to_start": [ + "tor_group", + "site_id" + ], + "credential_needed_to_start": false, + "inventory_needed_to_start": false, + "job_template_data": { + "name": "hello_world_job_template", + "id": $jtId, + "description": "hello_world Runner Job Template" + }, + "defaults": { + "extra_vars": "", + "diff_mode": false, + "limit": "", + "job_tags": "", + "skip_tags": "", + "job_type": "run", + "verbosity": 0, + "inventory": { + "name": "Demo Inventory", + "id": 1 + } + } + }""" - every { - svc.setNodeTemplateAttributeValue( - "execute-remote-ansible", - "execute-command-logs", - "processed successfully".asJsonPrimitive()) - } returns Unit + private fun getInventory() = """{ + "count": 1, + "next": null, + "previous": null, + "results": [ + { + "id": 1, + "type": "inventory", + "url": "/api/v2/inventories/1/", + "related": { + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "hosts": "/api/v2/inventories/1/hosts/", + "groups": "/api/v2/inventories/1/groups/", + "root_groups": "/api/v2/inventories/1/root_groups/", + "variable_data": "/api/v2/inventories/1/variable_data/", + "script": "/api/v2/inventories/1/script/", + "tree": "/api/v2/inventories/1/tree/", + "inventory_sources": "/api/v2/inventories/1/inventory_sources/", + "update_inventory_sources": "/api/v2/inventories/1/update_inventory_sources/", + "activity_stream": "/api/v2/inventories/1/activity_stream/", + "job_templates": "/api/v2/inventories/1/job_templates/", + "ad_hoc_commands": "/api/v2/inventories/1/ad_hoc_commands/", + "access_list": "/api/v2/inventories/1/access_list/", + "object_roles": "/api/v2/inventories/1/object_roles/", + "instance_groups": "/api/v2/inventories/1/instance_groups/", + "copy": "/api/v2/inventories/1/copy/", + "organization": "/api/v2/organizations/1/" + }, + "summary_fields": { + "organization": { + "id": 1, + "name": "Default", + "description": "" + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "object_roles": { + "admin_role": { + "description": "Can manage all aspects of the inventory", + "name": "Admin", + "id": 21 + }, + "update_role": { + "description": "May update project or inventory or group using the configured source update system", + "name": "Update", + "id": 22 + }, + "adhoc_role": { + "description": "May run ad hoc commands on an inventory", + "name": "Ad Hoc", + "id": 23 + }, + "use_role": { + "description": "Can use the inventory in a job template", + "name": "Use", + "id": 24 + }, + "read_role": { + "description": "May view settings for the inventory", + "name": "Read", + "id": 25 + } + }, + "user_capabilities": { + "edit": true, + "delete": true, + "copy": true, + "adhoc": true + } + }, + "created": "2019-05-21T15:45:31.954359Z", + "modified": "2019-05-21T15:45:31.954378Z", + "name": "Demo Inventory", + "description": "", + "organization": 1, + "kind": "", + "host_filter": null, + "variables": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "insights_credential": null, + "pending_deletion": false + } + ] + }""" - every { - svc.bluePrintContext() - } returns bluePrintRuntimeService.bluePrintContext() - return executionServiceInput - } + private fun newJobTemplateLaunch(jtId: Int, jobId: Int) = """{ + "job": $jobId, + "ignored_fields": {}, + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.016410Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "pending", + "failed": false, + "started": null, + "finished": null, + "elapsed": 0, + "job_args": "", + "job_cwd": "", + "job_env": {}, + "job_explanation": "", + "execution_node": "", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": null, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "credential": null, + "vault_credential": null + }""" + + private fun getJobStatus1(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "waiting", + "failed": false, + "started": null, + "finished": null, + "elapsed": 0, + "job_args": "", + "job_cwd": "", + "job_env": {}, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": {}, + "playbook_counts": { + "play_count": 0, + "task_count": 0 + }, + "custom_virtualenv": null, + "credential": null, + "vault_credential": null + }""" + + private fun getJobStatus2(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "running", + "failed": false, + "started": "2019-06-12T11:21:27.510766Z", + "finished": null, + "elapsed": 10.862184, + "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]", + "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder", + "job_env": { + "HOSTNAME": "awx", + "LC_ALL": "en_US.UTF-8", + "VIRTUAL_ENV": "/var/lib/awx/venv/ansible", + "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "SUPERVISOR_GROUP_NAME": "tower-processes", + "PWD": "/var/lib/awx", + "LANG": "en_US.UTF-8", + "PS1": "(awx) ", + "SUPERVISOR_ENABLED": "1", + "HOME": "/var/lib/awx", + "SHLVL": "2", + "LANGUAGE": "en_US.UTF-8", + "LC_CTYPE": "en_US.UTF-8", + "SUPERVISOR_PROCESS_NAME": "dispatcher", + "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock", + "DJANGO_SETTINGS_MODULE": "awx.settings.production", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "TZ": "UTC", + "ANSIBLE_FORCE_COLOR": "True", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible", + "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4", + "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:", + "JOB_ID": "$jobId", + "INVENTORY_ID": "1", + "PROJECT_REVISION": "", + "ANSIBLE_RETRY_FILES_ENABLED": "False", + "MAX_EVENT_RES": "700000", + "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback", + "AWX_HOST": "https://towerhost", + "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp", + "ANSIBLE_STDOUT_CALLBACK": "awx_display", + "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId" + }, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": {}, + "playbook_counts": { + "play_count": 1, + "task_count": 1 + }, + "custom_virtualenv": "/var/lib/awx/venv/ansible", + "credential": null, + "vault_credential": null + }""" + + private fun getJobStatus3(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "running", + "failed": false, + "started": "2019-06-12T11:21:27.510766Z", + "finished": null, + "elapsed": 21.297881, + "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]", + "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder", + "job_env": { + "HOSTNAME": "awx", + "LC_ALL": "en_US.UTF-8", + "VIRTUAL_ENV": "/var/lib/awx/venv/ansible", + "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "SUPERVISOR_GROUP_NAME": "tower-processes", + "PWD": "/var/lib/awx", + "LANG": "en_US.UTF-8", + "PS1": "(awx) ", + "SUPERVISOR_ENABLED": "1", + "HOME": "/var/lib/awx", + "SHLVL": "2", + "LANGUAGE": "en_US.UTF-8", + "LC_CTYPE": "en_US.UTF-8", + "SUPERVISOR_PROCESS_NAME": "dispatcher", + "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock", + "DJANGO_SETTINGS_MODULE": "awx.settings.production", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "TZ": "UTC", + "ANSIBLE_FORCE_COLOR": "True", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible", + "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4", + "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:", + "JOB_ID": "$jobId", + "INVENTORY_ID": "1", + "PROJECT_REVISION": "", + "ANSIBLE_RETRY_FILES_ENABLED": "False", + "MAX_EVENT_RES": "700000", + "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback", + "AWX_HOST": "https://towerhost", + "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp", + "ANSIBLE_STDOUT_CALLBACK": "awx_display", + "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId" + }, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": false, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": {}, + "playbook_counts": { + "play_count": 1, + "task_count": 2 + }, + "custom_virtualenv": "/var/lib/awx/venv/ansible", + "credential": null, + "vault_credential": null + } """ + + private fun getJobStatus4(jtId: Int, jobId: Int) = """{ + "id": $jobId, + "type": "job", + "url": "/api/v2/jobs/$jobId/", + "related": { + "created_by": "/api/v2/users/1/", + "labels": "/api/v2/jobs/$jobId/labels/", + "inventory": "/api/v2/inventories/1/", + "project": "/api/v2/projects/8/", + "extra_credentials": "/api/v2/jobs/$jobId/extra_credentials/", + "credentials": "/api/v2/jobs/$jobId/credentials/", + "unified_job_template": "/api/v2/job_templates/$jtId/", + "stdout": "/api/v2/jobs/$jobId/stdout/", + "job_events": "/api/v2/jobs/$jobId/job_events/", + "job_host_summaries": "/api/v2/jobs/$jobId/job_host_summaries/", + "activity_stream": "/api/v2/jobs/$jobId/activity_stream/", + "notifications": "/api/v2/jobs/$jobId/notifications/", + "job_template": "/api/v2/job_templates/$jtId/", + "cancel": "/api/v2/jobs/$jobId/cancel/", + "create_schedule": "/api/v2/jobs/$jobId/create_schedule/", + "relaunch": "/api/v2/jobs/$jobId/relaunch/" + }, + "summary_fields": { + "inventory": { + "id": 1, + "name": "Demo Inventory", + "description": "", + "has_active_failures": false, + "total_hosts": 1, + "hosts_with_active_failures": 0, + "total_groups": 0, + "groups_with_active_failures": 0, + "has_inventory_sources": false, + "total_inventory_sources": 0, + "inventory_sources_with_failures": 0, + "organization_id": 1, + "kind": "" + }, + "project": { + "id": 8, + "name": "cds_playbooks", + "description": "CDS - cds_playbooks Project", + "status": "ok", + "scm_type": "" + }, + "job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template" + }, + "unified_job_template": { + "id": $jtId, + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "unified_job_type": "job" + }, + "instance_group": { + "name": "tower", + "id": 1 + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "user_capabilities": { + "delete": true, + "start": true + }, + "labels": { + "count": 0, + "results": [] + }, + "extra_credentials": [], + "credentials": [] + }, + "created": "2019-06-12T11:21:26.891986Z", + "modified": "2019-06-12T11:21:27.355185Z", + "name": "hello_world_job_template", + "description": "hello_world Runner Job Template", + "job_type": "run", + "inventory": 1, + "project": 8, + "playbook": "hello_world.yml", + "forks": 0, + "limit": "", + "verbosity": 0, + "extra_vars": "{\"tor_group\": \"vEPC\", \"site_id\": \"3 - Belmont\"}", + "job_tags": "", + "force_handlers": false, + "skip_tags": "", + "start_at_task": "", + "timeout": 0, + "use_fact_cache": false, + "unified_job_template": $jtId, + "launch_type": "manual", + "status": "successful", + "failed": false, + "started": "2019-06-12T11:21:27.510766Z", + "finished": "2019-06-12T11:21:48.993385Z", + "elapsed": 21.483, + "job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-i\", \"/tmp/awx_223_ft8hu4p4/tmptmtwllu4\", \"-e\", \"@/tmp/awx_223_ft8hu4p4/env/extravars\", \"hello_world.yml\"]", + "job_cwd": "/var/lib/awx/projects/cds_playbooks_folder", + "job_env": { + "HOSTNAME": "awx", + "LC_ALL": "en_US.UTF-8", + "VIRTUAL_ENV": "/var/lib/awx/venv/ansible", + "PATH": "/var/lib/awx/venv/ansible/bin:/var/lib/awx/venv/awx/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "SUPERVISOR_GROUP_NAME": "tower-processes", + "PWD": "/var/lib/awx", + "LANG": "en_US.UTF-8", + "PS1": "(awx) ", + "SUPERVISOR_ENABLED": "1", + "HOME": "/var/lib/awx", + "SHLVL": "2", + "LANGUAGE": "en_US.UTF-8", + "LC_CTYPE": "en_US.UTF-8", + "SUPERVISOR_PROCESS_NAME": "dispatcher", + "SUPERVISOR_SERVER_URL": "unix:///tmp/supervisor.sock", + "DJANGO_SETTINGS_MODULE": "awx.settings.production", + "DJANGO_LIVE_TEST_SERVER_ADDRESS": "localhost:9013-9199", + "TZ": "UTC", + "ANSIBLE_FORCE_COLOR": "True", + "ANSIBLE_HOST_KEY_CHECKING": "False", + "ANSIBLE_INVENTORY_UNPARSED_FAILED": "True", + "ANSIBLE_PARAMIKO_RECORD_HOST_KEYS": "False", + "ANSIBLE_VENV_PATH": "/var/lib/awx/venv/ansible", + "AWX_PRIVATE_DATA_DIR": "/tmp/awx_223_ft8hu4p4", + "PYTHONPATH": "/var/lib/awx/venv/ansible/lib/python2.7/site-packages:/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/lib:", + "JOB_ID": "$jobId", + "INVENTORY_ID": "1", + "PROJECT_REVISION": "", + "ANSIBLE_RETRY_FILES_ENABLED": "False", + "MAX_EVENT_RES": "700000", + "ANSIBLE_CALLBACK_PLUGINS": "/var/lib/awx/venv/awx/lib64/python3.6/site-packages/awx/plugins/callback", + "AWX_HOST": "https://towerhost", + "ANSIBLE_SSH_CONTROL_PATH_DIR": "/tmp/awx_223_ft8hu4p4/cp", + "ANSIBLE_STDOUT_CALLBACK": "awx_display", + "AWX_ISOLATED_DATA_DIR": "/tmp/awx_223_ft8hu4p4/artifacts/$jobId" + }, + "job_explanation": "", + "execution_node": "awx", + "controller_node": "", + "result_traceback": "", + "event_processing_finished": true, + "job_template": $jtId, + "passwords_needed_to_start": [], + "ask_diff_mode_on_launch": false, + "ask_variables_on_launch": true, + "ask_limit_on_launch": true, + "ask_tags_on_launch": true, + "ask_skip_tags_on_launch": true, + "ask_job_type_on_launch": false, + "ask_verbosity_on_launch": false, + "ask_inventory_on_launch": true, + "ask_credential_on_launch": true, + "allow_simultaneous": false, + "artifacts": {}, + "scm_revision": "", + "instance_group": 1, + "diff_mode": false, + "job_slice_number": 0, + "job_slice_count": 1, + "host_status_counts": { + "ok": 1 + }, + "playbook_counts": { + "play_count": 1, + "task_count": 2 + }, + "custom_virtualenv": "/var/lib/awx/venv/ansible", + "credential": null, + "vault_credential": null + }""" + + private fun getReport() = """ + +PLAY [Hello World Sample] ****************************************************** + +TASK [Gathering Facts] ********************************************************* +ok: [localhost] + +TASK [Hello Message] *********************************************************** +ok: [localhost] => { + "msg": "Hello World!" } -//class MockRemoteScriptExecutionService : RemoteScriptExecutionService { -// override suspend fun init(selector: String) { -// } -// -// override suspend fun prepareEnv(prepareEnvInput: PrepareRemoteEnvInput): RemoteScriptExecutionOutput { -// assertEquals(prepareEnvInput.requestId, "123456-1000", "failed to match request id") -// assertNotNull(prepareEnvInput.packages, "failed to get packages") -// -// val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>() -// every { remoteScriptExecutionOutput.response } returns "prepared successfully" -// every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS -// return remoteScriptExecutionOutput -// } -// -// override suspend fun executeCommand(remoteExecutionInput: RemoteScriptExecutionInput): RemoteScriptExecutionOutput { -// assertEquals(remoteExecutionInput.requestId, "123456-1000", "failed to match request id") -// -// val remoteScriptExecutionOutput = mockk<RemoteScriptExecutionOutput>() -// every { remoteScriptExecutionOutput.response } returns "processed successfully" -// every { remoteScriptExecutionOutput.status } returns StatusType.SUCCESS -// return remoteScriptExecutionOutput -// } -// -// override suspend fun close() { -// -// } -//} +PLAY RECAP ********************************************************************* +localhost : ok=2 changed=0 unreachable=0 failed=0 + +""" +} diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/application-test.properties b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/application-test.properties new file mode 100644 index 000000000..527eb8a26 --- /dev/null +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/application-test.properties @@ -0,0 +1,35 @@ +# +# Copyright © 2017-2018 AT&T Intellectual Property. +# +# Modifications Copyright © 2019 IBM, Bell Canada. +# +# 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. +# +blueprintsprocessor.db.primary.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 +blueprintsprocessor.db.primary.username=sa +blueprintsprocessor.db.primary.password= +blueprintsprocessor.db.primary.driverClassName=org.h2.Driver +blueprintsprocessor.db.primary.hibernateHbm2ddlAuto=create-drop +blueprintsprocessor.db.primary.hibernateDDLAuto=update +blueprintsprocessor.db.primary.hibernateNamingStrategy=org.hibernate.cfg.ImprovedNamingStrategy +blueprintsprocessor.db.primary.hibernateDialect=org.hibernate.dialect.H2Dialect +# Controller Blueprints Core Configuration +blueprintsprocessor.blueprintDeployPath=./target/blueprints/deploy +blueprintsprocessor.blueprintArchivePath=./target/blueprints/archive + +# Python executor +blueprints.processor.functions.python.executor.executionPath=./../../../../components/scripts/python/ccsdk_blueprints +blueprints.processor.functions.python.executor.modulePaths=./../../../../components/scripts/python/ccsdk_blueprints + +# Executor Options +blueprintprocessor.netconfExecutor.enabled=true
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/payload/requests/remote-ansible-request-full.json b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/payload/requests/remote-ansible-request-full.json new file mode 100644 index 000000000..11bb90b50 --- /dev/null +++ b/ms/blueprintsprocessor/functions/ansible-awx-executor/src/test/resources/payload/requests/remote-ansible-request-full.json @@ -0,0 +1,32 @@ +{ + "actionIdentifiers": { + "blueprintName": "remote_ansible", + "blueprintVersion": "1.0.0", + "actionName": "execute-remote-ansible", + "mode": "sync" + }, + "commonHeader": { + "flags": { + "force": true, + "ttl": 3600 + }, + "originatorId": "mock", + "requestId": "123456-2000", + "subRequestId": "sub-123456-1000", + "timestamp": "2012-04-23T18:25:43.511Z" + }, + "payload": { + "execute-remote-ansible-request": { + "endpoint-selector": "awx", + "job-template-name": "hello_world_job_template", + "inventory": "Demo Inventory", + "limit": "123", + "tags": "some-tag", + "skip-tags": "some-skip-tag", + "extra-vars": { + "site_id": "3 - Belmont", + "tor_group": "vEPC" + } + } + } +} diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt index b1121b3d4..4daaceeff 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImpl.kt @@ -101,7 +101,6 @@ class NetconfSessionImpl(private val deviceInfo: DeviceInfo, private val rpcServ return streamHandler.getFutureFromSendMessage(streamHandler.sendMessage(formattedRequest, messageId), replyTimeout.toLong(), TimeUnit.SECONDS) } catch (e: InterruptedException) { - Thread.currentThread().interrupt() throw NetconfException("$deviceInfo: Interrupted while waiting for reply for request: $formattedRequest", e) } catch (e: TimeoutException) { throw NetconfException("$deviceInfo: Timed out while waiting for reply for request $formattedRequest after $replyTimeout sec.", diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicatorTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicatorTest.kt index cb023fd9a..47c729187 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicatorTest.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfDeviceCommunicatorTest.kt @@ -24,19 +24,15 @@ import io.mockk.mockk import io.mockk.spyk import io.mockk.verify import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.NetconfReceivedEvent import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.NetconfSession import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.NetconfSessionListener import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.utils.RpcMessageUtils -import java.io.ByteArrayInputStream import java.io.IOException import java.io.InputStream import java.io.OutputStream -import java.io.Reader -import java.io.Writer import java.nio.charset.StandardCharsets import java.util.concurrent.CompletableFuture import java.util.concurrent.ConcurrentHashMap @@ -62,13 +58,12 @@ class NetconfDeviceCommunicatorTest { | |#4 |<rpc - | |#18 | message-id="102" | |#79 - | xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> - | <close-session/> + | xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + | <close-session/> |</rpc> |## |""".trimMargin() @@ -176,7 +171,6 @@ class NetconfDeviceCommunicatorTest { assertEquals("", eventSlot.captured.messagePayload) } - @Ignore //TODO: Not clear on validateChunkedFraming, the size validation part could be discarding valid msg.. @Test fun `NetconfDeviceCommunicator in END_CHUNKED_PATTERN passing validation generates DEVICE_REPLY`() { val eventSlot = CapturingSlot<NetconfReceivedEvent>() @@ -190,7 +184,12 @@ class NetconfDeviceCommunicatorTest { assertTrue { eventSlot.isCaptured } //eventually, sessionListener is called with message type DEVICE_REPLY assertEquals(NetconfReceivedEvent.Type.DEVICE_REPLY, eventSlot.captured.type) - assertEquals("", eventSlot.captured.messagePayload) + assertEquals(""" +<rpc message-id="102" + xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> + <close-session/> +</rpc> + """.trimIndent(), eventSlot.captured.messagePayload) } @Test @@ -199,7 +198,7 @@ class NetconfDeviceCommunicatorTest { fun `chunked sample is validated by the chunked response regex`() { val test1 = "\n#10\nblah\n##\n" val chunkedFramingPattern = Pattern.compile("(\\n#([1-9][0-9]*)\\n(.+))+\\n##\\n", Pattern.DOTALL) - val matcher = chunkedFramingPattern.matcher(validChunkedEncodedMsg) + val matcher = chunkedFramingPattern.matcher(test1) assertTrue { matcher.matches() } } diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImplTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImplTest.kt index f5fd5410a..7f6c8d390 100644 --- a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImplTest.kt +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/core/NetconfSessionImplTest.kt @@ -32,7 +32,6 @@ import org.apache.sshd.client.future.DefaultOpenFuture import org.apache.sshd.client.session.ClientSession import org.apache.sshd.common.FactoryManager import org.junit.Before -import org.junit.Ignore import org.junit.Test import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.DeviceInfo import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.DeviceResponse @@ -278,7 +277,6 @@ class NetconfSessionImplTest { verify(exactly = 1) { netconfSessionSpy.clearReplies() } } - @Ignore //TODO //Test for handling CompletableFuture.get returns InterruptedException inside NetconfDeviceCommunicator @Test fun `syncRpc throws NetconfException if InterruptedException is caught`() { @@ -360,19 +358,21 @@ class NetconfSessionImplTest { } @Test - @Ignore - //TODO: get 't' inside asyncRpc to be a Throwable fun `asyncRpc wraps exception`() { - assertFailsWith(exceptionClass = NetconfException::class, message = futureMsg) { - val netconfSessionSpy = spyk(netconfSession) - val futureRet: CompletableFuture<String> = CompletableFuture.supplyAsync { - throw Exception("blah") - } - futureRet.completeExceptionally(IOException("something is wrong")) - every { netconfCommunicator.sendMessage(any(), any()) } returns futureRet - //RUN - val rpcResultFuture = netconfSessionSpy.asyncRpc("0", "0") + val netconfSessionSpy = spyk(netconfSession) + every { netconfSessionSpy.checkAndReestablish() } just Runs + val futureRet: CompletableFuture<String> = CompletableFuture.supplyAsync { + throw Exception("blah") + } + every { netconfCommunicator.sendMessage(any(), any()) } returns futureRet + //run the method + val rpcResultFuture = netconfSessionSpy.asyncRpc("0", "0") + every { netconfSessionSpy.checkAndReestablish() } just Runs + val e = assertFailsWith(exceptionClass = ExecutionException::class, message = futureMsg) { + rpcResultFuture.get() } + val cause = e.cause + assertTrue { cause is NetconfException } } @Test diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtilsTest.kt b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtilsTest.kt new file mode 100644 index 000000000..e24659d1d --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/functions/netconf/executor/utils/NetconfMessageUtilsTest.kt @@ -0,0 +1,179 @@ +package org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.utils + +import org.junit.Assert.* +import org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor.api.NetconfException +import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils +import kotlin.test.Test +import kotlin.test.assertFailsWith + +class NetconfMessageUtilsTest { + + @Test + fun `test getConfig with all parameters present`() { + val outcome = NetconfMessageUtils.getConfig("customMessageId", "customConfigType", "customFilterContent") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/getConfig-response-all-parameters.xml") + assertEquals("getConfig return was not correct", expectation, outcome) + } + + @Test + fun `test getConfig with filterContent parameter null`() { + val outcome = NetconfMessageUtils.getConfig("customMessageId", "customConfigType",null) + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/getConfig-response-filterContent-null.xml") + assertEquals("getConfig return was not correct", expectation, outcome) + } + + @Test + fun `test doWrappedRpc`() { + val outcome = NetconfMessageUtils.doWrappedRpc("customMessageId", "customRequest") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/doWrappedRpc-response.xml") + assertEquals("doWrappedRpc return was not correct", expectation, outcome) + } + + @Test + fun `test editConfig with all parameters present`() { + val outcome = NetconfMessageUtils.editConfig("customMessageId", "customConfigType", "customDefaultOperation", + "customNewConfiguration") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/editConfig-response-all-parameters.xml") + assertEquals("editConfig return was not correct", expectation, outcome) + } + + @Test + fun `test editConfig with defaultOperation parameter null`() { + val outcome = NetconfMessageUtils.editConfig("customMessageId", "customConfigType", null, + "customNewConfiguration") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/editConfig-response-defaultOperation-null.xml") + assertEquals("editConfig return was not correct", expectation, outcome) + } + + @Test + fun `test validate`() { + val outcome = NetconfMessageUtils.validate("customMessageId", "customConfigType") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/validate-response.xml") + assertEquals("validate return was not correct", expectation, outcome) + } + + @Test + fun `test commit with both persistId and persist non-empty`() { + assertFailsWith(exceptionClass = NetconfException::class, message = "commit should have thrown an exception") { + NetconfMessageUtils.commit("customMessageId", false, 1, "customPersist", "customPersistId") + } + } + + @Test + fun `test commit with confirmed true, persist empty and persistId non-empty`() { + assertFailsWith(exceptionClass = NetconfException::class, message = "commit should have thrown an exception") { + NetconfMessageUtils.commit("customMessageId", true, 1, "", "customPersistId") + } + } + + @Test + fun `test commit with confirmed true, persistId empty and persist empty`() { + val outcome = NetconfMessageUtils.commit("customMessageId", true, 1, "", "") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/commit-response-confirmed-true-and-persistId-empty-and-persist-empty.xml") + assertEquals("commit return was not correct", expectation, outcome) + } + + @Test + fun `test commit with confirmed false, persistId non-empty and persist empty`() { + val outcome = NetconfMessageUtils.commit("customMessageId", false, 1, "", "customPersistId") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/commit-response-confirmed-false-and-persistId-empty-and-persist-not-empty.xml") + assertEquals("commit return was not correct", expectation, outcome) + } + + @Test + fun `test commit with confirmed false, persistId empty and persist non-empty`() { + val outcome = NetconfMessageUtils.commit("customMessageId", false, 1, "customPersist", "") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/commit-response-confirmed-false-and-persistId-not-empty-and-persist-empty.xml") + assertEquals("commit return was not correct", expectation, outcome) + } + + @Test + fun `test cancelCommit with all parameters not empty`() { + val outcome = NetconfMessageUtils.cancelCommit("customMessageId", "customPersistId") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/cancelCommit-response-all-parameters-not-empty.xml") + assertEquals("cancelCommit return was not correct", expectation, outcome) + } + + @Test + fun `test cancelCommit with persistId empty`() { + val outcome = NetconfMessageUtils.cancelCommit("customMessageId", "") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/cancelCommit-response-persistId-empty.xml") + assertEquals("cancelCommit return was not correct", expectation, outcome) + } + + @Test + fun `test unlock with all parameters not empty`() { + val outcome = NetconfMessageUtils.unlock("customMessageId", "customConfigType") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/unlock-response-all-parameters-not-empty.xml") + assertEquals("unlock return was not correct", expectation, outcome) + } + + @Test + fun `test deleteConfig with all parameters not empty`() { + val outcome = NetconfMessageUtils.deleteConfig("customMessageId", "customConfigType") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/deleteConfig-response-all-parameters-not-empty.xml") + assertEquals("deleteConfig return was not correct", expectation, outcome) + } + + @Test + fun `test deleteConfig with configType equals to NetconfDatastore_RUNNING_datastore`() { + assertFailsWith(exceptionClass = NetconfException::class, message = "deleteConfig should have thrown an exception") { + NetconfMessageUtils.deleteConfig("customMessageId", NetconfDatastore.RUNNING.datastore) + } + } + + @Test + fun `test discardChanges with all parameters not empty`() { + val outcome = NetconfMessageUtils.discardChanges("customMessageId") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/discardChanges-response-all-parameters-not-empty.xml") + assertEquals("discardChanges return was not correct", expectation, outcome) + } + + @Test + fun `test lock with all parameters not empty`() { + val outcome = NetconfMessageUtils.lock("customMessageId", "customConfigType") + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/lock-response-all-parameters-not-empty.xml") + assertEquals("lock return was not correct", expectation, outcome) + } + + @Test + fun `test closeSession with force true`() { + val outcome = NetconfMessageUtils.closeSession("customMessageId", true) + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/closeSession-response-force-true.xml") + assertEquals("closeSession return was not correct", expectation, outcome) + } + + @Test + fun `test closeSession with force false`() { + val outcome = NetconfMessageUtils.closeSession("customMessageId", false) + val expectation = JacksonUtils.getClassPathFileContent("netconf-messages/closeSession-response-force-false.xml") + assertEquals("closeSession return was not correct", expectation, outcome) + } + + //TODO validateRPCXML + + @Test + fun `test getMsgId with valid message`() { + val messageId = "1234" + val outcome = NetconfMessageUtils.getMsgId("message-id=\"${messageId}\"") + val expectation = messageId + assertEquals("getMsgId return was not correct", expectation, outcome) + } + + @Test + fun `test getMsgId with RpcMessageUtils_HELLO message`() { + val outcome = NetconfMessageUtils.getMsgId(RpcMessageUtils.HELLO) + val expectation = "-1" + assertEquals("getMsgId return was not correct", expectation, outcome) + } + + @Test + fun `test getMsgId with invalid message`() { + val outcome = NetconfMessageUtils.getMsgId("invalid message") + val expectation = "" + assertEquals("getMsgId return was not correct", expectation, outcome) + } + +//TODO validateChunkedFraming + +} diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/cancelCommit-response-all-parameters-not-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/cancelCommit-response-all-parameters-not-empty.xml new file mode 100644 index 000000000..7f5a44cc5 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/cancelCommit-response-all-parameters-not-empty.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<cancel-commit> +<persist-id>customPersistId</persist-id></cancel-commit> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/cancelCommit-response-persistId-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/cancelCommit-response-persistId-empty.xml new file mode 100644 index 000000000..5ffaf6fd9 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/cancelCommit-response-persistId-empty.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<cancel-commit> +</cancel-commit> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/closeSession-response-force-false.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/closeSession-response-force-false.xml new file mode 100644 index 000000000..282097b71 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/closeSession-response-force-false.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<close-session/> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/closeSession-response-force-true.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/closeSession-response-force-true.xml new file mode 100644 index 000000000..01a28d923 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/closeSession-response-force-true.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<kill-session/> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-false-and-persistId-empty-and-persist-not-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-false-and-persistId-empty-and-persist-not-empty.xml new file mode 100644 index 000000000..d19e5b41e --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-false-and-persistId-empty-and-persist-not-empty.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<commit> +<persist-id>customPersistId</persist-id></commit> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-false-and-persistId-not-empty-and-persist-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-false-and-persistId-not-empty-and-persist-empty.xml new file mode 100644 index 000000000..ac489b774 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-false-and-persistId-not-empty-and-persist-empty.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<commit> +</commit> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-true-and-persistId-empty-and-persist-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-true-and-persistId-empty-and-persist-empty.xml new file mode 100644 index 000000000..ad0fef80f --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/commit-response-confirmed-true-and-persistId-empty-and-persist-empty.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<commit> +<confirmed/><confirm-timeout>1</confirm-timeout></commit> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/deleteConfig-response-all-parameters-not-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/deleteConfig-response-all-parameters-not-empty.xml new file mode 100644 index 000000000..1758bde55 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/deleteConfig-response-all-parameters-not-empty.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<delete-config> +<target> +<customConfigType/> +</target> +</delete-config> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/discardChanges-response-all-parameters-not-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/discardChanges-response-all-parameters-not-empty.xml new file mode 100644 index 000000000..3559dd9f6 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/discardChanges-response-all-parameters-not-empty.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<discard-changes/> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/doWrappedRpc-response.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/doWrappedRpc-response.xml new file mode 100644 index 000000000..0f6c3e76b --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/doWrappedRpc-response.xml @@ -0,0 +1,3 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +customRequest</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/editConfig-response-all-parameters.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/editConfig-response-all-parameters.xml new file mode 100644 index 000000000..f4a789fea --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/editConfig-response-all-parameters.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<edit-config> +<target> +<customConfigType/> +</target> +<default-operation>customDefaultOperation</default-operation> +<config xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> +customNewConfiguration +</config> +</edit-config> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/editConfig-response-defaultOperation-null.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/editConfig-response-defaultOperation-null.xml new file mode 100644 index 000000000..8efa46e20 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/editConfig-response-defaultOperation-null.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<edit-config> +<target> +<customConfigType/> +</target> +<config xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0"> +customNewConfiguration +</config> +</edit-config> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/getConfig-response-all-parameters.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/getConfig-response-all-parameters.xml new file mode 100644 index 000000000..4135c166b --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/getConfig-response-all-parameters.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<get-config> +<source> +<customConfigType/> +</source> +<filter type="subtree"> +customFilterContent +</filter> +</get-config> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/getConfig-response-filterContent-null.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/getConfig-response-filterContent-null.xml new file mode 100644 index 000000000..dee751944 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/getConfig-response-filterContent-null.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<get-config> +<source> +<customConfigType/> +</source> +</get-config> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/lock-response-all-parameters-not-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/lock-response-all-parameters-not-empty.xml new file mode 100644 index 000000000..1329e37b5 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/lock-response-all-parameters-not-empty.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<lock> +<target> +<customConfigType/> +</target> +</lock> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/unlock-response-all-parameters-not-empty.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/unlock-response-all-parameters-not-empty.xml new file mode 100644 index 000000000..35a07f724 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/unlock-response-all-parameters-not-empty.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<unlock> +<target> +<customConfigType/> +</target> +</unlock> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/validate-response.xml b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/validate-response.xml new file mode 100644 index 000000000..3947be6e2 --- /dev/null +++ b/ms/blueprintsprocessor/functions/netconf-executor/src/test/resources/netconf-messages/validate-response.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rpc message-id="customMessageId" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> +<validate> +<source> +<customConfigType/> +</source> +</validate> +</rpc>
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml b/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml index 0cae94690..011edae95 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/pom.xml @@ -44,7 +44,15 @@ </dependency> <dependency> <groupId>org.springframework.boot</groupId> - <artifactId>spring-boot-starter-web</artifactId> + <artifactId>spring-boot-starter</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-web</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-webflux</artifactId> <scope>test</scope> </dependency> <dependency> diff --git a/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt b/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt index 21d05e620..e6a66800b 100644 --- a/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt +++ b/ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/rest/service/RestClientServiceTest.kt @@ -23,8 +23,8 @@ import com.fasterxml.jackson.databind.ObjectMapper import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.async import kotlinx.coroutines.runBlocking -import org.apache.catalina.connector.Connector -import org.junit.Ignore +import org.junit.After +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintProperties @@ -34,18 +34,17 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.autoconfigure.EnableAutoConfiguration import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory -import org.springframework.boot.web.servlet.server.ServletWebServerFactory +import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory +import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory +import org.springframework.boot.web.server.WebServer import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration import org.springframework.http.HttpMethod -import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity -import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder -import org.springframework.security.crypto.password.PasswordEncoder -import org.springframework.stereotype.Component +import org.springframework.http.server.reactive.HttpHandler +import org.springframework.security.config.web.server.ServerHttpSecurity +import org.springframework.security.core.userdetails.MapReactiveUserDetailsService +import org.springframework.security.core.userdetails.User +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.web.server.SecurityWebFilterChain import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner @@ -63,10 +62,9 @@ import kotlin.test.assertNotNull @RunWith(SpringRunner::class) @EnableAutoConfiguration(exclude = [DataSourceAutoConfiguration::class]) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) -@ContextConfiguration(classes = [BluePrintRestLibConfiguration::class, - BlueprintPropertyConfiguration::class, - SampleController::class, BluePrintProperties::class, - BluePrintProperties::class]) +@ContextConfiguration(classes = [BluePrintRestLibConfiguration::class, SampleController::class, + SecurityConfiguration::class, + BlueprintPropertyConfiguration::class, BluePrintProperties::class]) @TestPropertySource(properties = [ "server.port=8443", @@ -76,7 +74,7 @@ import kotlin.test.assertNotNull "server.ssl.keyStoreType=PKCS12", "server.ssl.keyAlias=tomcat", "blueprintsprocessor.restclient.sample.type=basic-auth", - "blueprintsprocessor.restclient.sample.url=http://127.0.0.1:8080", + "blueprintsprocessor.restclient.sample.url=http://127.0.0.1:8081", "blueprintsprocessor.restclient.sample.username=admin", "blueprintsprocessor.restclient.sample.password=jans", "blueprintsprocessor.restclient.test.type=ssl-basic-auth", @@ -87,12 +85,31 @@ import kotlin.test.assertNotNull "blueprintsprocessor.restclient.test.sslTrust=src/test/resources/keystore.p12", "blueprintsprocessor.restclient.test.sslTrustPassword=changeit" ]) -@Ignore class RestClientServiceTest { @Autowired lateinit var bluePrintRestLibPropertyService: BluePrintRestLibPropertyService + @Autowired + lateinit var httpHandler : HttpHandler + + lateinit var http : WebServer + + fun localPort() = http.port + + @Before + fun start() { + // Second Http server required for non-SSL requests to be processed along with the https server. + val factory: ReactiveWebServerFactory = NettyReactiveWebServerFactory(8081) + this.http = factory.getWebServer(this.httpHandler) + this.http.start() + } + + @After + fun stop() { + this.http.stop() + } + @Test fun testPatch() { val restClientService = bluePrintRestLibPropertyService @@ -118,7 +135,7 @@ class RestClientServiceTest { fun testSimpleBasicAuth() { val json: String = "{\n" + " \"type\" : \"basic-auth\",\n" + - " \"url\" : \"http://localhost:8080\",\n" + + " \"url\" : \"http://localhost:8081\",\n" + " \"username\" : \"admin\",\n" + " \"password\" : \"jans\"\n" + "}" @@ -308,49 +325,25 @@ open class SampleController { * Security configuration required for basic authentication with username and * password for any request in the server. */ -@Configuration -@EnableWebSecurity -open class SecurityConfig : WebSecurityConfigurerAdapter() { - - @Throws(Exception::class) - override fun configure(http: HttpSecurity) { - http - .csrf().disable() - .authorizeRequests().anyRequest().authenticated() - .and() - .httpBasic() - } +open class SecurityConfiguration { - @Autowired - @Throws(Exception::class) - open fun configureGlobal(auth: AuthenticationManagerBuilder) { - auth.inMemoryAuthentication() - .withUser("admin") - .password(passwordEncoder().encode("jans")) + @Bean + open fun userDetailsService(): MapReactiveUserDetailsService { + val user: UserDetails = User.withDefaultPasswordEncoder() + .username("admin") + .password("jans") .roles("USER") + .build() + return MapReactiveUserDetailsService(user) } @Bean - open fun passwordEncoder(): PasswordEncoder { - return BCryptPasswordEncoder() - } -} - -/** - * Http server required for http request to be processed along with the https - * server. - */ -@Component -class HttpServer { - @Bean - fun servletContainer(): ServletWebServerFactory { - - val connector = Connector(TomcatServletWebServerFactory.DEFAULT_PROTOCOL) - connector.port = 8080 - - val tomcat = TomcatServletWebServerFactory() - tomcat.addAdditionalTomcatConnectors(connector) - return tomcat + open fun springSecurityFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain { + return http + .csrf().disable() + .authorizeExchange().anyExchange().authenticated() + .and().httpBasic() + .and().build() } } diff --git a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandlerTest.kt b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandlerTest.kt index 5072b3c6a..ce5acd400 100644 --- a/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandlerTest.kt +++ b/ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/BluePrintProcessingGRPCHandlerTest.kt @@ -22,7 +22,6 @@ import com.google.protobuf.util.JsonFormat import io.grpc.stub.StreamObserver import io.grpc.testing.GrpcServerRule import org.junit.Assert -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -42,7 +41,6 @@ import org.springframework.test.context.TestPropertySource import org.springframework.test.context.junit4.SpringRunner import kotlin.test.BeforeTest -@Ignore @RunWith(SpringRunner::class) @DirtiesContext @EnableAutoConfiguration diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/scripts/BlueprintPythonInterpreterProxyTest.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/scripts/BlueprintPythonInterpreterProxyTest.kt deleted file mode 100644 index 12ef9733a..000000000 --- a/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/scripts/BlueprintPythonInterpreterProxyTest.kt +++ /dev/null @@ -1,48 +0,0 @@ -package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts - -import org.junit.Test -import org.junit.runner.RunWith -import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonUtils - -import kotlin.test.assertNotNull -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.test.context.ContextConfiguration -import org.springframework.test.context.TestPropertySource -import org.springframework.test.context.junit4.SpringRunner -import kotlin.test.BeforeTest - -@RunWith(SpringRunner::class) -@ContextConfiguration(classes = [BluePrintPython::class, PythonExecutorProperty::class, String::class]) -@TestPropertySource(properties = -["blueprints.processor.functions.python.executor.modulePaths=./../../../../../components/scripts/python/ccsdk_blueprints", - "blueprints.processor.functions.python.executor.executionPath=./../../../../../components/scripts/python/ccsdk_blueprints"]) -class BlueprintPythonInterpreterProxyTest { - - lateinit var blueprintPythonInterpreterProxy: BlueprintPythonInterpreterProxy - - @Autowired - lateinit var pythonExecutorProperty: PythonExecutorProperty - - @BeforeTest - fun init() { - val blueprintBasePath = "./../../../../../components/model-catalog/blueprint-model/test-blueprint/baseconfiguration" - val pythonPath: MutableList<String> = arrayListOf() - pythonPath.add(blueprintBasePath) - pythonPath.addAll(pythonExecutorProperty.modulePaths) - val pythonClassName = "PythonTestScript" - val content = JacksonUtils.getContent("./src/test/resources/PythonTestScript.py") - - val blueprintPython = BluePrintPython(pythonExecutorProperty.executionPath, pythonPath, arrayListOf()) - blueprintPython.content = content - blueprintPython.pythonClassName = pythonClassName - blueprintPython.moduleName = "Unit test - Blueprint Python Script [Class Name = $pythonClassName]" - - blueprintPythonInterpreterProxy = BlueprintPythonInterpreterProxy(blueprintPython) - } - - @Test - fun getPythonInterpreter() { - val pythonObject = blueprintPythonInterpreterProxy.getPythonInstance(hashMapOf()) - assertNotNull(pythonObject, "failed to get python interpreter") - } -}
\ No newline at end of file |