Skip to content
Snippets Groups Projects
SenderClientIT.java 32.8 KiB
Newer Older
package dev.fitko.fitconnect.integrationtests;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.RSAKey;
import dev.fitko.fitconnect.api.config.ApplicationConfig;
import dev.fitko.fitconnect.api.config.chunking.AttachmentChunkingConfig;
import dev.fitko.fitconnect.api.domain.model.attachment.Attachment;
import dev.fitko.fitconnect.api.domain.model.event.Event;
Martin Vogel's avatar
Martin Vogel committed
import dev.fitko.fitconnect.api.domain.model.event.Status;
import dev.fitko.fitconnect.api.domain.model.metadata.AuthenticationInformation;
import dev.fitko.fitconnect.api.domain.model.metadata.ContentStructure;
import dev.fitko.fitconnect.api.domain.model.metadata.Hash;
import dev.fitko.fitconnect.api.domain.model.metadata.Metadata;
import dev.fitko.fitconnect.api.domain.model.metadata.SignatureType;
import dev.fitko.fitconnect.api.domain.model.metadata.attachment.ApiAttachment;
import dev.fitko.fitconnect.api.domain.model.metadata.attachment.Purpose;
import dev.fitko.fitconnect.api.domain.model.metadata.data.Data;
import dev.fitko.fitconnect.api.domain.model.metadata.data.MimeType;
import dev.fitko.fitconnect.api.domain.model.metadata.data.SubmissionSchema;
import dev.fitko.fitconnect.api.domain.model.reply.replychannel.ReplyChannel;
import dev.fitko.fitconnect.api.domain.sender.SendableEncryptedSubmission;
import dev.fitko.fitconnect.api.domain.sender.SendableSubmission;
import dev.fitko.fitconnect.api.domain.subscriber.ReceivedSubmission;
import dev.fitko.fitconnect.api.exceptions.client.FitConnectSenderException;
import dev.fitko.fitconnect.api.services.crypto.CryptoService;
import dev.fitko.fitconnect.client.SenderClient;
import dev.fitko.fitconnect.client.SubscriberClient;
import dev.fitko.fitconnect.client.bootstrap.ClientFactory;
import dev.fitko.fitconnect.client.util.ReplyChannelKeyGenerator;
import dev.fitko.fitconnect.core.crypto.HashService;
import dev.fitko.fitconnect.core.crypto.JWECryptoService;
import dev.fitko.fitconnect.integrationtests.condition.EnableIfEnvironmentVariablesAreSet;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static dev.fitko.fitconnect.client.util.ResourceLoadingUtils.readResourceToString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

@EnableIfEnvironmentVariablesAreSet
public class SenderClientIT extends IntegrationTestBase {

