/* *------------------------------------------------------------------------------ * Copyright (C) 2015-2016 University of Dundee. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * *------------------------------------------------------------------------------ */ package integration.gateway; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.Arrays; import java.util.concurrent.Future; import omero.RLong; import omero.api.IPixelsPrx; import omero.gateway.SecurityContext; import omero.gateway.exception.DSAccessException; import omero.gateway.exception.DSOutOfServiceException; import omero.model.IObject; import omero.model.PixelsType; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import omero.gateway.model.AnnotationData; import omero.gateway.model.BooleanAnnotationData; import omero.gateway.model.DataObject; import omero.gateway.model.DatasetData; import omero.gateway.model.DoubleAnnotationData; import omero.gateway.model.FileAnnotationData; import omero.gateway.model.ImageData; import omero.gateway.model.LongAnnotationData; import omero.gateway.model.MapAnnotationData; import omero.gateway.model.PlateData; import omero.gateway.model.ProjectData; import omero.gateway.model.RatingAnnotationData; import omero.gateway.model.ScreenData; import omero.gateway.model.TagAnnotationData; import omero.gateway.model.TermAnnotationData; import omero.gateway.model.TextualAnnotationData; import omero.gateway.model.XMLAnnotationData; /** * * @author Dominik Lindner      <a * href="mailto:d.lindner@dundee.ac.uk">d.lindner@dundee.ac.uk</a> * @since 5.1 */ public class DataManagerFacilityTest extends GatewayTest { /** Number of attachment files to generate */ final int nAttachmentFiles = 25; /** File size of an attachment */ final int fileSizeInMb = 25; /** * The amount a parallel attachment upload is allowed to be slower than a * single upload */ final double multipleAttachmentUploadThreshold = 1.5; ProjectData proj; DatasetData ds; ImageData img; File[] attachments; @Override @BeforeClass(alwaysRun = true) protected void setUp() throws Exception { super.setUp(); attachments = new File[nAttachmentFiles]; for (int i = 0; i < attachments.length; i++) { attachments[i] = createFile(fileSizeInMb); } } @AfterClass(alwaysRun = true) protected void teardown() { if (attachments != null) { for (int i = 0; i < attachments.length; i++) { attachments[i].delete(); } } } @Test public void testSaveAndReturnObject() throws DSOutOfServiceException, DSAccessException { ProjectData proj = new ProjectData(); proj.setName(UUID.randomUUID().toString()); this.proj = (ProjectData) datamanagerFacility.saveAndReturnObject( rootCtx, proj); Assert.assertTrue(this.proj.getId() > -1); DatasetData ds = new DatasetData(); ds.setName(UUID.randomUUID().toString()); Set<ProjectData> projs = new HashSet<ProjectData>(1); projs.add(this.proj); ds.setProjects(projs); this.ds = (DatasetData) datamanagerFacility.saveAndReturnObject( rootCtx, ds); Assert.assertTrue(this.ds.getId() > -1); } @Test(dependsOnMethods = { "testSaveAndReturnObject" }) public void testAddImage() throws Exception { long imgId = createImage(rootCtx); List<Long> ids = new ArrayList<Long>(1); ids.add(imgId); img = browseFacility.getImages(rootCtx, ids).iterator() .next(); Assert.assertNotNull(img); List<ImageData> l = new ArrayList<ImageData>(1); l.add(img); datamanagerFacility.addImagesToDataset(rootCtx, l, ds); ids.clear(); ids.add(ds.getId()); ds = browseFacility.getDatasets(rootCtx, ids).iterator().next(); Assert.assertEquals(ds.getImages().size(), 1); } @Test(dependsOnMethods = { "testAddImage" }) public void testUpdateObject() throws DSOutOfServiceException, DSAccessException { Timestamp timestamp = img.getUpdated(); String newName = UUID.randomUUID().toString(); img.setName(newName); datamanagerFacility.updateObject(rootCtx, img.asIObject(), null); img = browseFacility.getImage(rootCtx, img.getId()); Assert.assertEquals(img.getName(), newName); Assert.assertTrue(img.getUpdated().after(timestamp)); } @Test(dependsOnMethods = { "testUpdateObject" }) public void testDeleteObject() throws DSOutOfServiceException, DSAccessException { datamanagerFacility.deleteObject(rootCtx, img.asIObject()); List<Long> ids = new ArrayList<Long>(1); ids.add(img.getId()); Collection<ImageData> img = browseFacility.getImages(rootCtx, ids); Assert.assertTrue(img.isEmpty()); } @Test public void testAttachFile() throws Exception { File tmp = File.createTempFile("attachedFile", "file"); BufferedWriter out = new BufferedWriter(new FileWriter(tmp)); out.write("Just a test"); out.close(); DatasetData ds = new DatasetData(); ds.setName(UUID.randomUUID().toString()); ds = (DatasetData) datamanagerFacility.saveAndReturnObject(rootCtx, ds); Future<FileAnnotationData> cb = datamanagerFacility.attachFile(rootCtx, tmp, "text/plain", "test", null, ds); FileAnnotationData fa = cb.get(); Assert.assertTrue(fa.getFileName().startsWith("attachedFile")); tmp.delete(); } /** * Checks the performance of multiple parallel file attachment uploads. * Should not be slower than 1.5x of single file attachment uploads. * * @throws Exception */ @Test(dependsOnMethods = { "testSaveAndReturnObject" }) public void testPerformanceAttachFile() throws Exception { long start = System.currentTimeMillis(); Future<FileAnnotationData> f = datamanagerFacility.attachFile(rootCtx, attachments[0], "application/octet-stream", "test", null, ds); f.get(); long singleUploadDuration = System.currentTimeMillis() - start; start = System.currentTimeMillis(); Future<FileAnnotationData>[] futures = new Future[attachments.length]; for (int i = 0; i < attachments.length; i++) { futures[i] = datamanagerFacility.attachFile(rootCtx, attachments[i], "application/octet-stream", "test", null, ds); } boolean finished = false; while (!finished) { finished = true; for (int i = 0; i < futures.length; i++) { if (!futures[i].isDone()) { finished = false; break; } } if (finished) break; Thread.sleep(100); } long duration = System.currentTimeMillis() - start; long durationPerFile = duration / attachments.length; Assert.assertTrue(durationPerFile < singleUploadDuration * multipleAttachmentUploadThreshold, "Parallel file attachment upload is significantly slower than single upload (" + durationPerFile + " vs " + singleUploadDuration + " ms)"); } @Test public void testAttachAnnotation() throws Exception { Queue<DataObject> targets = new LinkedList<DataObject>(); DatasetData ds = new DatasetData(); ds.setName(UUID.randomUUID().toString()); targets.add(ds); ProjectData proj = new ProjectData(); proj.setName(UUID.randomUUID().toString()); targets.add(proj); ScreenData s = new ScreenData(); s.setName(UUID.randomUUID().toString()); targets.add(s); PlateData p = new PlateData(); p.setName(UUID.randomUUID().toString()); targets.add(p); DataObject dob = targets.poll(); while(dob.getId()<0) { dob = datamanagerFacility.saveAndReturnObject(rootCtx, dob); targets.add(dob); dob = targets.poll(); } targets.add(dob); long imgId = createImage(rootCtx); targets.add(browseFacility.getImage(rootCtx, imgId)); Collection<AnnotationData> annos = new ArrayList<AnnotationData>(); annos.add(new BooleanAnnotationData(true)); annos.add(new DoubleAnnotationData(5d)); annos.add(new LongAnnotationData(1)); annos.add(new MapAnnotationData()); annos.add(new RatingAnnotationData(3)); annos.add(new TagAnnotationData("test")); annos.add(new TermAnnotationData("test2")); annos.add(new TextualAnnotationData("test3")); annos.add(new XMLAnnotationData("<test4/>")); for(DataObject target : targets) { for(AnnotationData anno : annos) { anno = datamanagerFacility.attachAnnotation(rootCtx, anno, target); Assert.assertNotNull(anno); Assert.assertTrue(anno.getId() >= 0); } } } @Test public void testCreateDataset() throws DSOutOfServiceException, DSAccessException { //create dataset only DatasetData ds = new DatasetData(); ds.setName(UUID.randomUUID().toString()); ds = datamanagerFacility.createDataset(rootCtx, ds, null); Assert.assertNotNull(ds); //create dataset and project ds = new DatasetData(); ds.setName(UUID.randomUUID().toString()); ProjectData proj = new ProjectData(); proj.setName(UUID.randomUUID().toString()); ds = datamanagerFacility.createDataset(rootCtx, ds, proj); Assert.assertNotNull(ds); boolean found = false; Collection<ProjectData> projects = browseFacility.getProjects(rootCtx); for(ProjectData p : projects) if(p.getName().equals(proj.getName())) { found = true; proj = p; break; } Assert.assertTrue(found, "Project was not created!"); found = false; Collection<DatasetData> datasets = proj.getDatasets(); for(DatasetData d : datasets) if(d.getName().equals(ds.getName())) { found = true; break; } Assert.assertTrue(found, "Project and Dataset not successfully linked!"); // create dataset and add to existing project ds = new DatasetData(); ds.setName(UUID.randomUUID().toString()); ds = datamanagerFacility.createDataset(rootCtx, ds, proj); Assert.assertNotNull(ds); proj = browseFacility.getProjects(rootCtx, Arrays.asList(new Long[]{proj.getId()})).iterator().next(); found = false; datasets = proj.getDatasets(); for(DatasetData d : datasets) if(d.getName().equals(ds.getName())) { found = true; break; } Assert.assertTrue(found, "Project and Dataset not successfully linked!"); } private long createImage(SecurityContext ctx) throws Exception { IPixelsPrx svc = gw.getPixelsService(ctx); List<IObject> types = svc .getAllEnumerations(PixelsType.class.getName()); List<Integer> channels = new ArrayList<Integer>(); for (int i = 0; i < 3; i++) { channels.add(i); } RLong id = svc.createImage(10, 10, 10, 10, channels, (PixelsType) types.get(1), "test", ""); return id.getValue(); } private File createFile(int sizeInMb) { try { File tmp = File.createTempFile(System.currentTimeMillis()+"_attachedFile", "file"); FileOutputStream fos = new FileOutputStream(tmp); Random r = new Random(); byte[] data = new byte[1024*1024]; r.nextBytes(data); int size = 0; while(size < (sizeInMb*1024*1024)) { fos.write(data); size += data.length; } fos.close(); return tmp; } catch (IOException e) { } return null; } }