diff --git a/.github/actions/cf-bind/action.yml b/.github/actions/cf-bind/action.yml new file mode 100644 index 00000000..08ce16db --- /dev/null +++ b/.github/actions/cf-bind/action.yml @@ -0,0 +1,78 @@ +name: Bind Cloud Foundry Services +description: Login to CF and bind services for hybrid testing via cds bind + +inputs: + cf-api: + description: Cloud Foundry API endpoint + required: true + cf-username: + description: Cloud Foundry username + required: true + cf-password: + description: Cloud Foundry password + required: true + cf-org: + description: Cloud Foundry organization + required: true + cf-space: + description: Cloud Foundry space + required: true + auth-method: + description: 'Malware scanner authentication method: basic or mtls' + required: true + +runs: + using: composite + steps: + - name: Install CF CLI + shell: bash + run: | + wget -q "https://packages.cloudfoundry.org/stable?release=linux64-binary&version=8.9.0&source=github-rel" -O cf-cli.tar.gz + tar -xzf cf-cli.tar.gz + sudo mv cf8 /usr/local/bin/cf + cf --version + + - name: CF Login + shell: bash + run: | + for i in {1..5}; do + cf login -a ${{ inputs.cf-api }} -u ${{ inputs.cf-username }} \ + -p ${{ inputs.cf-password }} -o ${{ inputs.cf-org }} -s ${{ inputs.cf-space }} && break + echo "cf login failed, retrying ($i/5)..." + sleep 10 + if [ "$i" -eq 5 ]; then + echo "cf login failed after 5 attempts." + exit 1 + fi + done + + - name: Install CDS dependencies + shell: bash + run: npm ci + working-directory: integration-tests/mtx-local + + - name: Bind objectstore + shell: bash + working-directory: integration-tests/mtx-local + run: | + for i in {1..5}; do + npx cds bind os -2 os:pipeline && break + echo "cds bind objectstore failed, retrying ($i/5)..." + sleep 30 + if [ "$i" -eq 5 ]; then + echo "cds bind objectstore failed after 5 attempts." + exit 1 + fi + done + + - name: Bind malware-scanner (basic) + if: inputs.auth-method == 'basic' + shell: bash + working-directory: integration-tests/mtx-local + run: npx cds bind malware -2 malware:malware-key-basic + + - name: Bind malware-scanner (mtls) + if: inputs.auth-method == 'mtls' + shell: bash + working-directory: integration-tests/mtx-local + run: npx cds bind malware -2 malware:malware-key-mtls diff --git a/.github/actions/integration-tests/action.yml b/.github/actions/integration-tests/action.yml index 8be8de2a..0b19579f 100644 --- a/.github/actions/integration-tests/action.yml +++ b/.github/actions/integration-tests/action.yml @@ -1,5 +1,5 @@ -name: Integration Tests with current version of CAP Java -description: Run integration tests with the current version of CAP Java using Maven. +name: Integration Tests +description: Run integration tests using Maven with cds bind for service bindings. inputs: java-version: @@ -8,12 +8,6 @@ inputs: maven-version: description: The Maven version the build shall run with. required: true - test-type: - description: 'Which integration test to run: build-version, latest-version, or oss' - required: true - auth-method: - description: 'Authentication method: basic or mtls' - required: true runs: using: composite @@ -34,17 +28,12 @@ runs: run: mvn clean install -ntp -B -pl cds-feature-attachments,storage-targets/cds-feature-attachments-fs,storage-targets/cds-feature-attachments-oss -am shell: bash - - name: Integration Tests with version of CAP Java used for build - if: inputs.test-type == 'build-version' - run: mvn clean verify -ntp -B -f ./integration-tests/pom.xml - shell: bash - - - name: Integration Tests with latest version of CAP Java - if: inputs.test-type == 'latest-version' - run: mvn clean verify -ntp -B -f ./integration-tests/pom.xml -P latest-test-version + - name: Integration Tests (build version) + run: npx cds bind --exec -- mvn clean verify -ntp -B -f ../../integration-tests/pom.xml + working-directory: integration-tests/mtx-local shell: bash - - name: Integration Tests for the object store service - if: inputs.test-type == 'oss' - run: mvn clean verify -ntp -B -Pintegration-tests-oss + - name: Integration Tests (latest CAP Java) + run: npx cds bind --exec -- mvn verify -ntp -B -f ../../integration-tests/pom.xml -P latest-test-version + working-directory: integration-tests/mtx-local shell: bash diff --git a/.github/actions/scan-with-sonar/action.yml b/.github/actions/scan-with-sonar/action.yml index a39d7612..0258878d 100644 --- a/.github/actions/scan-with-sonar/action.yml +++ b/.github/actions/scan-with-sonar/action.yml @@ -71,7 +71,7 @@ runs: -Dsonar.qualitygate.wait=true -Dsonar.java.source=17 -Dsonar.exclusions=**/samples/** - -Dsonar.coverage.jacoco.xmlReportPaths=coverage-report/target/site/jacoco-aggregate/jacoco.xml + -Dsonar.coverage.jacoco.xmlReportPaths=${{ github.workspace }}/coverage-report/target/site/jacoco-aggregate/jacoco.xml -Dsonar.coverage.exclusions=cds-feature-attachments/src/test/**,cds-feature-attachments/src/gen/**,storage-targets/cds-feature-attachments-fs/src/test/**,storage-targets/cds-feature-attachments-oss/src/test/** -B -ntp shell: bash diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index e3623638..10e74fcf 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -39,73 +39,57 @@ jobs: run: mvn spotless:check -Dspotless.check.skip=false -B -ntp integration-tests: - name: ITests (Java ${{ matrix.java-version }}, ${{ matrix.test-type }}, ${{ matrix.auth-method }}) + name: ITests (Java ${{ matrix.java-version }}, ${{ matrix.auth-method }}, ${{ matrix.hyperscaler }}) runs-on: ubuntu-latest timeout-minutes: 30 strategy: fail-fast: false matrix: java-version: [ 17, 21 ] - test-type: [ build-version, latest-version, oss ] auth-method: [ basic, mtls ] - env: - AWS_S3_HOST: ${{ secrets.AWS_S3_HOST }} - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_S3_REGION: ${{ secrets.AWS_S3_REGION }} - AWS_S3_ACCESS_KEY_ID: ${{ secrets.AWS_S3_ACCESS_KEY_ID }} - AWS_S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_SECRET_ACCESS_KEY }} - AZURE_CONTAINER_URI: ${{ secrets.AZURE_CONTAINER_URI }} - AZURE_SAS_TOKEN: ${{ secrets.AZURE_SAS_TOKEN }} - GS_BASE_64_ENCODED_PRIVATE_KEY_DATA: ${{ secrets.GS_BASE_64_ENCODED_PRIVATE_KEY_DATA }} - GS_BUCKET: ${{ secrets.GS_BUCKET }} - GS_PROJECT_ID: ${{ secrets.GS_PROJECT_ID }} - MALWARE_SCANNER_URL: ${{ matrix.auth-method == 'basic' && secrets.MALWARE_SCANNER_URL || '' }} - MALWARE_SCANNER_USERNAME: ${{ matrix.auth-method == 'basic' && secrets.MALWARE_SCANNER_USERNAME || '' }} - MALWARE_SCANNER_PASSWORD: ${{ matrix.auth-method == 'basic' && secrets.MALWARE_SCANNER_PASSWORD || '' }} - MALWARE_SCANNER_MTLS_URI: ${{ matrix.auth-method == 'mtls' && secrets.MALWARE_SCANNER_MTLS_URI || '' }} - MALWARE_SCANNER_MTLS_CERTIFICATE: ${{ matrix.auth-method == 'mtls' && secrets.MALWARE_SCANNER_MTLS_CERTIFICATE || '' }} - MALWARE_SCANNER_MTLS_KEY: ${{ matrix.auth-method == 'mtls' && secrets.MALWARE_SCANNER_MTLS_KEY || '' }} + hyperscaler: [ AWS, AZURE, GCP ] steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.sha || github.sha }} + - name: Bind CF Services + uses: ./.github/actions/cf-bind + with: + cf-api: ${{ secrets[format('CF_API_{0}', matrix.hyperscaler)] }} + cf-username: ${{ secrets.CF_USERNAME }} + cf-password: ${{ secrets.CF_PASSWORD }} + cf-org: ${{ secrets[format('CF_ORG_{0}', matrix.hyperscaler)] }} + cf-space: ${{ secrets[format('CF_SPACE_{0}', matrix.hyperscaler)] }} + auth-method: ${{ matrix.auth-method }} + - name: Integration Tests uses: ./.github/actions/integration-tests with: java-version: ${{ matrix.java-version }} maven-version: ${{ env.MAVEN_VERSION }} - test-type: ${{ matrix.test-type }} - auth-method: ${{ matrix.auth-method }} sonarqube-scan: name: SonarQube Scan runs-on: ubuntu-latest timeout-minutes: 30 - env: - AWS_S3_HOST: ${{ secrets.AWS_S3_HOST }} - AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }} - AWS_S3_REGION: ${{ secrets.AWS_S3_REGION }} - AWS_S3_ACCESS_KEY_ID: ${{ secrets.AWS_S3_ACCESS_KEY_ID }} - AWS_S3_SECRET_ACCESS_KEY: ${{ secrets.AWS_S3_SECRET_ACCESS_KEY }} - AZURE_CONTAINER_URI: ${{ secrets.AZURE_CONTAINER_URI }} - AZURE_SAS_TOKEN: ${{ secrets.AZURE_SAS_TOKEN }} - GS_BASE_64_ENCODED_PRIVATE_KEY_DATA: ${{ secrets.GS_BASE_64_ENCODED_PRIVATE_KEY_DATA }} - GS_BUCKET: ${{ secrets.GS_BUCKET }} - GS_PROJECT_ID: ${{ secrets.GS_PROJECT_ID }} - MALWARE_SCANNER_URL: ${{ secrets.MALWARE_SCANNER_URL }} - MALWARE_SCANNER_USERNAME: ${{ secrets.MALWARE_SCANNER_USERNAME }} - MALWARE_SCANNER_PASSWORD: ${{ secrets.MALWARE_SCANNER_PASSWORD }} - MALWARE_SCANNER_MTLS_URI: ${{ secrets.MALWARE_SCANNER_MTLS_URI }} - MALWARE_SCANNER_MTLS_CERTIFICATE: ${{ secrets.MALWARE_SCANNER_MTLS_CERTIFICATE }} - MALWARE_SCANNER_MTLS_KEY: ${{ secrets.MALWARE_SCANNER_MTLS_KEY }} steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: ref: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.head.sha || github.sha }} + - name: Bind CF Services + uses: ./.github/actions/cf-bind + with: + cf-api: ${{ secrets.CF_API_AWS }} + cf-username: ${{ secrets.CF_USERNAME }} + cf-password: ${{ secrets.CF_PASSWORD }} + cf-org: ${{ secrets.CF_ORG_AWS }} + cf-space: ${{ secrets.CF_SPACE_AWS }} + auth-method: basic + - name: SonarQube Scan uses: ./.github/actions/scan-with-sonar with: diff --git a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/service/malware/client/MalwareScanClientIT.java b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/service/malware/client/MalwareScanClientIT.java index e29302c7..b1d247a8 100644 --- a/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/service/malware/client/MalwareScanClientIT.java +++ b/cds-feature-attachments/src/test/java/com/sap/cds/feature/attachments/service/malware/client/MalwareScanClientIT.java @@ -4,15 +4,13 @@ package com.sap.cds.feature.attachments.service.malware.client; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import com.sap.cds.services.environment.CdsProperties.ConnectionPool; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; import java.time.Duration; -import java.util.Map; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Nested; @@ -20,9 +18,6 @@ import org.junit.jupiter.api.TestInstance; class MalwareScanClientIT { - // The tests in this class are intended to run against a real Malware Scanner instance. - // They require valid credentials set up in the environment. - // Basic auth and mTLS tests skip independently when their credentials are missing. private static final String EICAR_TEST_STRING = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*"; @@ -30,15 +25,16 @@ class MalwareScanClientIT { private static final ConnectionPool CONNECTION_POOL = new ConnectionPool(Duration.ofSeconds(120), 20, 20); - private static MalwareScanClient buildClient(Map creds) { - ServiceBinding binding = mock(ServiceBinding.class); - when(binding.getCredentials()).thenReturn(creds); - HttpClientProvider clientProvider = new MalwareScanClientProvider(binding, CONNECTION_POOL); - return new DefaultMalwareScanClient(clientProvider); + private static ServiceBinding getMalwareScannerBinding() { + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("malware-scanner"::equals).orElse(false)) + .findFirst() + .orElse(null); } - private static String normalizePem(String pem) { - return pem.replace("\\n", "\n"); + private static MalwareScanClient buildClient(ServiceBinding binding) { + HttpClientProvider clientProvider = new MalwareScanClientProvider(binding, CONNECTION_POOL); + return new DefaultMalwareScanClient(clientProvider); } @Nested @@ -49,18 +45,12 @@ class BasicAuth { @BeforeAll void setUp() { - String url = System.getenv("MALWARE_SCANNER_URL"); - String username = System.getenv("MALWARE_SCANNER_USERNAME"); - String password = System.getenv("MALWARE_SCANNER_PASSWORD"); - - if (url == null || username == null || password == null) { - client = null; - } else { - client = buildClient(Map.of("url", url, "username", username, "password", password)); + ServiceBinding binding = getMalwareScannerBinding(); + if (binding != null && binding.getCredentials().containsKey("username")) { + client = buildClient(binding); } - Assumptions.assumeTrue( - client != null, "Basic auth malware scanner credentials not available — skipping tests"); + client != null, "Basic auth malware scanner binding not available — skipping tests"); } @Test @@ -90,26 +80,12 @@ class Mtls { @BeforeAll void setUp() { - String uri = System.getenv("MALWARE_SCANNER_MTLS_URI"); - String certificate = System.getenv("MALWARE_SCANNER_MTLS_CERTIFICATE"); - String key = System.getenv("MALWARE_SCANNER_MTLS_KEY"); - - if (uri == null || certificate == null || key == null) { - client = null; - } else { - client = - buildClient( - Map.of( - "uri", - uri, - "certificate", - normalizePem(certificate), - "key", - normalizePem(key))); + ServiceBinding binding = getMalwareScannerBinding(); + if (binding != null && binding.getCredentials().containsKey("certificate")) { + client = buildClient(binding); } - Assumptions.assumeTrue( - client != null, "mTLS malware scanner credentials not available — skipping tests"); + client != null, "mTLS malware scanner binding not available — skipping tests"); } @Test diff --git a/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AwsMtxOssStorageTest.java b/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AwsMtxOssStorageTest.java index 068504f6..c2e8d571 100644 --- a/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AwsMtxOssStorageTest.java +++ b/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AwsMtxOssStorageTest.java @@ -3,46 +3,22 @@ */ package com.sap.cds.feature.attachments.integrationtests.mt.oss; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; -import java.util.HashMap; /** * Runs the multitenancy OSS storage integration tests against a real AWS S3 instance. Skipped - * automatically if the required environment variables are not set. - * - *

Required environment variables: {@code AWS_S3_HOST}, {@code AWS_S3_BUCKET}, {@code - * AWS_S3_REGION}, {@code AWS_S3_ACCESS_KEY_ID}, {@code AWS_S3_SECRET_ACCESS_KEY}. + * automatically if no objectstore binding with AWS credentials is available in VCAP_SERVICES. */ class AwsMtxOssStorageTest extends AbstractMtxOssStorageTest { @Override protected ServiceBinding getServiceBinding() { - String host = System.getenv("AWS_S3_HOST"); - String bucket = System.getenv("AWS_S3_BUCKET"); - String region = System.getenv("AWS_S3_REGION"); - String accessKeyId = System.getenv("AWS_S3_ACCESS_KEY_ID"); - String secretAccessKey = System.getenv("AWS_S3_SECRET_ACCESS_KEY"); - - if (host == null - || bucket == null - || region == null - || accessKeyId == null - || secretAccessKey == null) { - return null; - } - - ServiceBinding binding = mock(ServiceBinding.class); - HashMap creds = new HashMap<>(); - creds.put("host", host); - creds.put("bucket", bucket); - creds.put("region", region); - creds.put("access_key_id", accessKeyId); - creds.put("secret_access_key", secretAccessKey); - when(binding.getCredentials()).thenReturn(creds); - return binding; + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("objectstore"::equals).orElse(false)) + .filter(b -> b.getCredentials().containsKey("access_key_id")) + .findFirst() + .orElse(null); } @Override diff --git a/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AzureMtxOssStorageTest.java b/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AzureMtxOssStorageTest.java index 1ebe1a35..f806406b 100644 --- a/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AzureMtxOssStorageTest.java +++ b/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/AzureMtxOssStorageTest.java @@ -3,35 +3,23 @@ */ package com.sap.cds.feature.attachments.integrationtests.mt.oss; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; -import java.util.HashMap; /** * Runs the multitenancy OSS storage integration tests against a real Azure Blob Storage instance. - * Skipped automatically if the required environment variables are not set. - * - *

Required environment variables: {@code AZURE_CONTAINER_URI}, {@code AZURE_SAS_TOKEN}. + * Skipped automatically if no objectstore binding with Azure credentials is available in + * VCAP_SERVICES. */ class AzureMtxOssStorageTest extends AbstractMtxOssStorageTest { @Override protected ServiceBinding getServiceBinding() { - String containerUri = System.getenv("AZURE_CONTAINER_URI"); - String sasToken = System.getenv("AZURE_SAS_TOKEN"); - - if (containerUri == null || sasToken == null) { - return null; - } - - ServiceBinding binding = mock(ServiceBinding.class); - HashMap creds = new HashMap<>(); - creds.put("container_uri", containerUri); - creds.put("sas_token", sasToken); - when(binding.getCredentials()).thenReturn(creds); - return binding; + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("objectstore"::equals).orElse(false)) + .filter(b -> b.getCredentials().containsKey("container_uri")) + .findFirst() + .orElse(null); } @Override diff --git a/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/GcpMtxOssStorageTest.java b/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/GcpMtxOssStorageTest.java index 017248d7..9476ff78 100644 --- a/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/GcpMtxOssStorageTest.java +++ b/integration-tests/mtx-local/srv/src/test/java/com/sap/cds/feature/attachments/integrationtests/mt/oss/GcpMtxOssStorageTest.java @@ -3,38 +3,23 @@ */ package com.sap.cds.feature.attachments.integrationtests.mt.oss; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; -import java.util.HashMap; /** * Runs the multitenancy OSS storage integration tests against a real Google Cloud Storage instance. - * Skipped automatically if the required environment variables are not set. - * - *

Required environment variables: {@code GS_BUCKET}, {@code GS_PROJECT_ID}, {@code - * GS_BASE_64_ENCODED_PRIVATE_KEY_DATA}. + * Skipped automatically if no objectstore binding with GCP credentials is available in + * VCAP_SERVICES. */ class GcpMtxOssStorageTest extends AbstractMtxOssStorageTest { @Override protected ServiceBinding getServiceBinding() { - String bucket = System.getenv("GS_BUCKET"); - String projectId = System.getenv("GS_PROJECT_ID"); - String base64EncodedPrivateKeyData = System.getenv("GS_BASE_64_ENCODED_PRIVATE_KEY_DATA"); - - if (bucket == null || projectId == null || base64EncodedPrivateKeyData == null) { - return null; - } - - ServiceBinding binding = mock(ServiceBinding.class); - HashMap creds = new HashMap<>(); - creds.put("bucket", bucket); - creds.put("projectId", projectId); - creds.put("base64EncodedPrivateKeyData", base64EncodedPrivateKeyData); - when(binding.getCredentials()).thenReturn(creds); - return binding; + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("objectstore"::equals).orElse(false)) + .filter(b -> b.getCredentials().containsKey("base64EncodedPrivateKeyData")) + .findFirst() + .orElse(null); } @Override diff --git a/pom.xml b/pom.xml index 024fe7d4..8c61f81d 100644 --- a/pom.xml +++ b/pom.xml @@ -71,13 +71,9 @@ - 4.6.1 + 4.9.0 - 9.6.1 - - - 4.8.0 - 9.7.2 + 9.9.0 true diff --git a/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AWSClientIT.java b/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AWSClientIT.java index 40aef4d3..d40a3c35 100644 --- a/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AWSClientIT.java +++ b/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AWSClientIT.java @@ -3,51 +3,30 @@ */ package com.sap.cds.feature.attachments.oss.client; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import com.sap.cds.feature.attachments.oss.handler.OSSAttachmentsServiceHandlerTestUtils; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; -import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.junit.jupiter.api.Test; class AWSClientIT { - // The tests in this class are intended to run against a real AWS Storage instance. - // They require a valid ServiceBinding with credentials set up in the environment. @Test void testCreateReadDeleteAttachmentFlowAWS() { - ServiceBinding binding = getRealServiceBindingAWS(); + ServiceBinding binding = getObjectStoreBinding(); + assumeTrue(binding != null, "No AWS objectstore binding available"); ExecutorService executor = Executors.newCachedThreadPool(); OSSAttachmentsServiceHandlerTestUtils.testCreateReadDeleteAttachmentFlow(binding, executor); } - private ServiceBinding getRealServiceBindingAWS() { - // Read environment variables - String host = System.getenv("AWS_S3_HOST"); - String bucket = System.getenv("AWS_S3_BUCKET"); - String region = System.getenv("AWS_S3_REGION"); - String accessKeyId = System.getenv("AWS_S3_ACCESS_KEY_ID"); - String secretAccessKey = System.getenv("AWS_S3_SECRET_ACCESS_KEY"); - - // Return null if any are missing - if (host == null - || bucket == null - || region == null - || accessKeyId == null - || secretAccessKey == null) { - return null; - } - - ServiceBinding binding = mock(ServiceBinding.class); - HashMap creds = new HashMap<>(); - creds.put("host", host); - creds.put("bucket", bucket); - creds.put("region", region); - creds.put("access_key_id", accessKeyId); - creds.put("secret_access_key", secretAccessKey); - when(binding.getCredentials()).thenReturn(creds); - return binding; + private ServiceBinding getObjectStoreBinding() { + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("objectstore"::equals).orElse(false)) + .filter(b -> b.getCredentials().containsKey("access_key_id")) + .findFirst() + .orElse(null); } } diff --git a/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AzureClientIT.java b/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AzureClientIT.java index 387e6b68..fc16a1fb 100644 --- a/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AzureClientIT.java +++ b/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/AzureClientIT.java @@ -3,41 +3,30 @@ */ package com.sap.cds.feature.attachments.oss.client; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import com.sap.cds.feature.attachments.oss.handler.OSSAttachmentsServiceHandlerTestUtils; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; -import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.junit.jupiter.api.Test; class AzureClientIT { - // The tests in this class are intended to run against a real Azure instance. - // They require a valid ServiceBinding with credentials set up in the environment. @Test void testCreateReadDeleteAttachmentFlowAzure() { - ServiceBinding binding = getRealServiceBindingAzure(); + ServiceBinding binding = getObjectStoreBinding(); + assumeTrue(binding != null, "No Azure objectstore binding available"); ExecutorService executor = Executors.newCachedThreadPool(); - OSSAttachmentsServiceHandlerTestUtils.testCreateReadDeleteAttachmentFlow(binding, executor); } - private ServiceBinding getRealServiceBindingAzure() { - // Read environment variables - String containerUri = System.getenv("AZURE_CONTAINER_URI"); - String sasToken = System.getenv("AZURE_SAS_TOKEN"); - // Return null if any are missing - if (containerUri == null || sasToken == null) { - return null; - } - - ServiceBinding binding = mock(ServiceBinding.class); - HashMap creds = new HashMap<>(); - creds.put("container_uri", containerUri); - creds.put("sas_token", sasToken); - when(binding.getCredentials()).thenReturn(creds); - return binding; + private ServiceBinding getObjectStoreBinding() { + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("objectstore"::equals).orElse(false)) + .filter(b -> b.getCredentials().containsKey("container_uri")) + .findFirst() + .orElse(null); } } diff --git a/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/GoogleClientIT.java b/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/GoogleClientIT.java index 759c4967..6230a58b 100644 --- a/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/GoogleClientIT.java +++ b/storage-targets/cds-feature-attachments-oss/src/test/java/com/sap/cds/feature/attachments/oss/client/GoogleClientIT.java @@ -3,44 +3,30 @@ */ package com.sap.cds.feature.attachments.oss.client; -import static org.mockito.Mockito.*; +import static org.junit.jupiter.api.Assumptions.assumeTrue; import com.sap.cds.feature.attachments.oss.handler.OSSAttachmentsServiceHandlerTestUtils; +import com.sap.cloud.environment.servicebinding.api.DefaultServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; -import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.junit.jupiter.api.Test; class GoogleClientIT { - // The tests in this class are intended to run against a real Google Cloud Storage instance. - // They require a valid ServiceBinding with credentials set up in the environment. @Test void testCreateReadDeleteAttachmentFlowGoogle() { - ServiceBinding binding = getRealServiceBindingGoogle(); + ServiceBinding binding = getObjectStoreBinding(); + assumeTrue(binding != null, "No Google Cloud Storage objectstore binding available"); ExecutorService executor = Executors.newCachedThreadPool(); - OSSAttachmentsServiceHandlerTestUtils.testCreateReadDeleteAttachmentFlow(binding, executor); } - private ServiceBinding getRealServiceBindingGoogle() { - // Read environment variables - String bucket = System.getenv("GS_BUCKET"); - String projectId = System.getenv("GS_PROJECT_ID"); - String base64EncodedPrivateKeyData = System.getenv("GS_BASE_64_ENCODED_PRIVATE_KEY_DATA"); - - // Return null if any are missing - if (bucket == null || projectId == null || base64EncodedPrivateKeyData == null) { - return null; - } - - ServiceBinding binding = mock(ServiceBinding.class); - HashMap creds = new HashMap<>(); - creds.put("bucket", bucket); - creds.put("projectId", projectId); - creds.put("base64EncodedPrivateKeyData", base64EncodedPrivateKeyData); - when(binding.getCredentials()).thenReturn(creds); - return binding; + private ServiceBinding getObjectStoreBinding() { + return DefaultServiceBindingAccessor.getInstance().getServiceBindings().stream() + .filter(b -> b.getServiceName().map("objectstore"::equals).orElse(false)) + .filter(b -> b.getCredentials().containsKey("base64EncodedPrivateKeyData")) + .findFirst() + .orElse(null); } }