/******************************************************************************* * Copyright French Prime minister Office/SGMAP/DINSIC/Vitam Program (2015-2019) * * contact.vitam@culture.gouv.fr * * This software is a computer program whose purpose is to implement a digital archiving back-office system managing * high volumetry securely and efficiently. * * This software is governed by the CeCILL 2.1 license under French law and abiding by the rules of distribution of free * software. You can use, modify and/ or redistribute the software under the terms of the CeCILL 2.1 license as * circulated by CEA, CNRS and INRIA at the following URL "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, modify and redistribute granted by the license, * users are provided only with a limited warranty and the software's author, the holder of the economic rights, and the * successive licensors have only limited liability. * * In this respect, the user's attention is drawn to the risks associated with loading, using, modifying and/or * developing or reproducing the software by the user in light of its specific status of free software, that may mean * that it is complicated to manipulate, and that also therefore means that it is reserved for developers and * experienced professionals having in-depth computer knowledge. Users are therefore encouraged to load and test the * software's suitability as regards their requirements in conditions enabling the security of their systems and/or data * to be ensured and, more generally, to use and operate it in the same conditions as regards security. * * The fact that you are presently reading this means that you have had knowledge of the CeCILL 2.1 license and that you * accept its terms. *******************************************************************************/ package fr.gouv.vitam.storage.offers.common.core; 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.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; import javax.ws.rs.core.Response; import org.apache.commons.io.IOUtils; import org.junit.After; import org.junit.Ignore; import org.junit.Test; import com.fasterxml.jackson.databind.JsonNode; import fr.gouv.vitam.common.PropertiesUtils; import fr.gouv.vitam.common.VitamConfiguration; import fr.gouv.vitam.common.digest.Digest; import fr.gouv.vitam.common.guid.GUIDFactory; import fr.gouv.vitam.common.junit.FakeInputStream; import fr.gouv.vitam.common.server.application.junit.AsyncResponseJunitTest; import fr.gouv.vitam.common.storage.StorageConfiguration; import fr.gouv.vitam.storage.engine.common.model.DataCategory; import fr.gouv.vitam.storage.engine.common.model.ObjectInit; import fr.gouv.vitam.workspace.api.exception.ContentAddressableStorageException; import fr.gouv.vitam.workspace.api.exception.ContentAddressableStorageNotFoundException; /** * Default offer service test implementation */ public class DefaultOfferServiceTest { private static final String CONTAINER_PATH = "container"; private static final DataCategory OBJECT_TYPE = DataCategory.OBJECT; private static final String FOLDER_PATH = "folder"; private static final String OBJECT_ID = GUIDFactory.newObjectGUID(0).getId(); private static final String OBJECT_ID_2 = GUIDFactory.newObjectGUID(0).getId(); private static final String OBJECT_ID_3 = GUIDFactory.newObjectGUID(0).getId(); private static final String OBJECT_ID_DELETE = GUIDFactory.newObjectGUID(0).getId(); private static final String DEFAULT_STORAGE_CONF = "default-storage.conf"; private static final String ARCHIVE_FILE_TXT = "archivefile.txt"; private static final String OBJECT_ID_2_CONTENT = "Vitam Test Content"; @After public void deleteFiles() throws Exception { final StorageConfiguration conf = PropertiesUtils.readYaml(PropertiesUtils.findFile(DEFAULT_STORAGE_CONF), StorageConfiguration.class); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_TYPE.getFolder(), OBJECT_ID)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_TYPE.getFolder(), OBJECT_ID_2)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_TYPE.getFolder(), OBJECT_ID_3)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_TYPE.getFolder(), OBJECT_ID_DELETE)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_TYPE.getFolder())); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, FOLDER_PATH)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_ID)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_ID_2)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_ID_3)); Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, OBJECT_ID_DELETE)); for (int i = 0; i < 150; i++) { Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH, "object_" + i)); } Files.deleteIfExists(Paths.get(conf.getStoragePath(), CONTAINER_PATH)); } @Test public void initOKTest() { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); } @Test(expected = ContentAddressableStorageException.class) public void createObjectTestKO() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); offerService.createObject("fakeContainer", OBJECT_ID, null, true); } @Test public void createContainerTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); offerService.initCreateObject(CONTAINER_PATH, getObjectInit(false), OBJECT_ID); // check final StorageConfiguration conf = PropertiesUtils.readYaml(PropertiesUtils.findFile(DEFAULT_STORAGE_CONF), StorageConfiguration.class); final File container = new File(conf.getStoragePath() + CONTAINER_PATH); assertTrue(container.exists()); assertTrue(container.isDirectory()); offerService.initCreateObject(CONTAINER_PATH, getObjectInit(false), OBJECT_ID); } @Test public void countObjectsTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); offerService.initCreateObject(CONTAINER_PATH, getObjectInit(false), OBJECT_ID_2); final InputStream streamToStore = IOUtils.toInputStream(OBJECT_ID_2_CONTENT); offerService.createObject(CONTAINER_PATH, OBJECT_ID_2, streamToStore, true); JsonNode result = offerService.countObjects(CONTAINER_PATH); assertEquals(1, result.get("objectNumber").longValue()); } @Test public void createFolderTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); // container (init) offerService.initCreateObject(CONTAINER_PATH, getObjectInit(true), GUIDFactory.newObjectGUID(0).getId()); // check final StorageConfiguration conf = PropertiesUtils.readYaml(PropertiesUtils.findFile(DEFAULT_STORAGE_CONF), StorageConfiguration.class); final File container = new File(conf.getStoragePath() + CONTAINER_PATH); assertTrue(container.exists()); assertTrue(container.isDirectory()); // folder offerService.createFolder(CONTAINER_PATH, FOLDER_PATH); // check final File folder = new File(container.getAbsolutePath() + "/" + FOLDER_PATH); assertTrue(folder.exists()); assertTrue(folder.isDirectory()); } @Test public void createObjectTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); // container ObjectInit objectInit = getObjectInit(false); objectInit = offerService.initCreateObject(CONTAINER_PATH, objectInit, OBJECT_ID); // check assertEquals(OBJECT_ID, objectInit.getId()); final StorageConfiguration conf = PropertiesUtils.readYaml(PropertiesUtils.findFile(DEFAULT_STORAGE_CONF), StorageConfiguration.class); final File container = new File(conf.getStoragePath() + CONTAINER_PATH); assertTrue(container.exists()); assertTrue(container.isDirectory()); String computedDigest = null; // object try (FileInputStream in = new FileInputStream(PropertiesUtils.findFile(ARCHIVE_FILE_TXT))) { assertNotNull(in); computedDigest = offerService.createObject(CONTAINER_PATH, objectInit.getId(), in, true); } // check final File testFile = PropertiesUtils.findFile(ARCHIVE_FILE_TXT); final File offerFile = new File(CONTAINER_PATH + "/" + OBJECT_ID); assertTrue(com.google.common.io.Files.equal(testFile, offerFile)); final Digest digest = Digest.digest(testFile, VitamConfiguration.getDefaultDigestType()); assertEquals(computedDigest, digest.toString()); assertEquals(offerService.getObjectDigest(CONTAINER_PATH, OBJECT_ID, VitamConfiguration.getDefaultDigestType()), digest.toString()); assertTrue(offerService.isObjectExist(CONTAINER_PATH, OBJECT_ID)); } // TODO activate when chunk mode is done in {@see DefaultOfferService} // method createObject @Test @Ignore public void createObjectChunkTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); // container ObjectInit objectInit = getObjectInit(false); objectInit = offerService.initCreateObject(CONTAINER_PATH, objectInit, OBJECT_ID); // check assertEquals(OBJECT_ID, objectInit.getId()); final StorageConfiguration conf = PropertiesUtils.readYaml(PropertiesUtils.findFile(DEFAULT_STORAGE_CONF), StorageConfiguration.class); final File container = new File(conf.getStoragePath() + CONTAINER_PATH); assertTrue(container.exists()); assertTrue(container.isDirectory()); String computedDigest = null; // object try (FileInputStream in = new FileInputStream(PropertiesUtils.findFile(ARCHIVE_FILE_TXT))) { assertNotNull(in); final FileChannel fc = in.getChannel(); final ByteBuffer bb = ByteBuffer.allocate(1024); byte[] bytes; int read = fc.read(bb); while (read >= 0) { bb.flip(); if (fc.position() == fc.size()) { bytes = new byte[read]; bb.get(bytes, 0, read); computedDigest = offerService.createObject(CONTAINER_PATH, objectInit.getId(), new ByteArrayInputStream(bytes), true); } else { bytes = bb.array(); computedDigest = offerService.createObject(CONTAINER_PATH, objectInit.getId(), new ByteArrayInputStream(bytes.clone()), false); assertEquals(computedDigest, Digest.digest(new ByteArrayInputStream(bytes.clone()), VitamConfiguration.getDefaultDigestType()) .toString()); } bb.clear(); read = fc.read(bb); } } // check final File testFile = PropertiesUtils.findFile(ARCHIVE_FILE_TXT); final File offerFile = new File(CONTAINER_PATH + "/" + objectInit.getType().getFolder() + "/" + OBJECT_ID); assertTrue(com.google.common.io.Files.equal(testFile, offerFile)); final Digest digest = Digest.digest(testFile, VitamConfiguration.getDefaultDigestType()); assertEquals(computedDigest, digest.toString()); assertEquals(offerService.getObjectDigest(CONTAINER_PATH, objectInit.getType().getFolder() + "/" + OBJECT_ID, VitamConfiguration.getDefaultDigestType()), digest.toString()); assertTrue(offerService.isObjectExist(CONTAINER_PATH, objectInit.getType().getFolder() + "/" + OBJECT_ID)); } @Test public void getObjectTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); offerService.initCreateObject(CONTAINER_PATH, getObjectInit(false), OBJECT_ID_2); final InputStream streamToStore = IOUtils.toInputStream(OBJECT_ID_2_CONTENT); offerService.createObject(CONTAINER_PATH, OBJECT_ID_2, streamToStore, true); final Response response = offerService.getObject(CONTAINER_PATH, OBJECT_ID_2, new AsyncResponseJunitTest()); assertNotNull(response); } private ObjectInit getObjectInit(boolean algo) throws IOException { final File file = PropertiesUtils.findFile(ARCHIVE_FILE_TXT); final ObjectInit objectInit = new ObjectInit(); if (algo) { objectInit.setDigestAlgorithm(VitamConfiguration.getDefaultDigestType()); } objectInit.setSize(file.length()); objectInit.setType(OBJECT_TYPE); return objectInit; } @Test public void getCapacityOk() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); // container ObjectInit objectInit = getObjectInit(false); objectInit = offerService.initCreateObject(CONTAINER_PATH, objectInit, OBJECT_ID); // check assertEquals(OBJECT_ID, objectInit.getId()); final StorageConfiguration conf = PropertiesUtils.readYaml(PropertiesUtils.findFile(DEFAULT_STORAGE_CONF), StorageConfiguration.class); final File container = new File(conf.getStoragePath() + CONTAINER_PATH); assertTrue(container.exists()); assertTrue(container.isDirectory()); final JsonNode jsonNode = offerService.getCapacity(CONTAINER_PATH); assertNotNull(jsonNode); assertNotNull(jsonNode.get("usableSpace")); assertNotNull(jsonNode.get("usedSpace")); } @Test public void checkObjectTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); final ObjectInit objectInit = getObjectInit(true); offerService.initCreateObject(CONTAINER_PATH, objectInit, OBJECT_ID_3); final InputStream streamToStore = IOUtils.toInputStream(OBJECT_ID_2_CONTENT); String digest = offerService.createObject(CONTAINER_PATH, OBJECT_ID_3, streamToStore, true); assertTrue(offerService.checkObject(CONTAINER_PATH, OBJECT_ID_3, digest, VitamConfiguration.getDefaultDigestType())); } public void deleteObjectTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); offerService.initCreateObject(CONTAINER_PATH, getObjectInit(false), OBJECT_ID_DELETE); // creation of an object final InputStream streamToStore = IOUtils.toInputStream(OBJECT_ID_2_CONTENT); String digest = offerService.createObject(CONTAINER_PATH, OBJECT_ID_DELETE, streamToStore, true); // check if the object has been created final Response response = offerService.getObject(CONTAINER_PATH, OBJECT_ID_DELETE, new AsyncResponseJunitTest()); assertNotNull(response); try { // check that if we try to delete an object with a wrong digest, we // get a not found exception offerService.deleteObject(CONTAINER_PATH, OBJECT_ID_DELETE, "fakeDigest", VitamConfiguration.getDefaultDigestType()); fail("Should raized an exception"); } catch (ContentAddressableStorageNotFoundException exc) { } try { // check that if we try to delete an object with the wrong digest // algorithm, we get a not found exception offerService.deleteObject(CONTAINER_PATH, OBJECT_ID_DELETE, digest, VitamConfiguration.getSecurityDigestType()); fail("Should raized an exception"); } catch (ContentAddressableStorageNotFoundException exc) { } // check that if we try to delete an object with the correct digest + // algorithm, it succeeds offerService.deleteObject(CONTAINER_PATH, OBJECT_ID_DELETE, digest, VitamConfiguration.getDefaultDigestType()); try { // check that the object has been deleted offerService.getObject(CONTAINER_PATH, OBJECT_ID_DELETE, new AsyncResponseJunitTest()); fail("Should raized an exception"); } catch (ContentAddressableStorageNotFoundException exc) { } } @Test(expected = ContentAddressableStorageNotFoundException.class) public void listCreateCursorNoContainerTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); offerService.createCursor(CONTAINER_PATH); } @Test public void listCreateCursorTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); final ObjectInit objectInit = getObjectInit(false); offerService.initCreateObject(CONTAINER_PATH, objectInit, "fake"); String cursorId = offerService.createCursor(CONTAINER_PATH); assertNotNull(cursorId); List<JsonNode> list = offerService.next(CONTAINER_PATH, cursorId); assertNotNull(list); assertTrue(list.isEmpty()); list = offerService.next(CONTAINER_PATH, cursorId); // TODO manage with exception assertNull(list); } @Test public void listCursorTest() throws Exception { final DefaultOfferService offerService = DefaultOfferServiceImpl.getInstance(); assertNotNull(offerService); final ObjectInit objectInit = getObjectInit(false); for (int i = 0; i < 150; i++) { offerService.initCreateObject(CONTAINER_PATH, objectInit, "object_" + i); offerService.createObject(CONTAINER_PATH, "object_" + i, new FakeInputStream(50, false), true); } String cursorId = offerService.createCursor(CONTAINER_PATH); assertNotNull(cursorId); boolean hasNext = offerService.hasNext(CONTAINER_PATH, cursorId); assertTrue(hasNext); List<JsonNode> list = offerService.next(CONTAINER_PATH, cursorId); assertNotNull(list); assertEquals(100, list.size()); hasNext = offerService.hasNext(CONTAINER_PATH, cursorId); assertTrue(hasNext); list = offerService.next(CONTAINER_PATH, cursorId); assertNotNull(list); assertEquals(50, list.size()); hasNext = offerService.hasNext(CONTAINER_PATH, cursorId); assertFalse(hasNext); list = offerService.next(CONTAINER_PATH, cursorId); // TODO manage with exception assertNull(list); } }