org.digidoc4j.impl.bdoc.BDocContainerTest.java Source code

Java tutorial

Introduction

Here is the source code for org.digidoc4j.impl.bdoc.BDocContainerTest.java

Source

/* DigiDoc4J library
*
* This software is released under either the GNU Library General Public
* License (see LICENSE.LGPL).
*
* Note that the only valid version of the LGPL license as far as this
* project is concerned is the original GNU Library General Public License
* Version 2.1, February 1999
*/

package org.digidoc4j.impl.bdoc;

import static org.digidoc4j.ContainerBuilder.BDOC_CONTAINER_TYPE;
import static org.digidoc4j.DigestAlgorithm.SHA1;
import static org.digidoc4j.DigestAlgorithm.SHA224;
import static org.digidoc4j.DigestAlgorithm.SHA256;
import static org.digidoc4j.SignatureProfile.B_BES;
import static org.digidoc4j.SignatureProfile.LT;
import static org.digidoc4j.SignatureProfile.LTA;
import static org.digidoc4j.SignatureProfile.LT_TM;
import static org.digidoc4j.testutils.TestDataBuilder.PKCS12_SIGNER;
import static org.digidoc4j.testutils.TestDataBuilder.createEmptyBDocContainer;
import static org.digidoc4j.testutils.TestDataBuilder.signContainer;
import static org.digidoc4j.testutils.TestSigningHelper.getSigningCert;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.zip.ZipFile;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.digidoc4j.Configuration;
import org.digidoc4j.Container;
import org.digidoc4j.ContainerBuilder;
import org.digidoc4j.ContainerOpener;
import org.digidoc4j.DataFile;
import org.digidoc4j.DataToSign;
import org.digidoc4j.DigestAlgorithm;
import org.digidoc4j.EncryptionAlgorithm;
import org.digidoc4j.Signature;
import org.digidoc4j.SignatureBuilder;
import org.digidoc4j.SignatureProfile;
import org.digidoc4j.ValidationResult;
import org.digidoc4j.exceptions.DigiDoc4JException;
import org.digidoc4j.exceptions.DuplicateDataFileException;
import org.digidoc4j.exceptions.InvalidSignatureException;
import org.digidoc4j.exceptions.OCSPRequestFailedException;
import org.digidoc4j.impl.DigiDoc4JTestHelper;
import org.digidoc4j.signers.PKCS12SignatureToken;
import org.digidoc4j.testutils.TestDataBuilder;
import org.digidoc4j.testutils.TestSigningHelper;
import org.digidoc4j.utils.Helper;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import eu.europa.esig.dss.DSSDocument;
import eu.europa.esig.dss.xades.DSSXMLUtils;
import eu.europa.esig.dss.xades.XPathQueryHolder;
import eu.europa.esig.dss.xades.validation.XAdESSignature;

public class BDocContainerTest extends DigiDoc4JTestHelper {

    @Rule
    public TemporaryFolder testFolder = new TemporaryFolder();

