diff --git a/bpdm-cleaning-service-dummy/pom.xml b/bpdm-cleaning-service-dummy/pom.xml
index b79f8592e..f8c5b56d3 100644
--- a/bpdm-cleaning-service-dummy/pom.xml
+++ b/bpdm-cleaning-service-dummy/pom.xml
@@ -123,6 +123,22 @@
+
+ com.github.tomakehurst
+ wiremock-jre8-standalone
+ test
+
+
+ com.ninja-squad
+ springmockk
+ test
+
+
+ org.assertj
+ assertj-core
+ test
+
+
org.assertj
assertj-core
diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/Application.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/Application.kt
index 30730dfd5..0c84b7bf8 100644
--- a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/Application.kt
+++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/Application.kt
@@ -23,9 +23,11 @@ import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
import org.springframework.boot.context.properties.ConfigurationPropertiesScan
import org.springframework.boot.runApplication
+import org.springframework.scheduling.annotation.EnableScheduling
@SpringBootApplication(exclude=[DataSourceAutoConfiguration::class])
@ConfigurationPropertiesScan
+@EnableScheduling
class Application
fun main(args: Array) {
diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/ClientsConfig.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/ClientsConfig.kt
new file mode 100644
index 000000000..33c849960
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/ClientsConfig.kt
@@ -0,0 +1,103 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.config
+
+
+import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient
+import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClientImpl
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
+import org.springframework.context.annotation.Bean
+import org.springframework.context.annotation.Configuration
+import org.springframework.http.HttpHeaders
+import org.springframework.http.MediaType
+import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder
+import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService
+import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository
+import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction
+import org.springframework.web.reactive.function.client.WebClient
+import java.util.function.Consumer
+
+
+@Configuration
+class ClientsConfig {
+
+
+ @Bean
+ @ConditionalOnProperty(
+ value = ["bpdm.orchestrator.security-enabled"],
+ havingValue = "false",
+ matchIfMissing = true
+ )
+ fun orchestratorClientNoAuth(poolConfigProperties: OrchestratorConfigProperties): OrchestrationApiClient {
+ val url = poolConfigProperties.baseUrl
+ return OrchestrationApiClientImpl { webClientBuilder(url).build() }
+ }
+
+
+ @Bean
+ @ConditionalOnProperty(
+ value = ["bpdm.orchestrator.security-enabled"],
+ havingValue = "true"
+ )
+ fun orchestratorClientWithAuth(
+ poolConfigProperties: OrchestratorConfigProperties,
+ clientRegistrationRepository: ClientRegistrationRepository,
+ authorizedClientService: OAuth2AuthorizedClientService
+ ): OrchestrationApiClient {
+ val url = poolConfigProperties.baseUrl
+ val clientRegistrationId = poolConfigProperties.oauth2ClientRegistration
+ ?: throw IllegalArgumentException("bpdm.orchestrator.oauth2-client-registration is required if bpdm.orchestrator.security-enabled is set")
+ return OrchestrationApiClientImpl {
+ webClientBuilder(url)
+ .apply(oauth2Configuration(clientRegistrationRepository, authorizedClientService, clientRegistrationId))
+ .build()
+ }
+ }
+
+
+ private fun webClientBuilder(url: String) =
+ WebClient.builder()
+ .baseUrl(url)
+ .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
+
+ private fun oauth2Configuration(
+ clientRegistrationRepository: ClientRegistrationRepository,
+ authorizedClientService: OAuth2AuthorizedClientService,
+ clientRegistrationId: String
+ ): Consumer {
+ val authorizedClientManager = authorizedClientManager(clientRegistrationRepository, authorizedClientService)
+ val oauth = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager)
+ oauth.setDefaultClientRegistrationId(clientRegistrationId)
+ return oauth.oauth2Configuration()
+ }
+
+ private fun authorizedClientManager(
+ clientRegistrationRepository: ClientRegistrationRepository,
+ authorizedClientService: OAuth2AuthorizedClientService
+ ): OAuth2AuthorizedClientManager {
+ val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build()
+ val authorizedClientManager = AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService)
+ authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider)
+ return authorizedClientManager
+ }
+
+}
\ No newline at end of file
diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/OrchestratorConfigProperties.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/OrchestratorConfigProperties.kt
new file mode 100644
index 000000000..ba5bd6a53
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/config/OrchestratorConfigProperties.kt
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.config
+
+import org.springframework.boot.context.properties.ConfigurationProperties
+
+
+@ConfigurationProperties(prefix = "bpdm.orchestrator")
+data class OrchestratorConfigProperties(
+ val baseUrl: String = "http://localhost:8085/",
+ val securityEnabled: Boolean = false,
+ val oauth2ClientRegistration: String?
+)
diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceDummy.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceDummy.kt
new file mode 100644
index 000000000..0d367d59a
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceDummy.kt
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.service
+
+
+import mu.KotlinLogging
+import org.eclipse.tractusx.bpdm.common.dto.AddressType
+import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient
+import org.eclipse.tractusx.orchestrator.api.model.*
+import org.springframework.scheduling.annotation.Scheduled
+import org.springframework.stereotype.Service
+import java.util.*
+
+@Service
+class CleaningServiceDummy(
+ private val orchestrationApiClient: OrchestrationApiClient,
+
+ ) {
+
+ private val logger = KotlinLogging.logger { }
+
+
+ @Scheduled(cron = "\${cleaningService.pollingCron:-}", zone = "UTC")
+ fun pollForCleaningTasks() {
+ try {
+ logger.info { "Starting polling for cleaning tasks from Orchestrator..." }
+
+ // Step 1: Fetch and reserve the next cleaning request
+ val cleaningRequest = orchestrationApiClient.goldenRecordTasks
+ .reserveTasksForStep(TaskStepReservationRequest(amount = 10, TaskStep.CleanAndSync))
+
+ val cleaningTasks = cleaningRequest.reservedTasks
+
+ logger.info { "${cleaningTasks.size} tasks found for cleaning. Proceeding with cleaning..." }
+
+ if (cleaningTasks.isNotEmpty()) {
+
+ val cleaningResults = cleaningTasks.map { reservedTask ->
+ // Step 2: Generate dummy cleaning results
+ processCleaningTask(reservedTask)
+ }
+
+ // Step 3: Send the cleaning result back to the Orchestrator
+ orchestrationApiClient.goldenRecordTasks.resolveStepResults(TaskStepResultRequest(cleaningResults))
+ logger.info { "Cleaning tasks processing completed for this iteration." }
+ }
+ } catch (e: Exception) {
+ logger.error(e) { "Error while processing cleaning task" }
+ }
+ }
+
+ fun processCleaningTask(reservedTask: TaskStepReservationEntryDto): TaskStepResultEntryDto {
+ val genericBusinessPartner = reservedTask.businessPartner.generic
+
+ val addressPartner = createAddressRepresentation(genericBusinessPartner)
+
+ val addressType = genericBusinessPartner.postalAddress.addressType ?: AddressType.AdditionalAddress
+
+ val legalEntityDto = createLegalEntityRepresentation(addressPartner, addressType, genericBusinessPartner)
+
+ val siteDto = createSiteDtoIfNeeded(genericBusinessPartner, addressPartner)
+
+ val addressDto = shouldCreateAddress(addressType, addressPartner)
+
+ return TaskStepResultEntryDto(reservedTask.taskId, BusinessPartnerFullDto(genericBusinessPartner, legalEntityDto, siteDto, addressDto))
+ }
+
+ private fun shouldCreateAddress(
+ addressType: AddressType,
+ addressPartner: LogisticAddressDto
+ ): LogisticAddressDto? {
+ val addressDto = if (addressType == AddressType.AdditionalAddress) {
+ addressPartner
+ } else {
+ null
+ }
+ return addressDto
+ }
+
+ fun createSiteDtoIfNeeded(businessPartner: BusinessPartnerGenericDto, addressPartner: LogisticAddressDto): SiteDto? {
+ if (!shouldCreateSite(businessPartner)) return null
+
+ val siteAddressReference = when (businessPartner.postalAddress.addressType) {
+ AddressType.SiteMainAddress, AddressType.LegalAndSiteMainAddress -> addressPartner.bpnAReference
+ else -> generateNewBpnRequestIdentifier()
+ }
+
+ val siteMainAddress = addressPartner.copy(bpnAReference = siteAddressReference)
+ return createSiteRepresentation(businessPartner, siteMainAddress)
+ }
+
+ fun createLegalEntityRepresentation(
+ addressPartner: LogisticAddressDto,
+ addressType: AddressType,
+ genericPartner: BusinessPartnerGenericDto
+ ): LegalEntityDto {
+ val legalAddressBpnReference = if (addressType == AddressType.LegalAddress || addressType == AddressType.LegalAndSiteMainAddress) {
+ addressPartner.bpnAReference
+ } else {
+ generateNewBpnRequestIdentifier()
+ }
+
+ val legalAddress = addressPartner.copy(bpnAReference = legalAddressBpnReference)
+
+ val bpnReferenceDto = createBpnReference(genericPartner.bpnL)
+
+ return genericPartner.toLegalEntityDto(bpnReferenceDto, legalAddress)
+
+ }
+
+ fun createAddressRepresentation(genericPartner: BusinessPartnerGenericDto): LogisticAddressDto {
+ val bpnReferenceDto = createBpnReference(genericPartner.bpnA)
+ return genericPartner.toLogisticAddressDto(bpnReferenceDto)
+ }
+
+ fun createSiteRepresentation(genericPartner: BusinessPartnerGenericDto, siteAddressReference: LogisticAddressDto): SiteDto {
+ val legalName = genericPartner.nameParts.joinToString(" ")
+ val bpnReferenceDto = createBpnReference(genericPartner.bpnS)
+ return genericPartner.toSiteDto(bpnReferenceDto, legalName, siteAddressReference)
+ }
+
+ fun createBpnReference(bpn: String?): BpnReferenceDto {
+ return if (bpn != null) {
+ BpnReferenceDto(bpn, BpnReferenceType.Bpn)
+ } else {
+ // Generate a new UUID and create a BpnReferenceDto object if bpnL/bpnS/bpnA is null
+ generateNewBpnRequestIdentifier()
+ }
+ }
+
+ private fun generateNewBpnRequestIdentifier() = BpnReferenceDto(UUID.randomUUID().toString(), BpnReferenceType.BpnRequestIdentifier)
+
+ fun shouldCreateSite(genericPartner: BusinessPartnerGenericDto): Boolean {
+ return genericPartner.postalAddress.addressType == AddressType.SiteMainAddress ||
+ genericPartner.postalAddress.addressType == AddressType.LegalAndSiteMainAddress ||
+ genericPartner.bpnS != null
+ }
+
+
+}
diff --git a/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/GenericBusinessPartnerMappings.kt b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/GenericBusinessPartnerMappings.kt
new file mode 100644
index 000000000..1cc1fef71
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/main/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/GenericBusinessPartnerMappings.kt
@@ -0,0 +1,94 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.service
+
+
+import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerIdentifierDto
+import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerStateDto
+import org.eclipse.tractusx.bpdm.common.dto.ClassificationDto
+import org.eclipse.tractusx.orchestrator.api.model.*
+
+
+fun BusinessPartnerGenericDto.toLegalEntityDto(bpnReferenceDto: BpnReferenceDto, legalAddress: LogisticAddressDto): LegalEntityDto {
+
+ return LegalEntityDto(
+ bpnLReference = bpnReferenceDto,
+ hasChanged = true,
+ legalName = nameParts.joinToString(" "),
+ legalShortName = shortName,
+ identifiers = identifiers.map { it.toLegalEntityIdentifierDto() },
+ legalForm = legalForm,
+ states = states.map { it.toLegalEntityState() },
+ classifications = classifications.map { it.toBusinessPartnerClassificationDto() },
+ legalAddress = legalAddress
+
+ )
+}
+
+fun ClassificationDto.toBusinessPartnerClassificationDto(): BusinessPartnerClassificationDto {
+
+ return BusinessPartnerClassificationDto(code = code, type = type, value = value)
+}
+
+fun BusinessPartnerIdentifierDto.toLegalEntityIdentifierDto(): LegalEntityIdentifierDto {
+
+ return LegalEntityIdentifierDto(value = value, type = type, issuingBody = issuingBody)
+}
+
+fun BusinessPartnerStateDto.toLegalEntityState(): LegalEntityState {
+
+ return LegalEntityState(description, validFrom, validTo, type)
+}
+
+fun BusinessPartnerStateDto.toSiteState(): SiteStateDto {
+
+ return SiteStateDto(description, validFrom, validTo, type)
+}
+
+fun BusinessPartnerGenericDto.toLogisticAddressDto(bpnReferenceDto: BpnReferenceDto):
+ LogisticAddressDto {
+ return LogisticAddressDto(
+ bpnAReference = bpnReferenceDto,
+ hasChanged = true,
+ name = nameParts.joinToString(" "),
+ states = emptyList(),
+ identifiers = emptyList(),
+ physicalPostalAddress = postalAddress.physicalPostalAddress,
+ alternativePostalAddress = postalAddress.alternativePostalAddress
+ )
+}
+
+fun BusinessPartnerGenericDto.toSiteDto(bpnReferenceDto: BpnReferenceDto, legalName: String, siteAddressReference: LogisticAddressDto): SiteDto {
+
+
+ return SiteDto(
+ bpnSReference = bpnReferenceDto,
+ hasChanged = true,
+ name = legalName,
+ states = states.map { it.toSiteState() },
+ mainAddress = siteAddressReference
+
+ )
+}
+
+
+
+
+
diff --git a/bpdm-cleaning-service-dummy/src/main/resources/application.properties b/bpdm-cleaning-service-dummy/src/main/resources/application.properties
index 9a18363d8..74107e09c 100644
--- a/bpdm-cleaning-service-dummy/src/main/resources/application.properties
+++ b/bpdm-cleaning-service-dummy/src/main/resources/application.properties
@@ -39,4 +39,8 @@ springdoc.swagger-ui.csrf.enabled=true
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
-
+#Connection to Orchestrator
+bpdm.orchestrator.base-url=http://localhost:8085/
+##
+#Cleaning Service Configurations
+cleaningService.pollingCron=-
diff --git a/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceApiCallsTest.kt b/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceApiCallsTest.kt
new file mode 100644
index 000000000..3b72b28db
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceApiCallsTest.kt
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.service
+
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import com.github.tomakehurst.wiremock.client.WireMock.*
+import com.github.tomakehurst.wiremock.core.WireMockConfiguration
+import com.github.tomakehurst.wiremock.junit5.WireMockExtension
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.businessPartnerWithBpnA
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.fixedTaskId
+
+import org.eclipse.tractusx.bpdm.common.dto.*
+import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient
+import org.eclipse.tractusx.orchestrator.api.model.*
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.api.extension.RegisterExtension
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ActiveProfiles
+import org.springframework.test.context.DynamicPropertyRegistry
+import org.springframework.test.context.DynamicPropertySource
+import java.time.Instant
+import java.util.*
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+class CleaningServiceApiCallsTest @Autowired constructor(
+ val cleaningServiceDummy: CleaningServiceDummy,
+ val jacksonObjectMapper: ObjectMapper,
+ val orchestrationApiClient: OrchestrationApiClient
+) {
+
+ companion object {
+ const val ORCHESTRATOR_RESERVE_TASKS_URL = "/api/golden-record-tasks/step-reservations"
+ const val ORCHESTRATOR_RESOLVE_TASKS_URL = "/api/golden-record-tasks/step-results"
+
+ @JvmField
+ @RegisterExtension
+ val orchestratorMockApi: WireMockExtension = WireMockExtension.newInstance()
+ .options(WireMockConfiguration.wireMockConfig().dynamicPort())
+ .build()
+
+ @JvmStatic
+ @DynamicPropertySource
+ fun properties(registry: DynamicPropertyRegistry) {
+ registry.add("bpdm.orchestrator.base-url") { orchestratorMockApi.baseUrl() }
+
+ }
+ }
+
+ @BeforeEach
+ fun beforeEach() {
+ orchestratorMockApi.resetAll()
+ this.mockOrchestratorResolveApi()
+ this.mockOrchestratorReserveApi()
+ }
+
+
+ @Test
+ fun `pollForCleaningTasks should reserve and resolve tasks from orchestrator`() {
+
+ // Call the method under test
+ cleaningServiceDummy.pollForCleaningTasks()
+
+ // Verify that the reserve API was called once (using WireMock)
+ orchestratorMockApi.verify(postRequestedFor(urlEqualTo(ORCHESTRATOR_RESERVE_TASKS_URL)).withRequestBody(matchingJsonPath("$.amount", equalTo("10"))))
+
+ // Verify that the resolve API was called once (using WireMock)
+ orchestratorMockApi.verify(postRequestedFor(urlEqualTo(ORCHESTRATOR_RESOLVE_TASKS_URL)))
+ }
+
+ @Test
+ fun `reserveTasksForStep should return expected response`() {
+
+
+ val expectedResponse = jacksonObjectMapper.writeValueAsString(createSampleTaskStepReservationResponse(businessPartnerWithBpnA))
+
+
+ val result = orchestrationApiClient.goldenRecordTasks.reserveTasksForStep(
+ TaskStepReservationRequest(amount = 10, TaskStep.Clean)
+ )
+
+ // Assert the expected result
+ val expectedResult = jacksonObjectMapper.readValue(expectedResponse, result::class.java) // Convert the expected JSON response to your DTO
+ assertEquals(expectedResult, result)
+
+ orchestrationApiClient.goldenRecordTasks.resolveStepResults(
+ TaskStepResultRequest(emptyList())
+ )
+
+ }
+
+
+ fun mockOrchestratorReserveApi() {
+
+ // Orchestrator reserve
+ orchestratorMockApi.stubFor(
+ post(urlPathEqualTo(ORCHESTRATOR_RESERVE_TASKS_URL))
+ .willReturn(
+ okJson(jacksonObjectMapper.writeValueAsString(createSampleTaskStepReservationResponse(businessPartnerWithBpnA)))
+ )
+ )
+ }
+
+ fun mockOrchestratorResolveApi() {
+ // Orchestrator resolve
+ orchestratorMockApi.stubFor(
+ post(urlPathEqualTo(ORCHESTRATOR_RESOLVE_TASKS_URL))
+ .willReturn(aResponse().withStatus(200))
+ )
+ }
+
+ // Helper method to create a sample TaskStepReservationResponse
+ private fun createSampleTaskStepReservationResponse(businessPartnerGenericDto: BusinessPartnerGenericDto): TaskStepReservationResponse {
+ val fullDto = BusinessPartnerFullDto(businessPartnerGenericDto)
+ return TaskStepReservationResponse(listOf(TaskStepReservationEntryDto(fixedTaskId, fullDto)), Instant.MIN)
+ }
+
+}
\ No newline at end of file
diff --git a/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceDummyTest.kt b/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceDummyTest.kt
new file mode 100644
index 000000000..8769212aa
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/service/CleaningServiceDummyTest.kt
@@ -0,0 +1,254 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.service
+
+import com.github.tomakehurst.wiremock.client.WireMock.*
+import org.assertj.core.api.Assertions
+import org.assertj.core.api.RecursiveComparisonAssert
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.businessPartnerWithBpnA
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.businessPartnerWithBpnLAndBpnAAndLegalAddressType
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.businessPartnerWithBpnSAndBpnAAndLegalAndSiteMainAddressType
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.businessPartnerWithEmptyBpnAndSiteMainAddressType
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.businessPartnerWithEmptyBpnLAndAdditionalAddressType
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.expectedLegalEntityDto
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.expectedLogisticAddressDto
+import org.eclipse.tractusx.bpdm.cleaning.testdata.CommonValues.expectedSiteDto
+import org.eclipse.tractusx.bpdm.common.dto.*
+import org.eclipse.tractusx.orchestrator.api.model.*
+import org.junit.jupiter.api.Assertions.*
+import org.junit.jupiter.api.Test
+import org.springframework.beans.factory.annotation.Autowired
+import org.springframework.boot.test.context.SpringBootTest
+import org.springframework.test.context.ActiveProfiles
+import java.time.Instant
+import java.util.*
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ActiveProfiles("test")
+class CleaningServiceDummyTest @Autowired constructor(
+ val cleaningServiceDummy: CleaningServiceDummy
+) {
+
+
+ @Test
+ fun `test processCleaningTask with BpnA present and additional address type`() {
+ val taskStepReservationEntryDto = createSampleTaskStepReservationResponse(businessPartnerWithBpnA).reservedTasks[0]
+
+ val result = cleaningServiceDummy.processCleaningTask(taskStepReservationEntryDto)
+
+ val expectedBpnA = taskStepReservationEntryDto.businessPartner.generic.bpnA
+
+ val resultedAddress = result.businessPartner?.address
+
+ val resultedLegalEntity = result.businessPartner?.legalEntity
+
+ // legalEntity should be Generated with new bpnL and legalAddress bpnA
+ // addressPartner should use passed bpnA, and it will be different from legalAddress since type is additional address type
+
+ assertEquals(expectedBpnA, resultedAddress?.bpnAReference?.referenceValue)
+
+ assertEquals(BpnReferenceType.BpnRequestIdentifier, resultedLegalEntity?.bpnLReference?.referenceType)
+
+ val expectedAddress = expectedLogisticAddressDto.copy(bpnAReference = BpnReferenceDto(expectedBpnA.toString(), BpnReferenceType.Bpn))
+
+ val expectedLegalEntity = expectedLegalEntityDto.copy(legalAddress = expectedLogisticAddressDto)
+
+ assertRecursively(resultedAddress).isEqualTo(expectedAddress)
+
+ // ignoring bpnLReference and bpnAReference since they are generated
+ assertRecursively(resultedLegalEntity).ignoringFields("bpnLReference", "legalAddress.bpnAReference").isEqualTo(expectedLegalEntity)
+
+
+ }
+
+ @Test
+ fun `test processCleaningTask with empty BpnA and additional address type`() {
+ val taskStepReservationEntryDto = createSampleTaskStepReservationResponse(businessPartnerWithEmptyBpnLAndAdditionalAddressType).reservedTasks[0]
+
+ val result = cleaningServiceDummy.processCleaningTask(taskStepReservationEntryDto)
+
+ val resultedAddress = result.businessPartner?.address
+
+ val resultedLegalEntity = result.businessPartner?.legalEntity
+
+ // legalEntity should be Generated with new bpnL and legalAddress bpnA
+ // addressPartner should be Generated bpnA, and it will be different from legalAddress since type is additional address type
+
+ assertEquals(BpnReferenceType.BpnRequestIdentifier, resultedAddress?.bpnAReference?.referenceType)
+
+ assertEquals(BpnReferenceType.BpnRequestIdentifier, resultedLegalEntity?.bpnLReference?.referenceType)
+
+ assertNotEquals(resultedAddress?.bpnAReference?.referenceValue, resultedLegalEntity?.legalAddress?.bpnAReference?.referenceValue)
+
+ val expectedAddress = expectedLogisticAddressDto.copy()
+
+ val expectedLegalEntity = expectedLegalEntityDto.copy(legalAddress = expectedLogisticAddressDto)
+
+ // bpnAReference since they are generated
+ assertRecursively(resultedAddress).ignoringFields("bpnAReference").isEqualTo(expectedAddress)
+
+ // ignoring bpnLReference and bpnAReference since they are generated
+ assertRecursively(resultedLegalEntity).ignoringFields("bpnAReference", "bpnLReference", "legalAddress.bpnAReference").isEqualTo(expectedLegalEntity)
+ }
+
+ @Test
+ fun `test processCleaningTask with BpnL and BpnA present and legal address type`() {
+ val taskStepReservationEntryDto = createSampleTaskStepReservationResponse(businessPartnerWithBpnLAndBpnAAndLegalAddressType).reservedTasks[0]
+
+ val result = cleaningServiceDummy.processCleaningTask(taskStepReservationEntryDto)
+
+ val expectedBpnA = taskStepReservationEntryDto.businessPartner.generic.bpnA
+
+ val expectedBpnL = taskStepReservationEntryDto.businessPartner.generic.bpnL
+
+ val resultedAddress = result.businessPartner?.address
+
+ val resultedLegalEntity = result.businessPartner?.legalEntity
+
+ // legalEntity should use passed bpnL and legalAddress should use passed bpnA since address type is LegalAddressType
+ // addressPartner should use null, since it does not create when type is LegalAddressType
+
+ assertNull(resultedAddress?.bpnAReference?.referenceValue)
+ assertEquals(expectedBpnL, resultedLegalEntity?.bpnLReference?.referenceValue)
+ assertEquals(expectedBpnA, resultedLegalEntity?.legalAddress?.bpnAReference?.referenceValue)
+
+
+ val expectedLegalEntity = expectedLegalEntityDto.copy(
+ legalAddress = expectedLogisticAddressDto.copy(
+ bpnAReference = BpnReferenceDto(
+ expectedBpnA.toString(),
+ BpnReferenceType.Bpn
+ )
+ ), bpnLReference = BpnReferenceDto(expectedBpnL.toString(), BpnReferenceType.Bpn)
+ )
+
+ assertRecursively(resultedLegalEntity).isEqualTo(expectedLegalEntity)
+ }
+
+ @Test
+ fun `test processCleaningTask with BpnS and BpnA present and legal and site main address type`() {
+ val taskStepReservationResponse = createSampleTaskStepReservationResponse(businessPartnerWithBpnSAndBpnAAndLegalAndSiteMainAddressType).reservedTasks[0]
+
+ val result = cleaningServiceDummy.processCleaningTask(taskStepReservationResponse)
+
+ val resultedAddress = result.businessPartner?.address
+
+ val resultedLegalEntity = result.businessPartner?.legalEntity
+
+ val resultedSite = result.businessPartner?.site
+
+ val expectedBpnA = taskStepReservationResponse.businessPartner.generic.bpnA
+
+ val expectedBpnS = taskStepReservationResponse.businessPartner.generic.bpnS
+
+
+ // legalEntity should Generate new bpnL and legalAddress should use passed bpnA since address type is LegalAndSiteMainAddress
+ // addressPartner should use null, since it does not create when type is LegalAndSiteMainAddress
+ // Site should use passed bpnS, and it will be the same MainAddress as legalAddress and addressPartner since address type is LegalAndSiteMainAddress
+
+
+ assertNull(resultedAddress?.bpnAReference?.referenceValue)
+
+ assertEquals(expectedBpnA, resultedLegalEntity?.legalAddress?.bpnAReference?.referenceValue)
+
+ assertEquals(expectedBpnA, resultedSite?.mainAddress?.bpnAReference?.referenceValue)
+
+ assertEquals(BpnReferenceType.BpnRequestIdentifier, resultedLegalEntity?.bpnLReference?.referenceType)
+
+ assertEquals(expectedBpnS, resultedSite?.bpnSReference?.referenceValue)
+
+
+ val expectedLegalEntity = expectedLegalEntityDto.copy(
+ legalAddress = expectedLogisticAddressDto.copy(
+ bpnAReference = BpnReferenceDto(
+ expectedBpnA.toString(),
+ BpnReferenceType.Bpn
+ )
+ )
+ )
+
+ val expectedSite = expectedSiteDto.copy(
+ mainAddress = expectedLogisticAddressDto.copy(bpnAReference = BpnReferenceDto(expectedBpnA.toString(), BpnReferenceType.Bpn)),
+ bpnSReference = BpnReferenceDto(expectedBpnS.toString(), BpnReferenceType.Bpn)
+ )
+
+
+ // ignoring bpnLReference since they are generated
+ assertRecursively(resultedLegalEntity).ignoringFields("bpnLReference").isEqualTo(expectedLegalEntity)
+
+ assertRecursively(resultedSite).isEqualTo(expectedSite)
+
+
+ }
+ @Test
+ fun `test processCleaningTask with empty Bpn and site main address type`() {
+ val taskStepReservationResponse = createSampleTaskStepReservationResponse(businessPartnerWithEmptyBpnAndSiteMainAddressType).reservedTasks[0]
+
+ val result = cleaningServiceDummy.processCleaningTask(taskStepReservationResponse)
+
+ val resultedAddress = result.businessPartner?.address
+
+ val resultedLegalEntity = result.businessPartner?.legalEntity
+
+ val resultedSite = result.businessPartner?.site
+
+
+ // legalEntity should Generate new bpnL and legalAddress should Generate new bpnA since address type is SiteMainAddress
+ // addressPartner should use null, since it does not create when type is SiteMainAddress
+ // Site should Generate new bpnS
+
+
+ assertEquals(BpnReferenceType.BpnRequestIdentifier, resultedLegalEntity?.bpnLReference?.referenceType)
+
+ assertNull(resultedAddress?.bpnAReference?.referenceType)
+
+ assertEquals(BpnReferenceType.BpnRequestIdentifier, resultedSite?.bpnSReference?.referenceType)
+
+ assertNotEquals(resultedAddress?.bpnAReference?.referenceValue, resultedLegalEntity?.legalAddress?.bpnAReference?.referenceValue)
+ assertNotEquals(resultedAddress?.bpnAReference?.referenceValue, resultedSite?.mainAddress?.bpnAReference?.referenceValue)
+
+ val expectedLegalEntity = expectedLegalEntityDto.copy(legalAddress = expectedLogisticAddressDto.copy())
+
+ val expectedSite = expectedSiteDto.copy(mainAddress = expectedLogisticAddressDto.copy())
+
+
+ // ignoring bpnLReference and legalAddress.bpnAReference since they are generated
+ assertRecursively(resultedLegalEntity).ignoringFields("bpnLReference", "legalAddress.bpnAReference").isEqualTo(expectedLegalEntity)
+
+ // ignoring bpnSReference and mainAddress.bpnAReference since they are generated
+ assertRecursively(resultedSite).ignoringFields("bpnSReference", "mainAddress.bpnAReference").isEqualTo(expectedSite)
+
+ }
+
+ // Helper method to create a sample TaskStepReservationResponse
+ private fun createSampleTaskStepReservationResponse(businessPartnerGenericDto: BusinessPartnerGenericDto): TaskStepReservationResponse {
+ val fullDto = BusinessPartnerFullDto(businessPartnerGenericDto)
+ return TaskStepReservationResponse(listOf(TaskStepReservationEntryDto(UUID.randomUUID().toString(), fullDto)), Instant.MIN)
+ }
+
+ fun assertRecursively(actual: T): RecursiveComparisonAssert<*> {
+ return Assertions.assertThat(actual)
+ .usingRecursiveComparison()
+ .ignoringCollectionOrder()
+ .ignoringAllOverriddenEquals()
+ .ignoringFieldsOfTypes(Instant::class.java)
+ }
+
+}
diff --git a/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/testdata/CommonValues.kt b/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/testdata/CommonValues.kt
new file mode 100644
index 000000000..3cb5b8f1c
--- /dev/null
+++ b/bpdm-cleaning-service-dummy/src/test/kotlin/org/eclipse/tractusx/bpdm/cleaning/testdata/CommonValues.kt
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Apache License, Version 2.0 which is available at
+ * https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ ******************************************************************************/
+
+package org.eclipse.tractusx.bpdm.cleaning.testdata
+
+import com.neovisionaries.i18n.CountryCode
+import org.eclipse.tractusx.bpdm.cleaning.service.toBusinessPartnerClassificationDto
+import org.eclipse.tractusx.bpdm.cleaning.service.toLegalEntityIdentifierDto
+import org.eclipse.tractusx.bpdm.cleaning.service.toLegalEntityState
+import org.eclipse.tractusx.bpdm.cleaning.service.toSiteState
+import org.eclipse.tractusx.bpdm.common.dto.*
+import org.eclipse.tractusx.bpdm.common.model.BusinessStateType
+import org.eclipse.tractusx.bpdm.common.model.ClassificationType
+import org.eclipse.tractusx.orchestrator.api.model.*
+import org.eclipse.tractusx.orchestrator.api.model.LegalEntityDto
+import org.eclipse.tractusx.orchestrator.api.model.LogisticAddressDto
+import org.eclipse.tractusx.orchestrator.api.model.PhysicalPostalAddressDto
+import org.eclipse.tractusx.orchestrator.api.model.SiteDto
+import org.eclipse.tractusx.orchestrator.api.model.StreetDto
+import java.time.LocalDateTime
+
+/**
+ * Contains simple test values used to create more complex test values such as DTOs
+ */
+object CommonValues {
+
+ val fixedTaskId = "taskid-123123"
+
+ val nameParts = listOf("Part1", "Part2")
+ const val shortName = "ShortName"
+ val identifiers = listOf(
+ BusinessPartnerIdentifierDto(
+ type = "Type1",
+ value = "Value1",
+ issuingBody = "IssuingBody1"
+ )
+ )
+ const val legalForm = "LegalForm"
+ val states = listOf(
+ BusinessPartnerStateDto(
+ validFrom = LocalDateTime.now(),
+ validTo = LocalDateTime.now().plusDays(10),
+ type = BusinessStateType.ACTIVE,
+ description = "ActiveState"
+ )
+ )
+ val classifications = listOf(
+ ClassificationDto(
+ type = ClassificationType.NACE,
+ code = "Code1",
+ value = "Value1"
+ )
+ )
+ val roles = listOf(BusinessPartnerRole.SUPPLIER, BusinessPartnerRole.CUSTOMER)
+ val physicalPostalAddress = PhysicalPostalAddressDto(
+ geographicCoordinates = GeoCoordinateDto(longitude = 12.34f, latitude = 56.78f),
+ country = CountryCode.PT,
+ administrativeAreaLevel1 = "AdminArea1",
+ administrativeAreaLevel2 = "AdminArea2",
+ administrativeAreaLevel3 = "AdminArea3",
+ postalCode = "PostalCode",
+ city = "City",
+ district = "District",
+ street = StreetDto("StreetName"),
+ companyPostalCode = "CompanyPostalCode",
+ industrialZone = "IndustrialZone",
+ building = "Building",
+ floor = "Floor",
+ door = "Door"
+ )
+
+ val postalAddressForLegalAndSite = PostalAddressDto(
+ addressType = AddressType.LegalAndSiteMainAddress,
+ physicalPostalAddress = physicalPostalAddress
+ )
+ val postalAddressForLegal = PostalAddressDto(
+ addressType = AddressType.LegalAddress,
+ physicalPostalAddress = physicalPostalAddress
+ )
+ val postalAddressForSite = PostalAddressDto(
+ addressType = AddressType.SiteMainAddress,
+ physicalPostalAddress = physicalPostalAddress
+ )
+ val postalAddressForAdditional = PostalAddressDto(
+ addressType = AddressType.AdditionalAddress,
+ physicalPostalAddress = physicalPostalAddress
+ )
+
+ val businessPartnerWithEmptyBpns = BusinessPartnerGenericDto(
+ nameParts = nameParts,
+ shortName = shortName,
+ identifiers = identifiers,
+ legalForm = legalForm,
+ states = states,
+ classifications = classifications,
+ roles = roles,
+ ownerBpnL = "ownerBpnL2"
+ )
+
+
+ val businessPartnerWithBpnA = businessPartnerWithEmptyBpns.copy(
+ postalAddress = postalAddressForAdditional,
+ bpnA = "FixedBPNA"
+ )
+
+
+ val businessPartnerWithBpnLAndBpnAAndLegalAddressType = businessPartnerWithEmptyBpns.copy(
+ postalAddress = postalAddressForLegal,
+ bpnA = "FixedBPNA",
+ bpnL = "FixedBPNL"
+ )
+
+ val businessPartnerWithEmptyBpnLAndAdditionalAddressType = businessPartnerWithEmptyBpns.copy(
+ postalAddress = postalAddressForAdditional,
+ )
+
+ val businessPartnerWithBpnSAndBpnAAndLegalAndSiteMainAddressType = businessPartnerWithEmptyBpns.copy(
+ postalAddress = postalAddressForLegalAndSite,
+ bpnA = "FixedBPNA",
+ bpnS = "FixedBPNS"
+ )
+
+ val businessPartnerWithEmptyBpnAndSiteMainAddressType = businessPartnerWithEmptyBpns.copy(
+ postalAddress = postalAddressForSite
+ )
+
+ val expectedLegalEntityDto = LegalEntityDto(
+ hasChanged = true,
+ legalName = nameParts.joinToString(" "),
+ legalShortName = shortName,
+ identifiers = identifiers.map { it.toLegalEntityIdentifierDto() },
+ legalForm = legalForm,
+ states = states.map { it.toLegalEntityState() },
+ classifications = classifications.map { it.toBusinessPartnerClassificationDto() }
+ )
+
+ val expectedSiteDto = SiteDto(
+ hasChanged = true,
+ name = nameParts.joinToString(" "),
+ states = states.map { it.toSiteState() },
+ )
+
+ val expectedLogisticAddressDto = LogisticAddressDto(
+
+ hasChanged = true,
+ name = nameParts.joinToString(" "),
+ states = emptyList(),
+ identifiers = emptyList(),
+ physicalPostalAddress = physicalPostalAddress
+ )
+
+
+}
\ No newline at end of file