/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE file at the root of the source * tree and available online at * * https://github.com/keeps/roda */ package org.roda.core.plugins; import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import org.apache.solr.client.solrj.SolrServerException; import org.roda.core.CorporaConstants; import org.roda.core.RodaCoreFactory; import org.roda.core.TestsHelper; import org.roda.core.common.iterables.CloseableIterable; import org.roda.core.common.monitor.TransferredResourcesScanner; import org.roda.core.data.common.RodaConstants; import org.roda.core.data.exceptions.AlreadyExistsException; import org.roda.core.data.exceptions.AuthorizationDeniedException; import org.roda.core.data.exceptions.GenericException; import org.roda.core.data.exceptions.InvalidParameterException; import org.roda.core.data.exceptions.IsStillUpdatingException; import org.roda.core.data.exceptions.NotFoundException; import org.roda.core.data.exceptions.RODAException; import org.roda.core.data.exceptions.RequestNotValidException; import org.roda.core.data.v2.common.OptionalWithCause; import org.roda.core.data.v2.index.IndexResult; import org.roda.core.data.v2.index.IndexRunnable; import org.roda.core.data.v2.index.filter.Filter; import org.roda.core.data.v2.index.filter.SimpleFilterParameter; import org.roda.core.data.v2.index.select.SelectedItemsAll; import org.roda.core.data.v2.index.select.SelectedItemsList; import org.roda.core.data.v2.index.select.SelectedItemsNone; import org.roda.core.data.v2.index.sublist.Sublist; import org.roda.core.data.v2.ip.AIP; import org.roda.core.data.v2.ip.File; import org.roda.core.data.v2.ip.IndexedAIP; import org.roda.core.data.v2.ip.Permissions; import org.roda.core.data.v2.ip.TransferredResource; import org.roda.core.data.v2.jobs.Job; import org.roda.core.data.v2.jobs.PluginType; import org.roda.core.index.IndexService; import org.roda.core.model.ModelService; import org.roda.core.plugins.plugins.base.FixAncestorsPlugin; import org.roda.core.plugins.plugins.ingest.EARKSIPToAIPPlugin; import org.roda.core.plugins.plugins.reindex.ReindexAIPPlugin; import org.roda.core.storage.fs.FSUtils; import org.roda.core.util.IdUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.collect.Iterables; import jersey.repackaged.com.google.common.collect.Lists; @Test(groups = {RodaConstants.TEST_GROUP_ALL, RodaConstants.TEST_GROUP_TRAVIS}) public class EARKSIPPluginsTest { private static final Logger LOGGER = LoggerFactory.getLogger(EARKSIPPluginsTest.class); private static final int CORPORA_FILES_COUNT = 4; private static final int CORPORA_FOLDERS_COUNT = 2; private static Path basePath; private static ModelService model; private static IndexService index; private static Path corporaPath; @BeforeClass public void setUp() throws Exception { basePath = TestsHelper.createBaseTempDir(getClass(), true); boolean deploySolr = true; boolean deployLdap = true; boolean deployFolderMonitor = true; boolean deployOrchestrator = true; boolean deployPluginManager = true; boolean deployDefaultResources = false; RodaCoreFactory.instantiateTest(deploySolr, deployLdap, deployFolderMonitor, deployOrchestrator, deployPluginManager, deployDefaultResources); model = RodaCoreFactory.getModelService(); index = RodaCoreFactory.getIndexService(); URL corporaURL = EARKSIPPluginsTest.class.getResource("/corpora"); corporaPath = Paths.get(corporaURL.toURI()); LOGGER.info("Running E-ARK SIP plugins tests under storage {}", basePath); } @AfterClass public void tearDown() throws Exception { RodaCoreFactory.shutdown(); FSUtils.deletePath(basePath); } @AfterMethod public void cleanUp() throws RODAException { index.execute(IndexedAIP.class, Filter.ALL, new ArrayList<>(), new IndexRunnable<IndexedAIP>() { @Override public void run(IndexedAIP item) throws GenericException, RequestNotValidException, AuthorizationDeniedException { try { model.deleteAIP(item.getId()); } catch (NotFoundException e) { // do nothing } } }); } private TransferredResource createCorpora() throws InterruptedException, IOException, NotFoundException, GenericException, RequestNotValidException, IsStillUpdatingException, AlreadyExistsException { TransferredResourcesScanner f = RodaCoreFactory.getTransferredResourcesScanner(); Path sip = corporaPath.resolve(CorporaConstants.SIP_FOLDER).resolve(CorporaConstants.EARK_SIP); f.createFile(null, CorporaConstants.EARK_SIP, Files.newInputStream(sip)); f.updateTransferredResources(Optional.empty(), true); index.commit(TransferredResource.class); return index.retrieve(TransferredResource.class, IdUtils.createUUID(CorporaConstants.EARK_SIP), new ArrayList<>()); } private AIP ingestCorpora() throws RequestNotValidException, NotFoundException, GenericException, AlreadyExistsException, AuthorizationDeniedException, InvalidParameterException, InterruptedException, IOException, SolrServerException, IsStillUpdatingException { String parentId = null; String aipType = RodaConstants.AIP_TYPE_MIXED; AIP root = model.createAIP(parentId, aipType, new Permissions(), RodaConstants.ADMIN); Map<String, String> parameters = new HashMap<>(); parameters.put(RodaConstants.PLUGIN_PARAMS_PARENT_ID, root.getId()); parameters.put(RodaConstants.PLUGIN_PARAMS_FORCE_PARENT_ID, "true"); TransferredResource transferredResource = createCorpora(); Assert.assertNotNull(transferredResource); Job job = TestsHelper.executeJob(EARKSIPToAIPPlugin.class, parameters, PluginType.SIP_TO_AIP, SelectedItemsList.create(TransferredResource.class, transferredResource.getUUID())); TestsHelper.getJobReports(index, job, true); index.commitAIPs(); IndexResult<IndexedAIP> find = index.find(IndexedAIP.class, new Filter(new SimpleFilterParameter(RodaConstants.AIP_PARENT_ID, root.getId())), null, new Sublist(0, 10), new ArrayList<>()); Assert.assertEquals(find.getTotalCount(), 1L); IndexedAIP indexedAIP = find.getResults().get(0); return model.retrieveAIP(indexedAIP.getId()); } @Test public void testIngestEARKSIP() throws IOException, InterruptedException, RODAException, SolrServerException { AIP aip = ingestCorpora(); Assert.assertEquals(aip.getRepresentations().size(), 1); CloseableIterable<OptionalWithCause<File>> allFiles = model.listFilesUnder(aip.getId(), aip.getRepresentations().get(0).getId(), true); List<File> reusableAllFiles = new ArrayList<>(); Iterables.addAll(reusableAllFiles, Lists.newArrayList(allFiles).stream().filter(f -> f.isPresent()).map(f -> f.get()).collect(Collectors.toList())); // All folders and files Assert.assertEquals(reusableAllFiles.size(), CORPORA_FOLDERS_COUNT + CORPORA_FILES_COUNT); } private List<String> createCorporaAncestors() throws InterruptedException, IOException, NotFoundException, GenericException, RequestNotValidException, IsStillUpdatingException, AlreadyExistsException { TransferredResourcesScanner f = RodaCoreFactory.getTransferredResourcesScanner(); List<String> resultIDs = new ArrayList<>(); Path sipFolder = corporaPath.resolve(CorporaConstants.SIP_FOLDER).resolve(CorporaConstants.ANCESTOR_SIP_FOLDER); Files.walk(sipFolder).forEach(filePath -> { if (FSUtils.isFile(filePath)) { try { TransferredResource tr = f.createFile(null, filePath.getFileName().toString(), Files.newInputStream(filePath)); resultIDs.add(tr.getUUID()); } catch (GenericException | RequestNotValidException | NotFoundException | AlreadyExistsException | IOException e) { LOGGER.error("Error creating file: " + filePath, e); } } }); f.updateTransferredResources(Optional.empty(), true); index.commit(TransferredResource.class); return resultIDs; } private void ingestCorporaAncestors() throws RequestNotValidException, NotFoundException, GenericException, AlreadyExistsException, AuthorizationDeniedException, InvalidParameterException, InterruptedException, IOException, SolrServerException, IsStillUpdatingException { String parentId = null; String aipType = RodaConstants.AIP_TYPE_MIXED; AIP root = model.createAIP(parentId, aipType, new Permissions(), RodaConstants.ADMIN); Map<String, String> parameters = new HashMap<>(); parameters.put(RodaConstants.PLUGIN_PARAMS_PARENT_ID, root.getId()); List<String> transferredResourcesIDs = createCorporaAncestors(); Assert.assertNotNull(transferredResourcesIDs); Job ingestJob = TestsHelper.executeJob(EARKSIPToAIPPlugin.class, parameters, PluginType.SIP_TO_AIP, SelectedItemsList.create(TransferredResource.class, transferredResourcesIDs)); TestsHelper.getJobReports(index, ingestJob, true); index.commitAIPs(); Map<String, String> fixAncestorsParameters = new HashMap<>(); fixAncestorsParameters.put(RodaConstants.PLUGIN_PARAMS_PARENT_ID, root.getId()); fixAncestorsParameters.put(RodaConstants.PLUGIN_PARAMS_OTHER_JOB_ID, ingestJob.getId()); Job fixAncestorsJob = TestsHelper.executeJob(FixAncestorsPlugin.class, fixAncestorsParameters, PluginType.MISC, new SelectedItemsNone<>()); TestsHelper.getJobReports(index, fixAncestorsJob, true); index.commitAIPs(); // 20161202 hsilva: somehow a reindex is needed for getting ancestors // correctly calculated TestsHelper.executeJob(ReindexAIPPlugin.class, fixAncestorsParameters, PluginType.MISC, SelectedItemsAll.create(AIP.class)); index.commitAIPs(); IndexResult<IndexedAIP> findAllAIP = index.find(IndexedAIP.class, Filter.ALL, null, new Sublist(0, 12), new ArrayList<>()); Assert.assertEquals(findAllAIP.getTotalCount(), 12L); IndexResult<IndexedAIP> findRootChildren = index.find(IndexedAIP.class, new Filter(new SimpleFilterParameter(RodaConstants.AIP_PARENT_ID, root.getId())), null, new Sublist(0, 2), new ArrayList<>()); Assert.assertEquals(findRootChildren.getTotalCount(), 2L); IndexResult<IndexedAIP> findSpecificAIP = index.find(IndexedAIP.class, new Filter(new SimpleFilterParameter(RodaConstants.INGEST_SIP_IDS, "026106")), null, new Sublist(0, 1), new ArrayList<>()); Assert.assertEquals(findSpecificAIP.getTotalCount(), 1L); IndexedAIP specificAIP = findSpecificAIP.getResults().get(0); Assert.assertEquals(specificAIP.getAncestors().size(), 4); } @Test public void testIngestAncestors() throws IOException, InterruptedException, RODAException, SolrServerException { ingestCorporaAncestors(); } }