    public void cleanup() {
    void testSendAndConfirmCycleWithJsonData() {
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
        final String submissionData = readResourceToString("/submission_data.json");
Henry Borasch's avatar
Henry Borasch committed

        final var submission = SendableSubmission.Builder()
Martin Vogel's avatar
Martin Vogel committed
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
Henry Borasch's avatar
Henry Borasch committed
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .addAttachment(Attachment.fromPath(Path.of("src/test/resources/attachment.txt"), "text/plain"))
                .addAttachment(Attachment.fromByteArray("attachment data".getBytes(), "text/plain"))
Martin Vogel's avatar
Martin Vogel committed
                .setReplyChannel(ReplyChannel.ofDeMail("test@mail.org"))
                .setCallback(URI.create("https://example.callback.net"), "callbackSecretWithMoreThan32Chars")
                .setAuthenticationInformation(List.of(new AuthenticationInformation("identificationReport", "1.0.0", "content")))
Martin Vogel's avatar
Martin Vogel committed
        final var sentSubmission = ClientFactory.createSenderClient(config).send(submission);

        assertNotNull(sentSubmission);

        // When
        final ReceivedSubmission receivedSubmission =
Martin Vogel's avatar
Martin Vogel committed
                ClientFactory.createSubscriberClient(config)
                        .requestSubmission(sentSubmission.getSubmissionId());

        // Then
        assertNotNull(receivedSubmission);
Henry Borasch's avatar
Henry Borasch committed
        assertThat(receivedSubmission.getDataAsString(), is(submissionData));
        assertThat(receivedSubmission.getDataSchemaUri(), is(URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json")));
        assertThat(receivedSubmission.getDataMimeType(), is("application/json"));
        assertThat(receivedSubmission.getServiceType().getIdentifier(), is("urn:de:fim:leika:leistung:99400048079000"));
        assertThat(receivedSubmission.getAttachments(), hasSize(2));
        assertThat(receivedSubmission.getMetadata().getReplyChannel(), is(ReplyChannel.ofDeMail("test@mail.org")));
        assertThat(receivedSubmission.getAttachments().get(0).getDataAsString(), is("Test attachment"));
        assertThat(receivedSubmission.getAttachments().get(0).getMimeType(), is("text/plain"));
    @Test
    void testSendAndConfirmCycleWithXmlData() throws IOException {

        // Given
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
        final String submissionData = readResourceToString("/submission_data.xml");

        final var submission = SendableSubmission.Builder()
Martin Vogel's avatar
Martin Vogel committed
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setXmlData(submissionData, URI.create("urn:de:fim:leika:leistung:99400048079000"))
                .addAttachment(Attachment.fromPath(Path.of("src/test/resources/attachment.txt"), "text/plain"))
                .addAttachment(Attachment.fromByteArray("attachment data".getBytes(), "text/plain"))
Martin Vogel's avatar
Martin Vogel committed
                .setReplyChannel(ReplyChannel.ofDeMail("test@mail.org"))
                .setCallback(URI.create("https://example.callback.net"), "callBackSecretWithMoreThan32Chars")
Martin Vogel's avatar
Martin Vogel committed
        final var sentSubmission = ClientFactory.createSenderClient(config).send(submission);

        assertNotNull(sentSubmission);

        // When
        final ReceivedSubmission receivedSubmission =
Martin Vogel's avatar
Martin Vogel committed
                ClientFactory.createSubscriberClient(config)
                        .requestSubmission(sentSubmission.getSubmissionId());

        // Then
        assertNotNull(receivedSubmission);
        assertThat(receivedSubmission.getDataAsString(), is(submissionData));
        assertThat(receivedSubmission.getDataSchemaUri(), is(URI.create("urn:de:fim:leika:leistung:99400048079000")));
        assertThat(receivedSubmission.getDataMimeType(), is("application/xml"));
        assertThat(receivedSubmission.getAttachments(), hasSize(2));
Martin Vogel's avatar
Martin Vogel committed
        assertThat(receivedSubmission.getMetadata().getReplyChannel(), is(ReplyChannel.ofDeMail("test@mail.org")));
        assertThat(new String(receivedSubmission.getAttachments().get(0).getDataAsBytes()), is("Test attachment"));
    }

    void testNewSubmissionForExistingCaseWithFitConnectReplyChannel() {
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
Martin Vogel's avatar
Martin Vogel committed
        final SenderClient senderClient = ClientFactory.createSenderClient(config);
        final SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
Martin Vogel's avatar
Martin Vogel committed
        final UUID destinationId = UUID.fromString(System.getenv("TEST_DESTINATION_ID"));
        final String submissionData = readResourceToString("/submission_data.json");
        final var firstSubmission = SendableSubmission.Builder()
                .setDestination(destinationId)
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .addAttachment(Attachment.fromPath(Path.of("src/test/resources/attachment.txt"), "text/plain"))
                .build();

        // When
        final var sentFirstSubmission = senderClient.send(firstSubmission);
        assertNotNull(sentFirstSubmission);

        final var secondSubmissionForCase = SendableSubmission.Builder()
                .setDestination(destinationId)
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .setCase(sentFirstSubmission.getCaseId())
Martin Vogel's avatar
Martin Vogel committed
                .setReplyChannel(ReplyChannel.ofFitConnect(ReplyChannelKeyGenerator.generateKeyPair().getPublicKey(), List.of("https://test.fitko.de")))
                .build();

        final var sentSecondSubmission = senderClient.send(secondSubmissionForCase);
        assertNotNull(secondSubmissionForCase);
        assertThat(sentSecondSubmission.getCaseId(), is(sentFirstSubmission.getCaseId()));

        // check if reply channel communication is possible by getting the encryption key
        final ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(sentSecondSubmission.getSubmissionId());
        final JWK encryptionPublicKey = receivedSubmission.getMetadata().getReplyChannel().getFitConnect().getEncryptionPublicKey().toJwk();
        assertThat(encryptionPublicKey, is(secondSubmissionForCase.getReplyChannel().getFitConnect().getEncryptionPublicKey().toJwk()));
    @Test
    void testSendAndConfirmCycleWithEncryptedData() throws ParseException, IOException {

        // Given
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
Martin Vogel's avatar
Martin Vogel committed
        final UUID destinationId = UUID.fromString(System.getenv("TEST_DESTINATION_ID"));

        final CryptoService cryptoService = new JWECryptoService(new HashService());
Martin Vogel's avatar
Martin Vogel committed
        final SenderClient senderClient = ClientFactory.createSenderClient(config);
        final SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
        final RSAKey encryptionKey = RSAKey.parse(senderClient.getPublicKeyForDestination(destinationId));
        final String jsonData = readResourceToString("/submission_data.json");
        final File attachmentFile = new File("src/test/resources/attachment.txt");
        final String attachmentData = Files.readString(attachmentFile.toPath());

        final String encryptedData = cryptoService.encryptBytes(encryptionKey, jsonData.getBytes(StandardCharsets.UTF_8), "application/json");
        final String encryptedAttachment = cryptoService.encryptBytes(encryptionKey, attachmentData.getBytes(StandardCharsets.UTF_8), "text/plain");

        final var submissionSchema = new SubmissionSchema();
Henry Borasch's avatar
Henry Borasch committed
        submissionSchema.setSchemaUri(URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"));
        submissionSchema.setMimeType(MimeType.APPLICATION_JSON);

        final var dataHash = new Hash();
        dataHash.setSignatureType(SignatureType.SHA_512);
        dataHash.setContent(cryptoService.hashBytes(jsonData.getBytes(StandardCharsets.UTF_8)));

        final var data = new Data();
        data.setHash(dataHash);
        data.setSubmissionSchema(submissionSchema);

        final var attachment = new ApiAttachment();
        attachment.setAttachmentId(UUID.randomUUID());
        attachment.setPurpose(Purpose.ATTACHMENT);
        attachment.setFilename(attachmentFile.getName());
        attachment.setMimeType("text/plain");

        final var attachmentHash = new Hash();
        attachmentHash.setContent(cryptoService.hashBytes(attachmentData.getBytes(StandardCharsets.UTF_8)));
        attachmentHash.setSignatureType(SignatureType.SHA_512);
        attachment.setHash(attachmentHash);

        final var contentStructure = new ContentStructure();
        contentStructure.setAttachments(List.of(attachment));
        contentStructure.setData(data);

        final var metadata = new Metadata();
        metadata.setSchema(config.getMetadataSchemaWriteVersion().toString());
        metadata.setContentStructure(contentStructure);
        final String encryptedMetadata = cryptoService.encryptObject(encryptionKey, metadata, "application/json");

        // When
        final var submission = SendableEncryptedSubmission.Builder()
                .setDestination(destinationId)
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setEncryptedMetadata(encryptedMetadata)
                .setEncryptedData(encryptedData)
                .addEncryptedAttachment(attachment.getAttachmentId(), encryptedAttachment)
        final var sentSubmission = senderClient.send(submission);
        assertNotNull(sentSubmission);
        final ReceivedSubmission receivedSubmission = subscriberClient.requestSubmission(sentSubmission.getSubmissionId());
        assertNotNull(receivedSubmission);
        assertThat(receivedSubmission.getDataAsString(), Matchers.is(jsonData));
        assertThat(receivedSubmission.getDataMimeType(), Matchers.is("application/json"));
        assertThat(receivedSubmission.getAttachments().get(0).getDataAsString(StandardCharsets.UTF_8), Matchers.is("Test attachment"));
    }

    @Test
    void testNewEncryptedSubmissionForExistingCaseWithFitConnectReplyChannel() throws ParseException, IOException {

        // Given
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
Martin Vogel's avatar
Martin Vogel committed
        final UUID destinationId = UUID.fromString(System.getenv("TEST_DESTINATION_ID"));

        final CryptoService cryptoService = new JWECryptoService(new HashService());
Martin Vogel's avatar
Martin Vogel committed
        final SenderClient senderClient = ClientFactory.createSenderClient(config);
        final SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);

        final RSAKey encryptionKey = RSAKey.parse(senderClient.getPublicKeyForDestination(destinationId));

        final String jsonData = readResourceToString("/submission_data.json");
        final File attachmentFile = new File("src/test/resources/attachment.txt");
        final String attachmentData = Files.readString(attachmentFile.toPath());

        final String encryptedData = cryptoService.encryptBytes(encryptionKey, jsonData.getBytes(StandardCharsets.UTF_8), MimeType.APPLICATION_JSON.value());
        final String encryptedAttachment = cryptoService.encryptBytes(encryptionKey, attachmentData.getBytes(StandardCharsets.UTF_8), "text/plain");

        final var submissionSchema = new SubmissionSchema();
        submissionSchema.setSchemaUri(URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"));
        submissionSchema.setMimeType(MimeType.APPLICATION_JSON);

        final var dataHash = new Hash();
        dataHash.setSignatureType(SignatureType.SHA_512);
        dataHash.setContent(cryptoService.hashBytes(jsonData.getBytes(StandardCharsets.UTF_8)));

        final var data = new Data();
        data.setHash(dataHash);
        data.setSubmissionSchema(submissionSchema);

        final var attachment = new ApiAttachment();
        attachment.setAttachmentId(UUID.randomUUID());
        attachment.setPurpose(Purpose.ATTACHMENT);
        attachment.setFilename(attachmentFile.getName());
        attachment.setMimeType("text/plain");

        final var attachmentHash = new Hash();
        attachmentHash.setContent(cryptoService.hashBytes(attachmentData.getBytes(StandardCharsets.UTF_8)));
        attachmentHash.setSignatureType(SignatureType.SHA_512);
        attachment.setHash(attachmentHash);

        final var contentStructure = new ContentStructure();
        contentStructure.setAttachments(List.of(attachment));
        contentStructure.setData(data);

        final var metadata = new Metadata();
        metadata.setSchema(config.getMetadataSchemaWriteVersion().toString());
        metadata.setContentStructure(contentStructure);

        final var contentStructureForNewSubmission = new ContentStructure();
        contentStructureForNewSubmission.setData(data);

        final var metadataForNewSubmission = new Metadata();
        metadataForNewSubmission.setSchema(config.getMetadataSchemaWriteVersion().toString());
        metadataForNewSubmission.setContentStructure(contentStructureForNewSubmission);
        metadataForNewSubmission.setReplyChannel(ReplyChannel.ofFitConnect(ReplyChannelKeyGenerator.generateKeyPair().getPublicKey(), List.of("https://test.fitko.de")));

        final String encryptedMetadata = cryptoService.encryptBytes(encryptionKey, new ObjectMapper().writeValueAsBytes(metadata), MimeType.APPLICATION_JSON.value());
        final String encryptedMetadataForNewSubmission = cryptoService.encryptBytes(encryptionKey, new ObjectMapper().writeValueAsBytes(metadataForNewSubmission), MimeType.APPLICATION_JSON.value());

        // When
        final var initialSubmission = SendableEncryptedSubmission.Builder()
                .setDestination(destinationId)
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setEncryptedMetadata(encryptedMetadata)
                .setEncryptedData(encryptedData)
                .addEncryptedAttachment(attachment.getAttachmentId(), encryptedAttachment)
                .build();

        final var sentInitialSubmission = senderClient.send(initialSubmission);
        assertNotNull(sentInitialSubmission);

        final var secondSubmissionForExistingCase = SendableEncryptedSubmission.Builder()
                .setDestination(destinationId)
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setEncryptedMetadata(encryptedMetadataForNewSubmission)
                .setEncryptedData(encryptedData)
                .setCase(sentInitialSubmission.getCaseId())
                .build();

        // Then
        final var sentSecondSubmissionForExistingCase = senderClient.send(secondSubmissionForExistingCase);
        assertNotNull(sentSecondSubmissionForExistingCase);

        final ReceivedSubmission receivedNewSubmissionForCase = subscriberClient.requestSubmission(sentSecondSubmissionForExistingCase.getSubmissionId());
        assertNotNull(sentSecondSubmissionForExistingCase);

        final JWK encryptionPublicKey = receivedNewSubmissionForCase.getMetadata().getReplyChannel().getFitConnect().getEncryptionPublicKey().toJwk();
        assertThat(encryptionPublicKey, is(metadataForNewSubmission.getReplyChannel().getFitConnect().getEncryptionPublicKey().toJwk()));
    }

    @Test
    void testSubmissionDataValidationFromLocalSchemaFile(@TempDir final Path tempDir) throws IOException {

        // Given

        // Prepare locally set submission data schema in given path
        final String schemaResource = readResourceToString("/submission-data-schema/submission_data_schema.json");
        final Path schemaPath = Files.writeString(Path.of(tempDir.toString(), "submission_data_schema.json"), schemaResource);
        final String schemaUri = "https://schema.fitko.de/fim/s00000114_1.1.schema.json";

        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment(true, Map.of(schemaUri, schemaPath.toString()));
        final String submissionData = readResourceToString("/submission_data.json");
        final URI submissionDataSchemaUri = URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json");

        final var submission = SendableSubmission.Builder()
Martin Vogel's avatar
Martin Vogel committed
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, submissionDataSchemaUri)
                .addAttachment(Attachment.fromPath(Path.of("src/test/resources/attachment.txt"), "text/plain"))
                .addAttachment(Attachment.fromByteArray("attachment data".getBytes(), "text/plain"))
Martin Vogel's avatar
Martin Vogel committed
                .setReplyChannel(ReplyChannel.ofDeMail("test@mail.org"))
Martin Vogel's avatar
Martin Vogel committed
        final var sentSubmission = ClientFactory.createSenderClient(config).send(submission);

        // Then
        assertNotNull(sentSubmission);
    void testAbortedSendSubmissionWithKeyValidationNotSilent() {
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment(false);

        // When
        final var submission = SendableSubmission.Builder()
Martin Vogel's avatar
Martin Vogel committed
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(readResourceToString("/submission_data.json"), URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
Martin Vogel's avatar
Martin Vogel committed
        final FitConnectSenderException exception = assertThrows(FitConnectSenderException.class, () -> ClientFactory.createSenderClient(config).send(submission));
        assertThat(exception.getMessage(), containsString("Invalid public encryption key"));
        assertThat(exception.getCause().getMessage(), containsString("JWK with id jsMQHFiA2uMGtiG3Ro8RJnYdEhp5W5KjGW-Vcf3-YMk has an invalid amount of certificates. Is 1 but should be 3."));
    void testReadSubmissionStatus() {
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
        final String submissionData = readResourceToString("/submission_data.json");
Martin Vogel's avatar
Martin Vogel committed
        final SenderClient senderClient = ClientFactory.createSenderClient(config);

        final var submission = SendableSubmission.Builder()
Martin Vogel's avatar
Martin Vogel committed
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .addAttachment(Attachment.fromPath(Path.of("src/test/resources/attachment.txt"), "plain/text"))
                .build();

        final var sentSubmission = senderClient.send(submission);

        assertNotNull(sentSubmission);
Martin Vogel's avatar
Martin Vogel committed
        final Status statusForSubmission = senderClient.getSubmissionStatus(sentSubmission);
Martin Vogel's avatar
Martin Vogel committed
        assertThat(statusForSubmission.getState(), isOneOf(Event.SUBMIT_SUBMISSION.getState(), Event.NOTIFY_SUBMISSION.getState()));
        assertThat(statusForSubmission.getIssuer(), containsString("https://test.fit-connect.fitko.dev"));
    void testSendSubmissionWithAdditionalReferenceInfo() {

        // Given
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment(true);

        final String submissionData = readResourceToString("/submission_data.json");
        final LocalDate applicationDate = LocalDate.of(2020, 1, 1);
        final UUID idBundDeApplicationId = UUID.randomUUID();

        final var submission = SendableSubmission.Builder()
Martin Vogel's avatar
Martin Vogel committed
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .setApplicationDate(applicationDate)
                .setIdBundDeApplicationId(idBundDeApplicationId)
Martin Vogel's avatar
Martin Vogel committed
        final var sentSubmission = ClientFactory.createSenderClient(config).send(submission);

        assertNotNull(sentSubmission);

        // When
        final ReceivedSubmission receivedSubmission =
Martin Vogel's avatar
Martin Vogel committed
                ClientFactory.createSubscriberClient(config)
                        .requestSubmission(sentSubmission.getSubmissionId());

        // Then
        assertNotNull(receivedSubmission);
        assertTrue(receivedSubmission.getApplicationDate().isPresent());
        assertThat(receivedSubmission.getApplicationDate().get(), is(applicationDate));
        assertThat(receivedSubmission.getMetadata().getAdditionalReferenceInfo().getIdBundDeApplicationId(), is(idBundDeApplicationId));
    void testSendSubmissionWithAdditionalReferenceInfoAndBundIdReplyChannel() {

        // Given
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment(true);
        final String submissionData = readResourceToString("/submission_data.json");

        final UUID idBundDeApplicationId = UUID.randomUUID();
        final UUID mailboxId = UUID.randomUUID();

        final var submission = SendableSubmission.Builder()
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .setReplyChannel(ReplyChannel.ofIdBundDeMailbox(mailboxId))
                .setIdBundDeApplicationId(idBundDeApplicationId)
                .build();

        final var sentSubmission = ClientFactory.createSenderClient(config).send(submission);

        assertNotNull(sentSubmission);

        // When
        final ReceivedSubmission receivedSubmission =
                ClientFactory.createSubscriberClient(config)
                        .requestSubmission(sentSubmission.getSubmissionId());

        // Then
        assertNotNull(receivedSubmission.getMetadata().getReplyChannel());
        assertNotNull(receivedSubmission.getMetadata().getAdditionalReferenceInfo());
        assertTrue(receivedSubmission.getMetadata().getReplyChannel().isIdBundDeMailbox());
        assertThat(receivedSubmission.getMetadata().getReplyChannel().getIdBundDeMailbox().getMailboxUuid(), is(mailboxId));
        assertThat(receivedSubmission.getMetadata().getAdditionalReferenceInfo().getIdBundDeApplicationId(), is(idBundDeApplicationId));
    }

    void testSendSubmissionWithChunkedAttachments(@TempDir Path attachmentStoragePath) throws IOException {
        final AttachmentChunkingConfig chunkingConfig = AttachmentChunkingConfig.builder()
                .chunkAllAttachments(true)
                .attachmentStoragePath(attachmentStoragePath)
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment(true, chunkingConfig);
        final SenderClient senderClient = ClientFactory.createSenderClient(config);

        final Path attachmentPath = Path.of("src/test/resources/large-pdf.pdf");
        final byte[] expectedAttachmentData = Files.readAllBytes(attachmentPath);

        final var submission = SendableSubmission.Builder()
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(readResourceToString("/submission_data.json"), URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .addAttachment(Attachment.fromLargeAttachment(attachmentPath, "application/pdf", "large-pdf_1.pdf", "test large pdf"))
                .addAttachment(Attachment.fromPath(attachmentPath, "application/pdf", "large-pdf_3.pdf", "test in-memory pdf"))
        final var sentSubmission = senderClient.send(submission);

        assertNotNull(sentSubmission);

        // When
        final ReceivedSubmission receivedSubmission =
                ClientFactory.createSubscriberClient(config)
                        .requestSubmission(sentSubmission.getSubmissionId());

        // Then
        assertNotNull(receivedSubmission);
        assertThat(receivedSubmission.getAttachments(), hasSize(2));
        assertArrayEquals(expectedAttachmentData, receivedSubmission.getAttachments().get(0).getDataAsBytes());
        assertArrayEquals(expectedAttachmentData, receivedSubmission.getAttachments().get(1).getDataAsBytes());
        // chunking all attachments will lead to attachments that are all stored in filesystem
        assertTrue(receivedSubmission.getAttachments().get(0).isLargeAttachment());
        assertTrue(receivedSubmission.getAttachments().get(1).isLargeAttachment());

        senderClient.clearAttachmentStorage();
        assertThat(attachmentStoragePath.toFile().listFiles().length, is(0));
    }

    @Test
    void testSendSubmissionWithDefaultChunkingForLargeAttachmentsOnly() throws IOException {

        // Given
        final AttachmentChunkingConfig chunkingConfig = AttachmentChunkingConfig.builder()
                .chunkAllAttachments(false)
                .build();

        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment(true, chunkingConfig);

        final Path attachmentPath = Path.of("src/test/resources/large-pdf.pdf");
        final byte[] expectedAttachmentData = Files.readAllBytes(attachmentPath);

        final var submission = SendableSubmission.Builder()
                .setDestination(UUID.fromString(System.getenv("TEST_DESTINATION_ID")))
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(readResourceToString("/submission_data.json"), URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .addAttachment(Attachment.fromLargeAttachment(attachmentPath, "application/pdf", "large-pdf_1.pdf", "test large pdf"))
                .addAttachment(Attachment.fromPath(attachmentPath, "application/pdf", "large-pdf_3.pdf", "test in-memory pdf"))
                .build();

        final var sentSubmission = ClientFactory.createSenderClient(config).send(submission);

        assertNotNull(sentSubmission);

        // When
        final ReceivedSubmission receivedSubmission =
                ClientFactory.createSubscriberClient(config)
                        .requestSubmission(sentSubmission.getSubmissionId());

        // Then
        assertNotNull(receivedSubmission);
        assertThat(receivedSubmission.getAttachments(), hasSize(2));
        assertArrayEquals(expectedAttachmentData, receivedSubmission.getAttachments().get(0).getDataAsBytes());
        assertArrayEquals(expectedAttachmentData, receivedSubmission.getAttachments().get(1).getDataAsBytes());

        assertTrue(receivedSubmission.getAttachments().get(0).isLargeAttachment());
        assertTrue(receivedSubmission.getAttachments().get(1).isInMemoryAttachment());
    void testMultiThreadExecution() throws InterruptedException {
        final ApplicationConfig config = getConfigWithCredentialsFromEnvironment();
Martin Vogel's avatar
Martin Vogel committed
        final SenderClient senderClient = ClientFactory.createSenderClient(config);
        final SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
        final String submissionData = readResourceToString("/submission_data.json");
        final UUID destinationId = UUID.fromString(System.getenv("TEST_DESTINATION_ID"));
        final var submission = SendableSubmission.Builder()
                .setDestination(destinationId)
                .setServiceType("urn:de:fim:leika:leistung:99400048079000", "Test Service")
                .setJsonData(submissionData, URI.create("https://schema.fitko.de/fim/s00000114_1.1.schema.json"))
                .addAttachment(Attachment.fromPath(Path.of("src/test/resources/attachment.txt"), "plain/text"))
                .build();

        // When
        final ExecutorService es = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 25; i++) {
            es.execute(new SenderRunner(senderClient, submission, "Thread-" + i));
        }
        es.shutdown();
        es.awaitTermination(1, TimeUnit.MINUTES);

        // wait for ZSD processing
        Thread.sleep(5000);

        final int handedInSubmissions = subscriberClient.getAvailableSubmissionsForDestination(destinationId).size();

        // Then
        assertThat(handedInSubmissions, is(25));
    static class SenderRunner implements Runnable {
        private final SenderClient senderClient;
        private final SendableSubmission submission;
        private final String threadName;
        SenderRunner(final SenderClient senderClient, final SendableSubmission submission, final String threadName) {
            this.senderClient = senderClient;
            this.submission = submission;
            this.threadName = threadName;
            System.out.println("Creating " + threadName);
        }
        public void run() {
            System.out.println("Running " + threadName);
            assertNotNull(senderClient.send(submission));
            System.out.println("Thread " + threadName + " exiting.");
        }
    }