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/doc/Design.md b/doc/Design.md
index 1945024c5..6777dde22 100644
--- a/doc/Design.md
+++ b/doc/Design.md
@@ -51,7 +51,6 @@
- [Texts](#texts)
- [Tests](#tests)
- [Unit Tests](#unit-tests)
- - [Mutation Tests](#mutation-tests)
- [Integration Tests](#integration-tests)
- [Quality Tools](#quality-tools)
@@ -93,21 +92,19 @@ In folder `.github/workflows` are the GitHub Actions defined. The following tabl
| File Name | Description |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pr.yml` | Builds and tests pull requests for Java 17 and 21. Requires approval for external forks. Each pull request needs green runs from this workflow to be merged. |
-| `main.yml` | Builds, tests, and deploys snapshots when commits are merged to main. Runs unit tests, integration tests, and mutation tests for Java 17 and 21. |
+| `main.yml` | Builds and tests when commits are merged to main. Runs unit tests and integration tests for Java 17 and 21. |
| `release.yml` | Triggered on GitHub releases. Updates version, runs BlackDuck scan, builds, tests, and deploys to Maven Central. See also [Build and Deploy](#build-and-deploy). |
| `pipeline.yml` | Reusable workflow containing shared build, test, integration test, SonarQube scan, CodeQL analysis, and snapshot deployment logic. Called by `pr.yml` and `main.yml`. |
### Build Action
The build step is implemented in action `.github/actions/build/action.yml` which is used in the workflows via `pipeline.yml`.
-As the build action does not only run a build of the project, but also the mutation tests, this action is used in all
-the mentioned workflows.
Additional reusable actions are defined in `.github/actions/`:
| Action | Description |
| --------------------- | ----------------------------------------------------------- |
-| `build` | Builds the project and runs unit/mutation tests |
+| `build` | Builds the project and runs unit tests |
| `integration-tests` | Runs integration tests (build-version, latest-version, oss) |
| `deploy-release` | Deploys release artifacts to Maven Central |
| `newrelease` | Updates version in pom.xml for new releases |
@@ -142,7 +139,7 @@ The following steps are executed in the workflow:
1. Update the version in the `pom.xml` files. The tag used in the release is read and git commands are used to update
the property `revision` in the parent `pom.xml` file.
-2. Build the project and run all unit, integration and mutation tests. Here a reuse action is used which is also
+2. Build the project and run all unit and integration tests. Here a reuse action is used which is also
executed in the main and pull request build.
3. Deploy the project to maven or artifactory. The deployment is done with the maven command `mvn deploy`. The
deployment is done to the repository defined in the `pom.xml` file. So only project parts which have defined the
@@ -660,18 +657,6 @@ The following settings are used for this plugin:
| Complexity Coverage | 95% |
| Class Missed Count | 0 |
-#### Mutation Tests
-
-In addition to this plugin, also mutation tests are executed during the build of the project in the GitHub Actions.
-To run the mutation tests the plugin `pitest-maven` is included in the same pom.
-
-Several mutators are maintained in the plugin and the following settings are used:
-
-| Setting | Value |
-| ----------------------------- | ----- |
-| Coverage Threshold | 95% |
-| Aggregated Mutation Threshold | 90% |
-
### Integration Tests
Spring Boot tests are implemented in the `integration-tests` folder.
@@ -746,7 +731,6 @@ The following quality tools are used in the project to ensure the quality of the
| Spotbugs | Defined in the root `pom.xml` | Static Code check for Java code working in the bytecode. |
| PMD/CPD | Defined in the root `pom.xml` | Static Code check for Java code working on the source code. CPD checks the coding for duplications. |
| Maven Enforcer Plugin | Defined in the root `pom.xml` | Checks if there are dependencies declared twice. |
-| Mutation Tests | Defined in `cds-feature-attachments/pom.xml` | See section [mutation tests](#mutation-tests). |
| Jacoco | Defined in `cds-feature-attachments/pom.xml` | See section [unit tests](#unit-tests). |
| Dependabot | Config is defined in the `.github/dependabot.yml` | Checks for new versions of dependencies. |
| CodeQL | Defined in `pipeline.yml` | Checks for vulnerabilities in the coding. Executed as part of the CI pipeline. |
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 068504f6e..c2e8d5710 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 1ebe1a354..f806406be 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 017248d77..9476ff780 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 2e775ac3b..78fc4a81b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,15 +69,9 @@
2.42.33
0.44.0
-
-
- 4.6.1
-
- 9.6.1
-
- 4.8.0
- 9.7.2
+ 4.9.0
+ 9.9.0
true
@@ -238,11 +232,6 @@
jacoco-maven-plugin
0.8.14
-
- org.pitest
- pitest-maven
- 1.23.0
-
com.github.spotbugs
spotbugs-maven-plugin
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 40aef4d38..d40a3c354 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 387e6b683..fc16a1fbe 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 759c49673..6230a58bb 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);
}
}