    @AfterClass
    public static void deleteTemporaryFiles() {
        try {
            DirectoryStream<Path> directoryStream = Files.newDirectoryStream(Paths.get("."));
            for (Path item : directoryStream) {
                String fileName = item.getFileName().toString();
                if (fileName.endsWith("bdoc") && fileName.startsWith("test"))
                    Files.deleteIfExists(item);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testSetDigestAlgorithmToSHA256() throws Exception {
        assertSettingDigestAlgorithm("http://www.w3.org/2001/04/xmlenc#sha256", SHA256);
    }

    @Test
    public void testSetDigestAlgorithmToSHA1() throws Exception {
        assertSettingDigestAlgorithm("http://www.w3.org/2000/09/xmldsig#sha1", SHA1);
    }

    @Test
    public void testSetDigestAlgorithmToSHA224() throws Exception {
        assertSettingDigestAlgorithm("http://www.w3.org/2001/04/xmldsig-more#sha224", SHA224);
    }

    private void assertSettingDigestAlgorithm(String expectedDigestAlgorithm, DigestAlgorithm actualDigestAlgorithm)
            throws IOException {
        Container container = TestDataBuilder.createContainerWithFile(testFolder);
        BDocSignature signature = (BDocSignature) SignatureBuilder.aSignature(container)
                .withSignatureDigestAlgorithm(actualDigestAlgorithm).withSignatureToken(PKCS12_SIGNER)
                .invokeSigning();
        container.addSignature(signature);
        assertEquals(expectedDigestAlgorithm, signature.getSignatureDigestAlgorithm().getXmlId());
    }

    @Test
    public void testDefaultDigestAlgorithm() throws Exception {
        Container container = TestDataBuilder.createContainerWithFile(testFolder);
        BDocSignature signature = (BDocSignature) SignatureBuilder.aSignature(container)
                .withSignatureToken(PKCS12_SIGNER).invokeSigning();
        container.addSignature(signature);
        assertEquals("http://www.w3.org/2001/04/xmlenc#sha256", signature.getSignatureDigestAlgorithm().getXmlId());
    }

    @Test
    public void testOpenBDocDocument() throws Exception {
        Container container = open("testFiles/one_signature.bdoc");
        container.validate();
    }

    @Test
    public void testOpenBDocDocumentWithTwoSignatures() throws Exception {
        Container container = open("testFiles/two_signatures.bdoc");
        container.validate();
    }

    @Test(expected = DigiDoc4JException.class)
    public void testAddDataFileWhenFileDoesNotExist() throws Exception {
        Container container = createContainerWithFile("notExisting.txt", "text/plain");
    }

    @Test(expected = DigiDoc4JException.class)
    public void testAddDataFileFromInputStreamWithByteArrayConversionFailure() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile(new MockInputStream(), "test.txt", "text/plain");
    }

    @Test(expected = InvalidSignatureException.class)
    public void testAddRawSignature() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addRawSignature(new byte[] {});
    }

    @Test
    public void testAddUnknownFileTypeKeepsMimeType() {
        Container container = createContainerWithFile("testFiles/test.unknown_type", "text/test_type");
        signContainer(container);
        container.save("test_add_unknown_datafile_type.bdoc");

        Container open = ContainerOpener.open("test_add_unknown_datafile_type.bdoc");
        assertEquals("text/test_type", open.getDataFiles().get(0).getMediaType());
    }

    @Test
    public void testSaveBDocDocumentWithTwoSignatures() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        signContainer(container);
        container.save("testTwoSignatures.bdoc");

        assertEquals(2, container.getSignatures().size());
        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                container.getSignatures().get(0).getSigningCertificate().getSerial());
        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                container.getSignatures().get(1).getSigningCertificate().getSerial());

        Container openedContainer = open("testTwoSignatures.bdoc");

        assertEquals(2, openedContainer.getSignatures().size());
        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                openedContainer.getSignatures().get(0).getSigningCertificate().getSerial());
        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                openedContainer.getSignatures().get(1).getSigningCertificate().getSerial());
    }

    @Test
    public void saveContainerWithoutSignatures() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        String path = testFolder.newFile("container.bdoc").getPath();
        container.saveAsFile(path);
        container = open(path);
        assertEquals(1, container.getDataFiles().size());
        assertEquals("test.txt", container.getDataFiles().get(0).getName());
    }

    @Test
    public void openContainer_withoutSignatures_andAddMoreDataFiles() throws Exception {
        Container container = open("testFiles/container_without_signatures.bdoc");
        assertEquals(1, container.getDataFiles().size());
        container.addDataFile("testFiles/test.xml", "text/xml");
        container.addDataFile("testFiles/word_file.docx", "application/octet-stream");
        assertEquals(3, container.getDataFiles().size());
        String path = testFolder.newFile("container.bdoc").getPath();
        container.saveAsFile(path);
        container = open(path);
        assertEquals(3, container.getDataFiles().size());
    }

    @Test
    public void openContainerFromStream_withoutSignatures_andAddMoreDataFiles() throws Exception {
        FileInputStream stream = new FileInputStream("testFiles/container_without_signatures.bdoc");
        Container container = open(stream);
        assertEquals(1, container.getDataFiles().size());
        container.addDataFile("testFiles/test.xml", "text/xml");
        container.addDataFile("testFiles/word_file.docx", "application/octet-stream");
        assertEquals(3, container.getDataFiles().size());
        String path = testFolder.newFile("container.bdoc").getPath();
        container.saveAsFile(path);
        stream = new FileInputStream(path);
        container = open(stream);
        assertEquals(3, container.getDataFiles().size());
    }

    @Test
    public void openContainerWithoutSignatures_addDataFileAndSignContainer() throws Exception {
        Container container = open("testFiles/container_without_signatures.bdoc");
        assertEquals(1, container.getDataFiles().size());
        container.addDataFile("testFiles/test.xml", "text/xml");
        signContainer(container);
        assertEquals(1, container.getSignatures().size());
        assertTrue(container.validate().isValid());
        String path = testFolder.newFile("container.bdoc").getPath();
        container.saveAsFile(path);
        container = open(path);
        assertTrue(container.validate().isValid());
    }

    @Test
    public void testGetDefaultSignatureParameters() {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        container.save("test.bdoc");

        container = open("test.bdoc");
        Signature signature = container.getSignature(0);
        assertNull(signature.getPostalCode());
        assertNull(signature.getCity());
        assertNull(signature.getStateOrProvince());
        assertNull(signature.getCountryName());
        assertThat(signature.getSignerRoles(), is(empty()));
    }

    @Test
    public void getSignatureByIndex() {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        signContainer(container);

        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                container.getSignature(1).getSigningCertificate().getSerial());
    }

    @Test
    public void notThrowingNPEWhenDOCXFileIsAddedToContainer() {
        Container container = createContainerWithFile("testFiles/word_file.docx", "text/xml");
        signContainer(container);
        assertEquals(1, container.getSignatures().size());
    }

    @Test
    public void signPdfDataFile() throws Exception {
        Container container = createContainerWithFile("testFiles/special-char-files/dds_acrobat.pdf",
                "application/pdf");
        signContainer(container);
        assertEquals(1, container.getDataFiles().size());
        assertEquals(1, container.getSignatures().size());
        String containerPath = testFolder.newFile("container.bdoc").getPath();
        container.saveAsFile(containerPath);
        container = open(containerPath);
        assertEquals(1, container.getDataFiles().size());
        assertTrue(container.validate().isValid());
    }

    @Test
    public void testAddSignaturesToExistingDocument() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        signContainer(container);
        container.save("testAddMultipleSignatures.bdoc");

        assertEquals(3, container.getSignatures().size());
        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                container.getSignatures().get(2).getSigningCertificate().getSerial());

        Container openedContainer = open("testAddMultipleSignatures.bdoc");

        assertEquals(3, openedContainer.getSignatures().size());
        assertEquals("530be41bbc597c44570e2b7c13bcfa0c",
                openedContainer.getSignatures().get(2).getSigningCertificate().getSerial());

        ValidationResult validationResult = openedContainer.validate();
        assertEquals(0, validationResult.getErrors().size());
    }

    @Test
    public void testRemoveSignatureWhenOneSignatureExists() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        container.removeSignature(0);
        container.save("testRemoveSignature.bdoc");
        assertEquals(0, container.getSignatures().size());

        container = open("testRemoveSignature.bdoc");
        assertEquals(0, container.getSignatures().size());
    }

    @Test
    public void testAddFilesWithSpecialCharactersIntoContainer() throws Exception {
        Container container = createContainerWithFile(
                "testFiles/special-char-files/dds_dds_JRI   pev.txt", "text/plain");
        container.addDataFile("testFiles/special-char-files/dds_ ?.docx", "text/plain");
        signContainer(container);
        container.saveAsFile("testWithSpecialCharFiles.bdoc");

        assertEquals(0, container.validate().getContainerErrors().size());
    }

    @Test
    public void testRemoveSignatureWhenTwoSignaturesExist() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        assertEquals(2, container.getSignatures().size());
        container.removeSignature(0);
        container.save("testRemoveSignature.bdoc");

        container = open("testRemoveSignature.bdoc");
        assertEquals(1, container.getSignatures().size());
    }

    @Test
    public void testRemoveSignatureWhenThreeSignaturesExist() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");

        signContainer(container);
        container.save("testThreeSignatures.bdoc");
        container = open("testThreeSignatures.bdoc");
        assertEquals(3, container.getSignatures().size());

        container.removeSignature(1);

        container.save("testRemoveSignature.bdoc");

        container = open("testRemoveSignature.bdoc");
        assertEquals(2, container.getSignatures().size());
    }

    @Test
    public void removeNewlyAddedSignatureFromExistingContainer() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        assertEquals(2, container.getSignatures().size());
        signContainer(container);
        assertEquals(3, container.getSignatures().size());
        container.removeSignature(container.getSignatures().get(0));
        assertEquals(2, container.getSignatures().size());
    }

    @Test
    public void removeSignatureFromExistingContainer() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        assertEquals(2, container.getSignatures().size());
        container.removeSignature(container.getSignatures().get(0));
        assertEquals(1, container.getSignatures().size());
        String path = testFolder.newFile("container.bdoc").getPath();
        container.saveAsFile(path);
        container = open(path);
        assertEquals(1, container.getSignatures().size());
    }

    @Test
    public void testSaveDocumentWithOneSignature() throws Exception {
        createSignedBDocDocument("testSaveBDocDocumentWithOneSignature.bdoc");
        assertTrue(Files.exists(Paths.get("testSaveBDocDocumentWithOneSignature.bdoc")));
    }

    @Test(expected = DigiDoc4JException.class)
    public void testRemoveDataFileAfterSigning() throws Exception {
        createSignedBDocDocument("testRemoveDataFile.bdoc");
        Container container = open("testRemoveDataFile.bdoc");
        assertEquals("test.txt", container.getDataFiles().get(0).getName());
        assertEquals(1, container.getDataFiles().size());
        container.removeDataFile("test.txt");
        assertEquals(0, container.getDataFiles().size());
    }

    @Test
    public void testRemoveDataFile() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        assertEquals("test.txt", container.getDataFiles().get(0).getName());
        assertEquals(1, container.getDataFiles().size());
        container.removeDataFile("test.txt");
        assertEquals(0, container.getDataFiles().size());
    }

    @Test(expected = DigiDoc4JException.class)
    public void testAddDataFileAfterSigning() throws Exception {
        createSignedBDocDocument("testAddDataFile.bdoc");
        Container container = open("testAddDataFile.bdoc");
        container.addDataFile("testFiles/test.txt", "text/plain");
    }

    @Test(expected = DigiDoc4JException.class)
    public void testRemovingNonExistingFile() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        container.removeDataFile("test1.txt");
    }

    @Test(expected = DuplicateDataFileException.class)
    public void testAddingSameFileSeveralTimes() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        container.addDataFile("testFiles/test.txt", "text/plain");
    }

    @Test(expected = DuplicateDataFileException.class)
    public void testAddingSamePreCreatedFileSeveralTimes() {
        Container container = createEmptyBDocContainer();
        DataFile dataFile = new DataFile("Hello world!".getBytes(), "test-file.txt", "text/plain");
        container.addDataFile(dataFile);
        container.addDataFile(dataFile);
    }

    @Test
    public void testAddingDifferentPreCreatedFiles() {
        Container container = createEmptyBDocContainer();
        container.addDataFile(new DataFile("Hello world!".getBytes(), "hello.txt", "text/plain"));
        container.addDataFile(new DataFile("Goodbye world!".getBytes(), "goodbye.txt", "text/plain"));
    }

    @Test(expected = DuplicateDataFileException.class)
    public void testAddingSameFileSeveralTimesViaInputStream() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile(new ByteArrayInputStream("test".getBytes()), "testFiles/test.txt", "text/plain");
        container.addDataFile(new ByteArrayInputStream("test".getBytes()), "testFiles/test.txt", "text/plain");
    }

    @Test
    public void testAddDateFileViaInputStream() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile(new ByteArrayInputStream("test".getBytes()), "testFiles/test.txt", "text/plain");
        signContainer(container);
        assertTrue(container.validate().isValid());
    }

    @Test(expected = DuplicateDataFileException.class)
    public void testAddingSameFileInDifferentContainerSeveralTimes() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        container.addDataFile("testFiles/sub/test.txt", "text/plain");
        signContainer(container);
        container.save("testAddSameFile.bdoc");
    }

    @Test(expected = DigiDoc4JException.class)
    public void testAddingNotExistingFile() throws Exception {
        Container container = createContainerWithFile("notExistingFile.txt", "text/plain");
    }

    @Test
    public void testAddFileAsStream() throws Exception {
        Container container = createEmptyBDocContainer();
        ByteArrayInputStream stream = new ByteArrayInputStream("tere, tere".getBytes());
        container.addDataFile(stream, "test1.txt", "text/plain");
        signContainer(container);
        container.save("testAddFileAsStream.bdoc");

        Container containerToTest = open("testAddFileAsStream.bdoc");
        assertEquals("test1.txt", containerToTest.getDataFiles().get(0).getName());
    }

    @Test
    public void setsSignatureId() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");

        Signature signature1 = SignatureBuilder.aSignature(container).withSignatureId("SIGNATURE-1")
                .withSignatureToken(PKCS12_SIGNER).invokeSigning();
        container.addSignature(signature1);

        Signature signature2 = SignatureBuilder.aSignature(container).withSignatureId("SIGNATURE-2")
                .withSignatureToken(PKCS12_SIGNER).invokeSigning();
        container.addSignature(signature2);

        container.saveAsFile("setsSignatureId.bdoc");

        container = open("setsSignatureId.bdoc");
        assertEquals("SIGNATURE-1", container.getSignature(0).getId());
        assertEquals("SIGNATURE-2", container.getSignature(1).getId());

        ZipFile zip = new ZipFile("setsSignatureId.bdoc");
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
    }

    @Test
    public void setsDefaultSignatureId() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        signContainer(container);
        container.save("testSetsDefaultSignatureId.bdoc");

        container = open("testSetsDefaultSignatureId.bdoc");
        String signature1Id = container.getSignatures().get(0).getId();
        String signature2Id = container.getSignatures().get(1).getId();
        assertFalse(StringUtils.equals(signature1Id, signature2Id));
        assertTrue(signature1Id.startsWith("id-"));
        assertTrue(signature2Id.startsWith("id-"));

        ZipFile zip = new ZipFile("testSetsDefaultSignatureId.bdoc");
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
    }

    @Test
    public void getDataFileByIndex() {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);

        assertEquals("test.txt", container.getDataFile(0).getName());
    }

    @Test(expected = DigiDoc4JException.class)
    public void openNonExistingFileThrowsError() {
        open("non-existing.bdoc");
    }

    @Test(expected = DigiDoc4JException.class)
    public void openClosedStreamThrowsException() throws IOException {
        FileInputStream stream = new FileInputStream(new File("testFiles/test.txt"));
        stream.close();
        open(stream, false);
    }

    @Test
    public void testLargeFileSigning() throws Exception {
        BDocContainer container = (BDocContainer) ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE)
                .withConfiguration(new Configuration(Configuration.Mode.TEST)).build();
        container.getConfiguration().enableBigFilesSupport(10);
        String path = createLargeFile((container.getConfiguration().getMaxDataFileCachedInBytes()) + 100);
        container.addDataFile(path, "text/plain");
        signContainer(container);
    }

    @Test
    public void openLargeFileFromStream() throws FileNotFoundException {
        BDocContainer container = (BDocContainer) ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE)
                .withConfiguration(new Configuration(Configuration.Mode.TEST)).build();
        container.getConfiguration().enableBigFilesSupport(0);

        String path = createLargeFile((container.getConfiguration().getMaxDataFileCachedInBytes()) + 100);
        container.addDataFile(path, "text/plain");
        signContainer(container);
        container.save("test-large-file.bdoc");
        File file = new File("test-large-file.bdoc");
        FileInputStream fileInputStream = new FileInputStream(file);
        open(fileInputStream, true);

        IOUtils.closeQuietly(fileInputStream);

        assertEquals(1, container.getSignatures().size());
    }

    @Test
    public void openAddFileFromStream() throws IOException {
        BDocContainer container = (BDocContainer) ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE)
                .withConfiguration(new Configuration(Configuration.Mode.TEST)).build();
        container.getConfiguration().enableBigFilesSupport(0);

        String path = createLargeFile((container.getConfiguration().getMaxDataFileCachedInBytes()) + 100);
        try (FileInputStream stream = new FileInputStream(new File(path))) {
            container.addDataFile(stream, "fileName", "text/plain");
            signContainer(container);
            container.save("test-large-file.bdoc");
            File file = new File("test-large-file.bdoc");
            FileInputStream fileInputStream = new FileInputStream(file);
            open(fileInputStream, true);
            IOUtils.closeQuietly(fileInputStream);
        }
        assertEquals(1, container.getSignatures().size());
    }

    private String createLargeFile(long size) {
        String fileName = "test_large_file.bdoc";
        try {
            RandomAccessFile largeFile = new RandomAccessFile(fileName, "rw");
            largeFile.setLength(size);//todo create large file correctly
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileName;
    }

    @Test
    public void testGetDocumentType() throws Exception {
        createSignedBDocDocument("testGetDocumentType.bdoc");
        Container container = open("testGetDocumentType.bdoc");
        assertEquals(Container.DocumentType.BDOC, container.getDocumentType());
    }

    @Test
    public void testAddTwoFilesAsStream() throws Exception {
        Container container = createEmptyBDocContainer();
        ByteArrayInputStream stream = new ByteArrayInputStream("tere, tere".getBytes());
        container.addDataFile(stream, "test1.txt", "text/plain");
        container.addDataFile(stream, "test2.txt", "text/plain");
    }

    @Test
    public void testAddTwoFilesAsFileWithoutOCSP() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        container.addDataFile("testFiles/test.xml", "text/xml");
        signContainer(container, B_BES);
        container.save("testTwoFilesSigned.bdoc");

        container = open("testTwoFilesSigned.bdoc");
        assertEquals(2, container.getDataFiles().size());
    }

    @Test
    public void testGetFileNameAndID() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        container.addDataFile("testFiles/test.xml", "text/xml");
        signContainer(container);
        container.save("testTwoFilesSigned.bdoc");

        container = open("testTwoFilesSigned.bdoc");

        assertEquals("test.txt", container.getDataFile(0).getName());
        assertEquals("test.xml", container.getDataFile(1).getName());
        assertEquals("test.txt", container.getDataFile(0).getId());
        assertEquals("test.xml", container.getDataFile(1).getId());
    }

    @Test
    public void testAddTwoFilesAsFileWithOCSP() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        container.addDataFile("testFiles/test.xml", "text/xml");
        signContainer(container);
        container.save("testTwoFilesSigned.bdoc");

        container = open("testTwoFilesSigned.bdoc");
        assertEquals(2, container.getDataFiles().size());
    }

    @Test
    public void saveToStream() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile(new ByteArrayInputStream(new byte[] { 0x42 }), "test_bytes.txt", "text/plain");
        signContainer(container);
        File expectedContainerAsFile = new File("testSaveToStreamTest.bdoc");
        OutputStream out = new FileOutputStream(expectedContainerAsFile);
        container.save(out);
        assertTrue(Files.exists(expectedContainerAsFile.toPath()));

        Container containerToTest = open(expectedContainerAsFile.getName());
        assertArrayEquals(new byte[] { 0x42 }, containerToTest.getDataFiles().get(0).getBytes());
    }

    @Test
    public void saveExistingContainerToStream() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        signContainer(container);
        assertEquals(3, container.getSignatures().size());
        InputStream inputStream = container.saveAsStream();
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        IOUtils.copy(inputStream, outputStream);
        ByteArrayInputStream savedContainerStream = new ByteArrayInputStream(outputStream.toByteArray());
        container = open(savedContainerStream);
        assertEquals(3, container.getSignatures().size());
        assertEquals(1, container.getDataFiles().size());
    }

    @Test(expected = DigiDoc4JException.class)
    public void saveToStreamThrowsException() throws IOException {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        File expectedContainerAsFile = new File("testSaveToStreamTest.bdoc");
        OutputStream out = new FileOutputStream(expectedContainerAsFile);
        out.close();
        container.save(out);
    }

    @Test
    public void saveExistingContainer() throws Exception {
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        String containerPath = testFolder.newFile("test-container.asice").getPath();
        container.saveAsFile(containerPath);
        Container savedContainer = open(containerPath);
        assertTrue(savedContainer.validate().isValid());
        assertEquals(1, savedContainer.getDataFiles().size());
        assertEquals(2, savedContainer.getSignatures().size());
        ZipFile zip = new ZipFile(containerPath);
        assertNotNull(zip.getEntry("mimetype"));
        assertNotNull(zip.getEntry("test.txt"));
        assertNotNull(zip.getEntry("META-INF/manifest.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
    }

    @Test
    public void containerIsLT() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container, LT);
        container.saveAsFile("testLT.bdoc");
        container = open("testLT.bdoc");
        assertEquals(1, container.getSignatures().size());
        assertNotNull(container.getSignature(0).getOCSPCertificate());
    }

    @Test
    public void verifySignatureProfileIsTS() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container, LT);
        container.saveAsFile("testAddConfirmation.bdoc");

        assertEquals(1, container.getSignatures().size());
        assertNotNull(container.getSignature(0).getOCSPCertificate());
    }

    @Test(expected = DigiDoc4JException.class)
    public void signWithoutDataFile() throws Exception {
        Container container = createEmptyBDocContainer();
        signContainer(container);
    }

    @Test
    public void nonStandardMimeType() {
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).build();
        container.addDataFile("testFiles/test.txt", "text/newtype");
        signContainer(container);
        container.save("testNonStandardMimeType.bdoc");
        container = ContainerOpener.open("testNonStandardMimeType.bdoc");
        ValidationResult result = container.validate();
        assertEquals(0, result.getErrors().size());
        assertEquals("text/newtype", container.getDataFile(0).getMediaType());
    }

    @Test
    public void getVersion() {
        Container container = createEmptyBDocContainer();
        assertNull(container.getVersion());
    }

    @Test
    public void twoStepSigning() throws IOException {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        X509Certificate signerCert = getSigningCert();
        DataToSign dataToSign = SignatureBuilder.aSignature(container).withSigningCertificate(signerCert)
                .buildDataToSign();
        byte[] signatureValue = TestSigningHelper.sign(dataToSign.getDigestToSign(),
                dataToSign.getDigestAlgorithm());
        Signature signature = dataToSign.finalize(signatureValue);
        container.addSignature(signature);
        container.saveAsFile("test.bdoc");

        container = ContainerOpener.open("test.bdoc");

        ValidationResult validate = container.validate();
        assertTrue(validate.isValid());

        assertEquals(1, container.getSignatures().size());
        Signature resultSignature = container.getSignature(0);
        assertEquals("http://www.w3.org/2001/04/xmlenc#sha256", resultSignature.getSignatureMethod());
        assertThat(resultSignature.getSignerRoles(), is(empty()));
        assertNull(resultSignature.getCity());
        assertTrue(StringUtils.isNotBlank(resultSignature.getId()));

        assertNotNull(resultSignature.getOCSPCertificate());
        assertNotNull(resultSignature.getSigningCertificate());
        assertNotNull(resultSignature.getAdESSignature().length);
        assertEquals(LT, resultSignature.getProfile());
        assertNotNull(resultSignature.getTimeStampTokenCertificate());

        List<DataFile> dataFiles = container.getDataFiles();
        assertEquals(1, dataFiles.size());
        DataFile dataFile = dataFiles.get(0);
        assertEquals("test.txt", dataFile.getName());
        dataFile.calculateDigest(DigestAlgorithm.SHA384);
        assertEquals("text/plain", dataFile.getMediaType());
        assertEquals(new String(Files.readAllBytes(Paths.get("testFiles/test.txt"))),
                new String(dataFile.getBytes()));
        assertEquals(15, dataFile.getFileSize());
        assertEquals("test.txt", dataFile.getId());
    }

    @Test
    public void twoStepSigningVerifySignatureParameters() {
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).build();
        container.addDataFile("testFiles/test.txt", "text/plain");
        X509Certificate signerCert = getSigningCert();
        DataToSign dataToSign = SignatureBuilder.aSignature(container)
                .withSignatureDigestAlgorithm(DigestAlgorithm.SHA512).withSigningCertificate(signerCert)
                .withSignatureId("S99").withRoles("manager", "employee").withCity("city")
                .withStateOrProvince("state").withPostalCode("postalCode").withCountry("country").buildDataToSign();
        byte[] signatureValue = TestSigningHelper.sign(dataToSign.getDigestToSign(),
                dataToSign.getDigestAlgorithm());
        Signature signature = dataToSign.finalize(signatureValue);
        container.addSignature(signature);
        container.saveAsFile("test.bdoc");

        container = ContainerOpener.open("test.bdoc");
        assertEquals(1, container.getSignatures().size());
        Signature resultSignature = container.getSignature(0);
        assertEquals("http://www.w3.org/2001/04/xmlenc#sha512", resultSignature.getSignatureMethod());
        assertEquals("employee", resultSignature.getSignerRoles().get(1));
        assertEquals("city", resultSignature.getCity());
        assertEquals("S99", resultSignature.getId());
    }

    @Test
    public void testContainerCreationAsTSA() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        signContainer(container, LTA);

        assertNotNull(container.getSignature(0).getOCSPCertificate());
    }

    private Container createSignedBDocDocument(String fileName) {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        container.save(fileName);
        return container;
    }

    private class MockInputStream extends InputStream {

        public MockInputStream() {
        }

        @Override
        public int read() throws IOException {
            return 0;
        }

        @Override
        public int read(@SuppressWarnings("NullableProblems") byte b[], int off, int len) throws IOException {
            throw new IOException();
        }

        @Override
        public void close() throws IOException {
            throw new IOException();
        }

    }

    static X509Certificate getSignerCert(String certFile) {
        try {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            try (FileInputStream stream = new FileInputStream(certFile)) {
                keyStore.load(stream, "test".toCharArray());
            }
            return (X509Certificate) keyStore.getCertificate("1");
        } catch (Exception e) {
            throw new DigiDoc4JException("Loading signer cert failed");
        }
    }

    @Test
    public void testBDocTM() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        signContainer(container, LT_TM);
        assertTrue(container.validate().isValid());
    }

    @Test
    public void testBDocTS() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        signContainer(container, LT);
        assertTrue(container.validate().isValid());
    }

    @Test
    public void containerWithBESProfileHasNoValidationErrors() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        signContainer(container, B_BES);

        assertEquals(B_BES, container.getSignatures().get(0).getProfile());
        assertNull(container.getSignature(0).getOCSPCertificate());
        ValidationResult result = container.validate();
        assertFalse(result.isValid());
    }

    @Test
    public void signWithECCCertificate() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        Signature signature = SignatureBuilder.aSignature(container)
                .withSignatureToken(new PKCS12SignatureToken("testFiles/ec-digiid.p12", "inno".toCharArray()))
                .withEncryptionAlgorithm(EncryptionAlgorithm.ECDSA).invokeSigning();
        container.addSignature(signature);
        assertEquals(1, container.getSignatures().size());
        assertTrue(container.validate().isValid());
    }

    @Test
    public void zipFileComment() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        container.save("testZipFileComment.bdoc");

        String expectedComment = Helper.createBDocUserAgent(SignatureProfile.LT_TM);
        ZipFile zipFile = new ZipFile("testZipFileComment.bdoc");
        assertEquals(expectedComment, zipFile.getEntry("mimetype").getComment());
        assertEquals(expectedComment, zipFile.getEntry("META-INF/manifest.xml").getComment());
        assertEquals(expectedComment, zipFile.getEntry("META-INF/manifest.xml").getComment());
        assertEquals(expectedComment, zipFile.getEntry("META-INF/signatures0.xml").getComment());
        assertEquals(expectedComment, zipFile.getEntry("test.txt").getComment());
    }

    @Test
    public void signingMoreThanTwoFiles() throws Exception {
        Container container = createContainerWithFile(
                "testFiles/special-char-files/dds_dds_JRI   pev.txt", "text/plain");
        container.addDataFile("testFiles/special-char-files/dds_ ?.docx", "text/plain");
        container.addDataFile("testFiles/special-char-files/dds_pakitud.zip", "text/plain");
        container.addDataFile("testFiles/special-char-files/dds_SK.jpg", "text/plain");
        container.addDataFile("testFiles/special-char-files/dds_acrobat.pdf", "text/plain");

        signContainer(container);

        BDocSignature signature = (BDocSignature) container.getSignature(0);
        assertSignatureContains(signature, "dds_dds_JRI   pev.txt");
        assertSignatureContains(signature, "dds_ ?.docx");
        assertSignatureContains(signature, "dds_pakitud.zip");
        assertSignatureContains(signature, "dds_SK.jpg");
        assertSignatureContains(signature, "dds_acrobat.pdf");
    }

    @Test
    public void signatureFileNamesShouldBeInSequence() throws Exception {
        Container container = createContainerWithFile("testFiles/test.txt", "text/plain");
        signContainer(container);
        signContainer(container);
        signContainer(container);
        String containerPath = testFolder.newFile().getPath();
        container.saveAsFile(containerPath);
        ZipFile zip = new ZipFile(containerPath);
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures2.xml"));
    }

    @Test
    public void whenSigningExistingContainer_withTwoSignatures_shouldCreateSignatureFileName_signatures2()
            throws Exception {
        ZipFile zip = new ZipFile("testFiles/asics_testing_two_signatures.bdoc");
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
        Container container = open("testFiles/asics_testing_two_signatures.bdoc");
        signContainer(container);
        String containerPath = testFolder.newFile().getPath();
        container.saveAsFile(containerPath);
        zip = new ZipFile(containerPath);
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures2.xml"));
    }

    @Test
    public void whenSigningExistingContainer_with_signatures1_xml_shouldCreateSignatureFileName_signatures2()
            throws Exception {
        ZipFile zip = new ZipFile("testFiles/DigiDocService_spec_est.pdf-TM-j.bdoc");
        assertNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
        Container container = open("testFiles/DigiDocService_spec_est.pdf-TM-j.bdoc");
        signContainer(container);
        String containerPath = testFolder.newFile().getPath();
        container.saveAsFile(containerPath);
        zip = new ZipFile(containerPath);
        assertNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures2.xml"));
    }

    @Test
    public void whenSigningContainer_withSignatureNameContainingNonNumericCharacters_shouldCreateSignatureFileName_inSequence()
            throws Exception {
        ZipFile zip = new ZipFile(
                "testFiles/valid-containers/valid-bdoc-ts-signature-file-name-with-non-numeric-characters.asice");
        assertNotNull(zip.getEntry("META-INF/l77Tsignaturesn00B.xml"));
        assertNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNull(zip.getEntry("META-INF/signatures1.xml"));
        Container container = open(
                "testFiles/valid-containers/valid-bdoc-ts-signature-file-name-with-non-numeric-characters.asice");
        signContainer(container, SignatureProfile.LT);
        signContainer(container, SignatureProfile.LT);
        String containerPath = testFolder.newFile("test-container.asice").getPath();
        container.saveAsFile(containerPath);
        zip = new ZipFile(containerPath);
        assertNotNull(zip.getEntry("META-INF/l77Tsignaturesn00B.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures0.xml"));
        assertNotNull(zip.getEntry("META-INF/signatures1.xml"));
    }

    @Test(expected = DuplicateDataFileException.class)
    public void whenOpeningContainer_withTwoDataFilesWithSameName_andWithSingleReferenceInManifest_shouldThrowException() {
        Container container = ContainerBuilder.aContainer()
                .fromExistingFile("testFiles/KS-19_IB-3721_bdoc21-TM-2fil-samename-1sig3.bdoc")
                .withConfiguration(new Configuration(Configuration.Mode.TEST)).build();
    }

    @Test(expected = OCSPRequestFailedException.class)
    public void signingContainer_withFailedOcspResponse_shouldThrowException() throws Exception {
        Configuration configuration = new Configuration(Configuration.Mode.TEST);
        configuration.setSignOCSPRequests(true);
        configuration.setOCSPAccessCertificateFileName("testFiles/signout.p12");
        configuration.setOCSPAccessCertificatePassword("test".toCharArray());
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).withConfiguration(configuration)
                .withDataFile("testFiles/test.txt", "text/plain").build();

        signContainer(container, LT_TM);
    }

    /**
     * This is necessary for jDigidoc compatibility. This requirement not in BDoc specification
     */
    @Test
    public void bdocTM_OcspResponderCert_shouldContainResponderCertIdAttribute() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        BDocSignature signature = (BDocSignature) signContainer(container, LT_TM);
        XAdESSignature xAdESSignature = signature.getOrigin().getDssSignature();
        assertEquals(1, countOcspResponderCertificates(xAdESSignature));
    }

    @Test
    public void savingContainerWithoutSignatures_shouldNotThrowException() throws Exception {
        Container container = createEmptyBDocContainer();
        container.addDataFile("testFiles/test.txt", "text/plain");
        assertTrue(container.getSignatures().isEmpty());
        assertEquals(1, container.getDataFiles().size());
        assertTrue(container.validate().isValid());
        String containerPath = testFolder.newFile().getPath();
        container.saveAsFile(containerPath);
        Container savedContainer = open(containerPath);
        assertTrue(savedContainer.getSignatures().isEmpty());
        assertEquals(1, container.getDataFiles().size());
        byte[] expectedDataFileBytes = FileUtils.readFileToByteArray(new File("testFiles/test.txt"));
        byte[] actualDataFileBytes = savedContainer.getDataFiles().get(0).getBytes();
        Assert.assertArrayEquals(expectedDataFileBytes, actualDataFileBytes);
    }

    @Test
    public void openBDoc_withoutCAConfiguration_shouldNotThrowException() throws Exception {
        Configuration configuration = new Configuration(Configuration.Mode.TEST);
        configuration.loadConfiguration("testFiles/digidoc_test_conf_no_ca.yaml");
        ExistingBDocContainer container = new ExistingBDocContainer("testFiles/valid-containers/valid-bdoc-tm.bdoc",
                configuration);
        assertTrue(container.validate().isValid());
    }

    private void assertSignatureContains(BDocSignature signature, String name) {
        assertNotNull(findSignedFile(signature, name));
    }

    private DSSDocument findSignedFile(BDocSignature signature, String name) {
        List<DSSDocument> signedFiles = signature.getOrigin().getDssSignature().getDetachedContents();
        for (DSSDocument signedFile : signedFiles) {
            if (name.equals(signedFile.getName())) {
                return signedFile;
            }
        }
        return null;
    }

    private Container open(String path) {
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).fromExistingFile(path).build();
        return container;
    }

    private Container open(String path, Configuration configuration) {
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).withConfiguration(configuration)
                .fromExistingFile(path).build();
        return container;
    }

    private Container open(InputStream fileInputStream, boolean actAsBigFilesSupportEnabled) {
        return open(fileInputStream);
    }

    private Container open(InputStream fileInputStream) {
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).fromStream(fileInputStream).build();
        return container;
    }

    private Container createContainerWithFile(String path, String mimeType) {
        Container container = ContainerBuilder.aContainer(BDOC_CONTAINER_TYPE).withDataFile(path, mimeType).build();
        return container;
    }

    private int countOcspResponderCertificates(XAdESSignature xAdESSignature) {
        XPathQueryHolder xPathQueryHolder = xAdESSignature.getXPathQueryHolder();
        String xPath = xPathQueryHolder.XPATH_CERTIFICATE_VALUES;
        Element certificateValues = DSSXMLUtils.getElement(xAdESSignature.getSignatureElement(), xPath);
        return countResponderCertIdInsCertificateValues(certificateValues);
    }

    private int countResponderCertIdInsCertificateValues(Element certificateValues) {
        int responderCertCount = 0;
        NodeList certificates = certificateValues.getChildNodes();
        for (int i = 0; i < certificates.getLength(); i++) {
            Node cert = certificates.item(i);
            Node certId = cert.getAttributes().getNamedItem("Id");
            if (certId != null) {
                String idValue = certId.getNodeValue();
                if (StringUtils.containsIgnoreCase(idValue, "RESPONDER_CERT")) {
                    responderCertCount++;
                }
            }
        }
        return responderCertCount;
    }
}