diff --git a/CHANGELOG.md b/CHANGELOG.md index bb5260c16..95688f4e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ For changes to the BPDM Helm charts please consult the [changelog](charts/bpdm/C - BPDM Pool: Post endpoint to fetch the BPNL/S/A based on the requested identifiers.([#1052](https://github.com/eclipse-tractusx/bpdm/issues/1052)) - BPDM Gate & Orchestrator: Enhance the error handling mechanism for the orchestrator and gate components by extending the list of available error codes.([#1003](https://github.com/eclipse-tractusx/bpdm/pull/1003#pullrequestreview-2477395867)) +- BPDM System Test: Tester module which performs automated end-to-end tests on an existing golden record process.([#1070](https://github.com/eclipse-tractusx/bpdm/pull/1070)) ### Changed diff --git a/DEPENDENCIES b/DEPENDENCIES index c495e066f..caf0e9738 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -43,6 +43,24 @@ maven/mavencentral/commons-codec/commons-codec/1.17.1, Apache-2.0 AND (Apache-2. maven/mavencentral/commons-collections/commons-collections/3.2.2, Apache-2.0, approved, #15185 maven/mavencentral/commons-io/commons-io/2.17.0, Apache-2.0, approved, #16198 maven/mavencentral/commons-logging/commons-logging/1.2, Apache-2.0, approved, CQ10162 +maven/mavencentral/io.cucumber/ci-environment/10.0.1, MIT, approved, #15218 +maven/mavencentral/io.cucumber/cucumber-core/7.18.1, MIT AND (Apache-2.0 AND MIT), approved, #15146 +maven/mavencentral/io.cucumber/cucumber-expressions/17.1.0, MIT, approved, #14271 +maven/mavencentral/io.cucumber/cucumber-gherkin-messages/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/cucumber-gherkin/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/cucumber-java/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/cucumber-junit/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/cucumber-plugin/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/cucumber-spring/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/datatable/7.18.1, Apache-2.0, approved, #15145 +maven/mavencentral/io.cucumber/docstring/7.18.1, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/gherkin/28.0.0, MIT, approved, #14276 +maven/mavencentral/io.cucumber/html-formatter/21.4.1, MIT, restricted, clearlydefined +maven/mavencentral/io.cucumber/junit-xml-formatter/0.5.0, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/messages/24.1.0, MIT, approved, #14274 +maven/mavencentral/io.cucumber/query/12.2.0, MIT, approved, clearlydefined +maven/mavencentral/io.cucumber/tag-expressions/6.1.0, MIT AND (BSD-3-Clause AND MIT) AND BSD-3-Clause, approved, #14277 +maven/mavencentral/io.cucumber/testng-xml-formatter/0.2.0, MIT, approved, clearlydefined maven/mavencentral/io.github.microutils/kotlin-logging-jvm/3.0.5, Apache-2.0, approved, clearlydefined maven/mavencentral/io.micrometer/micrometer-commons/1.14.1, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #17272 maven/mavencentral/io.micrometer/micrometer-core/1.14.1, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #17271 diff --git a/bpdm-system-tester/README.md b/bpdm-system-tester/README.md new file mode 100644 index 000000000..add9a76f4 --- /dev/null +++ b/bpdm-system-tester/README.md @@ -0,0 +1,17 @@ +# System Tester + +This application performs automated end-to-end tests on an existing golden record process. +For this it needs access to a BPDM Gate application in order to share business partner data and compare the resulting golden records with the expected result. + +In order to use this application you first need to [install the BPDM applications](../INSTALL.md). +For a local execution you can follow the following steps: + +1. Create a JAR file of the bpdm system tester (Execute from project root) +```bash +mvn -B -U clean package -pl bpdm-system-tester -am -DskipTests +``` +2. Install and run the BPDM applications locally without authentication +3. Run the JAR file so the tests will be executed: +```bash +java -jar bpdm-system-tester/target/bpdm-system-tester.jar +``` \ No newline at end of file diff --git a/bpdm-system-tester/pom.xml b/bpdm-system-tester/pom.xml new file mode 100644 index 000000000..5a1f44742 --- /dev/null +++ b/bpdm-system-tester/pom.xml @@ -0,0 +1,103 @@ + + 4.0.0 + + + org.eclipse.tractusx + bpdm-parent + ${revision} + + + bpdm-system-tester + Business Partner Data Management System Tester + Application to perform system tests for the BPDM system and golden record process + jar + + + 7.18.1 + + + + + org.jetbrains.kotlinx + kotlinx-coroutines-core + + + org.springframework.boot + spring-boot-starter + + + org.jetbrains.kotlin + kotlin-reflect + + + org.jetbrains.kotlin + kotlin-stdlib + + + ${project.groupId} + bpdm-pool-api + + + ${project.groupId} + bpdm-gate-api + + + io.github.microutils + kotlin-logging-jvm + + + org.assertj + assertj-core + + + io.cucumber + cucumber-java + ${cucumber.version} + + + io.cucumber + cucumber-junit + ${cucumber.version} + + + io.cucumber + cucumber-spring + ${cucumber.version} + + + ${project.groupId} + bpdm-common-test + test + + + org.springframework.boot + spring-boot-starter-test + + + + org.mockito + mockito-core + + + + + + + + bpdm-system-tester + ${project.basedir}/src/main/kotlin + + + org.springframework.boot + spring-boot-maven-plugin + + + org.jetbrains.kotlin + kotlin-maven-plugin + + + + + + diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/Application.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/Application.kt new file mode 100644 index 000000000..3c2c193ef --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/Application.kt @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system + +import io.cucumber.junit.Cucumber +import org.junit.runner.RunWith +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration +import org.springframework.boot.context.properties.ConfigurationPropertiesScan + +@RunWith(Cucumber::class) +class CucumberTestRunConfiguration + +@SpringBootApplication(exclude=[DataSourceAutoConfiguration::class]) +@ConfigurationPropertiesScan +class SpringApplicationConfiguration + +fun main(args: Array) { + //use parallel execution default if not overwritten + //can't use cucumber.properties for this as the properties parser currently does not support it + //see https://github.com/cucumber/cucumber-jvm/issues/2833 + val cucumberArgs = if(!args.contains("--threads")) args.plus(listOf("--threads", "16")) else args + io.cucumber.core.cli.Main.main(*cucumberArgs) +} \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/GateClientConfig.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/GateClientConfig.kt new file mode 100644 index 000000000..c37ada7e2 --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/GateClientConfig.kt @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.config + +import org.eclipse.tractusx.bpdm.common.util.BpdmClientProperties +import org.eclipse.tractusx.bpdm.common.util.BpdmWebClientProvider +import org.eclipse.tractusx.bpdm.common.util.ClientConfigurationProperties +import org.eclipse.tractusx.bpdm.gate.api.client.GateClient +import org.eclipse.tractusx.bpdm.gate.api.client.GateClientImpl +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@ConfigurationProperties(prefix = PoolClientConfigurationProperties.PREFIX) +data class GateClientConfigProperties( + override val baseUrl: String = "http://localhost:8081", + val searchChangelogPageSize: Int = 100, + override val securityEnabled: Boolean = false, + override val registration: OAuth2ClientProperties.Registration, + override val provider: OAuth2ClientProperties.Provider +) : BpdmClientProperties { + companion object { + const val PREFIX = "${ClientConfigurationProperties.PREFIX}.gate" + } + + override fun getId() = PREFIX +} + +@Configuration +class GateClientConfig{ + + @Bean + fun gateClient(webClientProvider: BpdmWebClientProvider, properties: GateClientConfigProperties): GateClient { + return GateClientImpl { webClientProvider.builder(properties).build() } + } +} \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/PoolClientConfig.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/PoolClientConfig.kt new file mode 100644 index 000000000..56f9eadbc --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/PoolClientConfig.kt @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.config + +import org.eclipse.tractusx.bpdm.common.util.BpdmClientProperties +import org.eclipse.tractusx.bpdm.common.util.BpdmWebClientProvider +import org.eclipse.tractusx.bpdm.common.util.ClientConfigurationProperties +import org.eclipse.tractusx.bpdm.pool.api.client.PoolApiClient +import org.eclipse.tractusx.bpdm.pool.api.client.PoolClientImpl +import org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientProperties +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + + +@ConfigurationProperties(prefix = PoolClientConfigurationProperties.PREFIX) +data class PoolClientConfigurationProperties( + override val baseUrl: String = "http://localhost:8080", + val searchChangelogPageSize: Int = 100, + override val securityEnabled: Boolean = false, + override val registration: OAuth2ClientProperties.Registration, + override val provider: OAuth2ClientProperties.Provider +) : BpdmClientProperties { + companion object { + const val PREFIX = "${ClientConfigurationProperties.PREFIX}.pool" + } + + override fun getId() = PREFIX +} + +@Configuration +class PoolClientConfiguration{ + + @Bean + fun poolClient(webClientProvider: BpdmWebClientProvider, properties: PoolClientConfigurationProperties): PoolApiClient{ + return PoolClientImpl { webClientProvider.builder(properties).build() } + } +} + diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/TestDataConfiguration.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/TestDataConfiguration.kt new file mode 100644 index 000000000..889a5a32a --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/TestDataConfiguration.kt @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.config + +import org.eclipse.tractusx.bpdm.gate.api.client.GateClient +import org.eclipse.tractusx.bpdm.pool.api.client.PoolApiClient +import org.eclipse.tractusx.bpdm.test.system.utils.GateInputFactory +import org.eclipse.tractusx.bpdm.test.system.utils.GateOutputFactory +import org.eclipse.tractusx.bpdm.test.system.utils.StepUtils +import org.eclipse.tractusx.bpdm.test.system.utils.TestMetadata +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import java.time.Instant + +@Configuration +class TestDataConfiguration { + + @Bean + fun testMetadata(poolClient: PoolApiClient): TestMetadata { + val testMetadata = TestMetadata( + identifierTypes = listOf("EU_VAT_ID_DE", "DUNS_ID"), + legalForms = listOf("SCE1", "SGST"), + adminAreas = listOf("DE-BW", "DE-BY") + ) + + return testMetadata + } + + @Bean + fun gateTestDataFactory(testMetadata: TestMetadata, testRunData: TestRunData): GateInputFactory { + return GateInputFactory(testMetadata, testRunData) + } + + @Bean + fun gateOutputFactory(gateInputDataFactory: GateInputFactory): GateOutputFactory { + return GateOutputFactory(gateInputDataFactory) + } + + @Bean + fun testRunData(): TestRunData { + return TestRunData(Instant.now()) + } + + @Bean + fun stepUtils(testRunData: TestRunData, gateClient: GateClient): StepUtils{ + return StepUtils(gateClient) + } +} \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/TestRunData.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/TestRunData.kt new file mode 100644 index 000000000..31f8a27da --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/config/TestRunData.kt @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.config + +import java.time.Instant + +data class TestRunData ( + val testTime: Instant +){ + fun toExternalId(seed: String): String = "${seed}_$testTime" +} \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/stepdefinations/ShareGenericNoBpnStepDefs.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/stepdefinations/ShareGenericNoBpnStepDefs.kt new file mode 100644 index 000000000..418399da7 --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/stepdefinations/ShareGenericNoBpnStepDefs.kt @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.stepdefinations + +import io.cucumber.java.en.Given +import io.cucumber.java.en.Then +import io.cucumber.java.en.When +import org.assertj.core.api.Assertions.assertThat +import org.eclipse.tractusx.bpdm.common.dto.AddressType +import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest +import org.eclipse.tractusx.bpdm.gate.api.client.GateClient +import org.eclipse.tractusx.bpdm.test.system.config.TestRunData +import org.eclipse.tractusx.bpdm.test.system.utils.* + +class ShareGenericNoBpnStepDefs( + private val gateInputDataFactory: GateInputFactory, + private val gateOutputFactory: GateOutputFactory, + private val gateClient: GateClient, + private val stepUtils: StepUtils, + private val testRunData: TestRunData +): SpringTestRunConfiguration() { + + @Given("^output \"([^\"]*)\" with external-ID \"([^\"]*)\"$") + fun `given output seed with externalId`(seed: String, externalId: String) { + uploadInput(seed, externalId, null) + stepUtils.waitForResult(testRunData.toExternalId(externalId)) + } + + @When("^the sharing member uploads full valid input \"([^\"]*)\" with external-ID \"([^\"]*)\" with address type \"([^\"]*)\"$") + fun `when the sharing member uploads input seed with address type`(seed: String, externalId: String, addressType: String) { + uploadInput(seed, externalId, AddressType.valueOf(addressType)) + } + + @When("^the sharing member uploads full valid input \"([^\"]*)\" with external-ID \"([^\"]*)\" without address type") + fun `when the sharing member uploads input seed without address type`(seed: String, externalId: String) { + uploadInput(seed, externalId, null) + } + + @Then("^the sharing member receives output \"([^\"]*)\" with external-ID \"([^\"]*)\" with address type \"([^\"]*)\"$") + fun `then the sharing member receives output seed with modifier`(seed: String, externalId: String, addressType: String) { + val expectedOutput = gateOutputFactory.createOutput(seed, externalId) + .withAddressType(AddressType.valueOf(addressType)) + // On no auth config we can't get own company data to true + .copy(isOwnCompanyData = false) + + stepUtils.waitForResult(expectedOutput.externalId) + + val actualOutput = gateClient.businessParters.getBusinessPartnersOutput(listOf(expectedOutput.externalId), PaginationRequest()).content.single() + + stepUtils.assertEqualIgnoreBpns(actualOutput, expectedOutput) + } + + @When("^the sharing member uploads input \"([^\"]*)\" with external-ID \"([^\"]*)\" without mandatory field \"([^\"]*)\"$") + fun `when the sharing member upload input seed without mandatory field`(seed: String, externalId: String, mandatoryField: String) { + uploadInputWithoutMandatoryField(seed, externalId, mandatoryField) + } + + @Then("^the sharing member receives sharing error \"([^\"]*)\" with external-ID \"([^\"]*)\" with error message \"([^\"]*)\"$") + fun `then the sharing member receives sharing error with error message`(seed: String, externalId: String, errorMessage: String) { + stepUtils.waitForResult(testRunData.toExternalId(externalId)) + val sharingState = gateClient.sharingState.getSharingStates(PaginationRequest(), listOf(testRunData.toExternalId(externalId))).content.single() + assertThat(sharingState.sharingErrorMessage).contains(errorMessage) + } + + private fun uploadInput(seed: String, externalId: String, addressType: AddressType?){ + val inputRequest = gateInputDataFactory.createFullValid(seed, externalId).withAddressType(addressType).withoutAnyBpn() + gateClient.businessParters.upsertBusinessPartnersInput(listOf(inputRequest)) + } + + private fun uploadInputWithoutMandatoryField(seed: String, externalId: String, mandatoryField: String) { + // Prepare invalid input by removing the necessary field to simulate the error + val inputRequest = when (mandatoryField) { + "legalName" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + nameParts = emptyList(), + legalEntity = gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().legalEntity.copy(legalName = null) + ) + "physicalAddress.country" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + address = gateInputDataFactory.createFullValid(seed, externalId).address.copy( + physicalPostalAddress = gateInputDataFactory.createFullValid(seed, externalId).address.physicalPostalAddress.copy(country = null) + ) + ) + "physicalAddress.city" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + address = gateInputDataFactory.createFullValid(seed, externalId).address.copy( + physicalPostalAddress = gateInputDataFactory.createFullValid(seed, externalId).address.physicalPostalAddress.copy(city = null) + ) + ) + "alternativeAddress.country" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + address = gateInputDataFactory.createFullValid(seed, externalId).address.copy( + alternativePostalAddress = gateInputDataFactory.createFullValid(seed, externalId).address.alternativePostalAddress!!.copy(country = null) + ) + ) + "alternativeAddress.city" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + address = gateInputDataFactory.createFullValid(seed, externalId).address.copy( + alternativePostalAddress = gateInputDataFactory.createFullValid(seed, externalId).address.alternativePostalAddress!!.copy(city = null) + ) + ) + "alternativeAddress.deliveryServiceType" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + address = gateInputDataFactory.createFullValid(seed, externalId).address.copy( + alternativePostalAddress = gateInputDataFactory.createFullValid(seed, externalId).address.alternativePostalAddress!!.copy(deliveryServiceType = null) + ) + ) + "alternativeAddress.deliveryServiceNumber" -> gateInputDataFactory.createFullValid(seed, externalId).withoutAnyBpn().copy( + address = gateInputDataFactory.createFullValid(seed, externalId).address.copy( + alternativePostalAddress = gateInputDataFactory.createFullValid(seed, externalId).address.alternativePostalAddress!!.copy(deliveryServiceNumber = null) + ) + ) + // Similarly we can handle other fields... + else -> throw IllegalArgumentException("Unsupported error field: $mandatoryField") + } + gateClient.businessParters.upsertBusinessPartnersInput(listOf(inputRequest)) + } + + +} \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/stepdefinations/SpringTestRunConfiguration.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/stepdefinations/SpringTestRunConfiguration.kt new file mode 100644 index 000000000..64ccdcba2 --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/stepdefinations/SpringTestRunConfiguration.kt @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.stepdefinations + +import io.cucumber.spring.CucumberContextConfiguration +import org.springframework.boot.test.context.SpringBootTest + +@CucumberContextConfiguration +@SpringBootTest +class SpringTestRunConfiguration \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/GateInputFactory.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/GateInputFactory.kt new file mode 100644 index 000000000..de6a6b787 --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/GateInputFactory.kt @@ -0,0 +1,168 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.utils + +import com.neovisionaries.i18n.CountryCode +import org.eclipse.tractusx.bpdm.common.dto.AddressType +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerRole +import org.eclipse.tractusx.bpdm.common.dto.GeoCoordinateDto +import org.eclipse.tractusx.bpdm.common.model.BusinessStateType +import org.eclipse.tractusx.bpdm.common.model.DeliveryServiceType +import org.eclipse.tractusx.bpdm.gate.api.model.* +import org.eclipse.tractusx.bpdm.gate.api.model.request.BusinessPartnerInputRequest +import org.eclipse.tractusx.bpdm.gate.api.model.response.AddressRepresentationInputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.LegalEntityRepresentationInputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.SiteRepresentationInputDto +import org.eclipse.tractusx.bpdm.test.system.config.TestRunData +import java.time.Duration +import java.time.Instant +import java.time.ZoneOffset +import kotlin.random.Random + +class GateInputFactory( + private val testMetadata: TestMetadata, + private val testRunData: TestRunData +) { + val genericFullValidWithSiteWithoutAnyBpn = createAllFieldsFilled("genericFullValidWithSiteWithoutAnyBpn") + { it.withoutAnyBpn().withAddressType(null) } + + fun createAllFieldsFilled(seed: String, transform: (BusinessPartnerInputRequest) -> BusinessPartnerInputRequest = {it}): InputTestData { + return InputTestData(seed, transform(SeededTestDataCreator(seed).createAllFieldsFilled())) + } + + fun createFullValid(seed: String, externalId: String = seed): BusinessPartnerInputRequest { + return SeededTestDataCreator(seed).createAllFieldsFilled().copy(externalId = testRunData.toExternalId(externalId)) + } + + inner class SeededTestDataCreator( + private val seed: String, + ){ + private val longSeed = seed.hashCode().toLong() + private val random = Random(longSeed) + private val listRange = 1 .. 3 + + + fun createAllFieldsFilled(): BusinessPartnerInputRequest{ + + return BusinessPartnerInputRequest( + externalId = "${seed}_${testRunData.testTime}", + nameParts = listRange.map { "Name Part $seed $it" }, + identifiers = emptyList(), + roles = BusinessPartnerRole.entries, + isOwnCompanyData = random.nextBoolean(), + states = emptyList(), + legalEntity = LegalEntityRepresentationInputDto( + legalEntityBpn = "BPNL $seed", + legalName = "Legal Name $seed", + shortName = "Short Name $seed", + legalForm = testMetadata.legalForms.random(random) + ), + site = SiteRepresentationInputDto( + siteBpn = "BPNS $seed", + name = "Site Name $seed" + ), + address = AddressRepresentationInputDto( + addressBpn = "BPNA $seed", + name = "Address Name $seed", + addressType = AddressType.AdditionalAddress, + physicalPostalAddress = createPhysicalAddress(), + alternativePostalAddress = createAlternativeAddress() + ) + ) + } + + + private fun createIdentifiers(): List{ + return listRange.map { testMetadata.identifierTypes.random(random) } + .mapIndexed{ index, type -> BusinessPartnerIdentifierDto(type = type, value = "Identifier Value $seed $index", issuingBody = "Issuing Body $seed $index") } + } + + private fun createStates(): List{ + return random.nextTime().let { + listRange.runningFold(Pair(it, it.plus(random.nextDuration()))){ current, _ -> Pair(current.second, current.second.plus(random.nextDuration())) } + }.map { (validFrom, validTo) -> BusinessPartnerStateDto(validFrom = validFrom, validTo = validTo, BusinessStateType.entries.random(random)) } + } + + private fun createPhysicalAddress(): PhysicalPostalAddressDto{ + return PhysicalPostalAddressDto( + geographicCoordinates = GeoCoordinateDto(longitude = random.nextDouble(), latitude = random.nextDouble(), altitude = random.nextDouble()), + country = CountryCode.entries.random(random), + administrativeAreaLevel1 = testMetadata.adminAreas.random(random), + administrativeAreaLevel2 = "Admin Level 2 $seed", + administrativeAreaLevel3 = "Admin Level 3 $seed", + postalCode = "Postal Code $seed", + city = "City $seed", + district = "District $seed", + street = StreetDto( + name = "Street Name $seed", + houseNumber = "House Number $seed", + houseNumberSupplement = "House Number Supplement $seed", + milestone = "Milestone $seed", + direction = "Direction $seed", + namePrefix = "Name Prefix $seed", + nameSuffix = "Name Suffix $seed", + additionalNamePrefix = "Additional Name Prefix $seed", + additionalNameSuffix = "Additional Name Suffix $seed" + ), + companyPostalCode = "Company Postal Code $seed", + industrialZone = "Industrial Zone $seed", + building = "Building $seed", + floor = "Floor $seed", + door = "Door $seed", + taxJurisdictionCode = "123" + ) + } + + private fun createAlternativeAddress(): AlternativePostalAddressDto{ + return AlternativePostalAddressDto( + geographicCoordinates = GeoCoordinateDto(longitude = random.nextDouble(), latitude = random.nextDouble(), altitude = random.nextDouble()), + country = CountryCode.entries.random(random), + administrativeAreaLevel1 = testMetadata.adminAreas.random(random), + postalCode = "Alt Postal Code $seed", + city = "Alt City $seed", + deliveryServiceNumber = "Delivery Service Number $seed", + deliveryServiceType = DeliveryServiceType.entries.random(random), + deliveryServiceQualifier = "Delivery Service Qualifier $seed" + ) + } + + private fun Random.nextInstant() = Instant.ofEpochSecond(nextLong(0, 365241780471)) + private fun Random.nextTime() = nextInstant().atOffset(ZoneOffset.UTC).toLocalDateTime() + private fun Random.nextDuration() = Duration.ofHours(nextLong(0, 10000)) + + } +} + +data class InputTestData( + val seed: String, + val request: BusinessPartnerInputRequest +) + +data class TestMetadata( + val identifierTypes: List, + val legalForms: List, + val adminAreas: List +) + +fun BusinessPartnerInputRequest.withoutAnyBpn() = withoutLegalEntityBpn().withoutSiteBpn().withoutAddressBpn() +fun BusinessPartnerInputRequest.withAddressType(addressType: AddressType?) = copy(address = address.copy(addressType = addressType)) +fun BusinessPartnerInputRequest.withoutLegalEntityBpn() = copy(legalEntity = legalEntity.copy(legalEntityBpn = null)) +fun BusinessPartnerInputRequest.withoutSiteBpn() = copy(site = site.copy(siteBpn = null)) +fun BusinessPartnerInputRequest.withoutAddressBpn() = copy(address = address.copy(addressBpn = null)) \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/GateOutputFactory.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/GateOutputFactory.kt new file mode 100644 index 000000000..1908fb42b --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/GateOutputFactory.kt @@ -0,0 +1,95 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.utils + +import org.eclipse.tractusx.bpdm.common.dto.AddressType +import org.eclipse.tractusx.bpdm.gate.api.model.ConfidenceCriteriaDto +import org.eclipse.tractusx.bpdm.gate.api.model.request.BusinessPartnerInputRequest +import org.eclipse.tractusx.bpdm.gate.api.model.response.AddressComponentOutputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerOutputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.LegalEntityRepresentationOutputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.SiteRepresentationOutputDto +import java.time.Instant +import java.time.LocalDateTime +import java.time.temporal.ChronoUnit + +class GateOutputFactory( + private val gateInputTestDataFactory: GateInputFactory +) { + + private val dummyConfidence = ConfidenceCriteriaDto( + sharedByOwner = false, + numberOfSharingMembers = 1, + checkedByExternalDataSource = false, + lastConfidenceCheckAt = LocalDateTime.now(), + nextConfidenceCheckAt = LocalDateTime.now().plus (5, ChronoUnit.DAYS), + confidenceLevel = 0 + ) + + fun createOutput(fromSeed: String, externalId: String = fromSeed): BusinessPartnerOutputDto{ + return createOutput(gateInputTestDataFactory.createFullValid(fromSeed, externalId)) + } + + fun createOutput( + fromInput: BusinessPartnerInputRequest + ): BusinessPartnerOutputDto{ + return BusinessPartnerOutputDto( + externalId = fromInput.externalId, + nameParts = fromInput.nameParts, + identifiers = fromInput.identifiers, + states = fromInput.states, + roles = fromInput.roles, + isOwnCompanyData = fromInput.isOwnCompanyData, + legalEntity = with(fromInput.legalEntity){ + LegalEntityRepresentationOutputDto( + legalEntityBpn = legalEntityBpn ?: "INVALID", + legalName = legalName, + shortName = shortName, + legalForm = legalForm, + confidenceCriteria = dummyConfidence, + states = states + ) + }, + site = with(fromInput.site){ + SiteRepresentationOutputDto( + siteBpn = siteBpn ?: "INVALID", + name = name, + confidenceCriteria = dummyConfidence, + states = states + ) + }, + address = with(fromInput.address){ + AddressComponentOutputDto( + addressBpn = addressBpn ?: "INVALID", + name = name, + addressType = addressType, + physicalPostalAddress = physicalPostalAddress, + alternativePostalAddress = alternativePostalAddress, + confidenceCriteria = dummyConfidence, + states = states + ) + }, + createdAt = Instant.now(), + updatedAt = Instant.now() + ) + } +} + +fun BusinessPartnerOutputDto.withAddressType(addressType: AddressType) = copy(address = address.copy(addressType = addressType)) \ No newline at end of file diff --git a/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/StepUtils.kt b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/StepUtils.kt new file mode 100644 index 000000000..612878687 --- /dev/null +++ b/bpdm-system-tester/src/main/kotlin/org/eclipse/tractusx/bpdm/test/system/utils/StepUtils.kt @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2021,2024 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.test.system.utils + +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.time.delay +import kotlinx.coroutines.time.withTimeout +import org.assertj.core.api.Assertions.assertThat +import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest +import org.eclipse.tractusx.bpdm.gate.api.client.GateClient +import org.eclipse.tractusx.bpdm.gate.api.model.ConfidenceCriteriaDto +import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType +import org.eclipse.tractusx.bpdm.gate.api.model.response.AddressComponentOutputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerOutputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.LegalEntityRepresentationOutputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.SiteRepresentationOutputDto +import java.time.Duration + +class StepUtils( + private val gateClient: GateClient +) { + + fun waitForResult(externalId: String): SharingStateType = runBlocking { + println("Waiting for result for $externalId ...") + withTimeout(Duration.ofMinutes(3)) { + while (true) { + val sharingState = gateClient.sharingState.getSharingStates(PaginationRequest(), listOf(externalId)).content.single() + if (sharingState.sharingStateType == SharingStateType.Success || sharingState.sharingStateType == SharingStateType.Error) { + return@withTimeout sharingState.sharingStateType + } + delay(Duration.ofSeconds(10)) + } + } as SharingStateType + } + + fun assertEqualIgnoreBpns(actualOutput: BusinessPartnerOutputDto, expectedOutput: BusinessPartnerOutputDto){ + assertThat(actualOutput) + .usingRecursiveComparison() + .ignoringCollectionOrder() + .ignoringFields(*ignoredFields) + .isEqualTo(expectedOutput) + } + + val ignoredFields = arrayOf( + BusinessPartnerOutputDto::createdAt.name, + BusinessPartnerOutputDto::updatedAt.name, + "${BusinessPartnerOutputDto::legalEntity.name}.${LegalEntityRepresentationOutputDto::legalEntityBpn.name}", + "${BusinessPartnerOutputDto::site.name}.${SiteRepresentationOutputDto::siteBpn.name}", + "${BusinessPartnerOutputDto::address.name}.${AddressComponentOutputDto::addressBpn.name}", + // ToDo: Cleaning service dummy should have fixed confidence criteria dummy times otherwise we need to keep ignoring these fields + "${BusinessPartnerOutputDto::legalEntity.name}.${AddressComponentOutputDto::confidenceCriteria.name}.${ConfidenceCriteriaDto::lastConfidenceCheckAt.name}", + "${BusinessPartnerOutputDto::legalEntity.name}.${AddressComponentOutputDto::confidenceCriteria.name}.${ConfidenceCriteriaDto::nextConfidenceCheckAt.name}", + "${BusinessPartnerOutputDto::site.name}.${AddressComponentOutputDto::confidenceCriteria.name}.${ConfidenceCriteriaDto::lastConfidenceCheckAt.name}", + "${BusinessPartnerOutputDto::site.name}.${AddressComponentOutputDto::confidenceCriteria.name}.${ConfidenceCriteriaDto::nextConfidenceCheckAt.name}", + "${BusinessPartnerOutputDto::address.name}.${AddressComponentOutputDto::confidenceCriteria.name}.${ConfidenceCriteriaDto::lastConfidenceCheckAt.name}", + "${BusinessPartnerOutputDto::address.name}.${AddressComponentOutputDto::confidenceCriteria.name}.${ConfidenceCriteriaDto::nextConfidenceCheckAt.name}", + ) + + +} \ No newline at end of file diff --git a/bpdm-system-tester/src/main/resources/application.yml b/bpdm-system-tester/src/main/resources/application.yml new file mode 100644 index 000000000..67a04b585 --- /dev/null +++ b/bpdm-system-tester/src/main/resources/application.yml @@ -0,0 +1,13 @@ +bpdm: + client: + pool: + enabled: false + provider: + issuer-uri: ${bpdm.security.auth-server-url:http://localhost:8180}/realms/${bpdm.security.realm:master} + registration: + authorization-grant-type: client_credentials + # Use a default client id for the client credentials request + client-id: BPDM-POOL + # Please provide a secret here +cucumber: + glue: "org.eclipse.tractusx.bpdm.test.system.stepdefinations" diff --git a/bpdm-system-tester/src/main/resources/cucumber.properties b/bpdm-system-tester/src/main/resources/cucumber.properties new file mode 100644 index 000000000..1525b5a64 --- /dev/null +++ b/bpdm-system-tester/src/main/resources/cucumber.properties @@ -0,0 +1,20 @@ +################################################################################ +# Copyright (c) 2021,2024 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 +################################################################################ + +cucumber.glue=org.eclipse.tractusx.bpdm.test.system.stepdefinations \ No newline at end of file diff --git a/bpdm-system-tester/src/main/resources/cucumber/share_generic_business_partner.feature b/bpdm-system-tester/src/main/resources/cucumber/share_generic_business_partner.feature new file mode 100644 index 000000000..c68c564aa --- /dev/null +++ b/bpdm-system-tester/src/main/resources/cucumber/share_generic_business_partner.feature @@ -0,0 +1,34 @@ +Feature: Share Valid Generic Business Partner without BPNs + Scenario: Update Without Address Type + Given output "CC_SHG_UWAT_1" with external-ID "CC_SHG_UWAT" + When the sharing member uploads full valid input "CC_SHG_UWAT_2" with external-ID "CC_SHG_UWAT" without address type + Then the sharing member receives output "CC_SHG_UWAT_2" with external-ID "CC_SHG_UWAT" with address type "LegalAndSiteMainAddress" + + Scenario: Share Without Address Type + When the sharing member uploads full valid input "CC_SHG_WAT" with external-ID "CC_SHG_WAT" without address type + Then the sharing member receives output "CC_SHG_WAT" with external-ID "CC_SHG_WAT" with address type "LegalAndSiteMainAddress" + + Scenario Outline: Share With Address Type + When the sharing member uploads full valid input "CC_SHG_WAT" with external-ID "" with address type "" + Then the sharing member receives output "CC_SHG_WAT" with external-ID "" with address type "" + + Examples: + | externalId | inputAddressType | outputAddressType | + | CC_SHG_WAT_1 | LegalAndSiteMainAddress | LegalAndSiteMainAddress | + | CC_SHG_WAT_2 | LegalAddress | LegalAndSiteMainAddress | + | CC_SHG_WAT_3 | SiteMainAddress | SiteMainAddress | + | CC_SHG_WAT_4 | AdditionalAddress | AdditionalAddress | + + Scenario Outline: Share With Missing or Invalid data + When the sharing member uploads input "CC_SHG_WATT" with external-ID "" without mandatory field "" + Then the sharing member receives sharing error "CC_SHG_WATT" with external-ID "" with error message "" + + Examples: + | externalId | mandatoryField | errorMessage | + | CC_SHG_WATT_1 | legalName | Legal name is null | + | CC_SHG_WATT_2 | physicalAddress.country | Physical Address has no country | + | CC_SHG_WATT_3 | physicalAddress.city | Physical Address has no city | + | CC_SHG_WATT_4 | alternativeAddress.country | Alternative Address has no country | + | CC_SHG_WATT_5 | alternativeAddress.city | Alternative Address has no city | + | CC_SHG_WATT_6 | alternativeAddress.deliveryServiceType | Alternative Address has no delivery service type | + | CC_SHG_WATT_7 | alternativeAddress.deliveryServiceNumber | Alternative Address has no delivery service number | \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0049c3140..469a8332e 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,7 @@ bpdm-cleaning-service-dummy bpdm-orchestrator bpdm-orchestrator-api + bpdm-system-tester @@ -57,6 +58,7 @@ 2.1 3.2.5 2.1.0 + 1.8.1 2.7.0 1.29 3.0.5