/* * Copyright 2010 Glencoe Software, Inc. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package integration.delete; import integration.AbstractServerTest; import java.io.File; import java.util.Arrays; import java.util.List; import ome.testing.ObjectFactory; import omero.ApiUsageException; import omero.RObject; import omero.RType; import omero.cmd.Delete2; import omero.cmd.SkipHead; import omero.cmd.graphs.ChildOption; import omero.gateway.util.Requests; import omero.model.AnnotationAnnotationLink; import omero.model.AnnotationAnnotationLinkI; import omero.model.Dataset; import omero.model.DatasetI; import omero.model.FileAnnotation; import omero.model.FileAnnotationI; import omero.model.IObject; import omero.model.ImageAnnotationLink; import omero.model.ImageAnnotationLinkI; import omero.model.ImageI; import omero.model.OriginalFile; import omero.model.OriginalFileI; import omero.model.Pixels; import omero.model.Plate; import omero.model.PlateI; import omero.model.Project; import omero.model.ProjectI; import omero.model.Screen; import omero.model.ScreenAnnotationLink; import omero.model.ScreenAnnotationLinkI; import omero.model.ScreenI; import omero.model.TagAnnotation; import omero.model.TagAnnotationI; import omero.model.TermAnnotation; import omero.model.TermAnnotationI; import omero.model.Well; import omero.model.WellI; import omero.model.WellSample; import omero.model.WellSampleI; import omero.sys.ParametersI; import omero.util.IceMapper; import org.springframework.util.ResourceUtils; import org.testng.Assert; import org.testng.annotations.Test; /** * Tests deletion of various elements of the graph. * These tests are resurrected from the previous DeleteITest class, now deleted. */ @Test(groups = { "integration", "delete" }) public class AdditionalDeleteTest extends AbstractServerTest { /** * Uses the /Image/Pixels/Channel delete specification to remove the * channels added during {@link #importImage()} and tests that the channels * are gone afterwards. */ public void testDeleteChannels() throws Throwable { // Create test data final long imageId = importImage(); List<?> ids = iQuery.projection( "select ch.id from Channel ch where ch.pixels.image.id = " + imageId, null); Assert.assertFalse(ids.isEmpty()); // Perform delete final SkipHead dc = Requests.skipHead("Image", imageId, "Channel", new Delete2()); callback(true, client, dc); // Check that data is gone ids = iQuery.projection( "select ch.id from Channel ch where ch.pixels.image.id = " + imageId, null); Assert.assertTrue(ids.isEmpty()); // Check that the image remains ids = iQuery.projection( "select id from Image where id = " + imageId, null); Assert.assertFalse(ids.isEmpty()); } /** * Uses the /Image/Pixels/RenderingDef delete specification to remove the * channels added during {@link #importImage()} and tests that the settings * are gone afterwards. */ public void testDeleteRenderingDef() throws Throwable { // Create test data final long imageId = importImage(); String check = "select rdef.id from RenderingDef rdef where rdef.pixels.image.id = " + imageId; List<?> ids = iQuery.projection(check, null); Assert.assertFalse(ids.isEmpty()); // Perform delete final SkipHead dc = Requests.skipHead("Image", imageId, "RenderingDef", new Delete2()); callback(true, client, dc); // Check that data is gone ids = iQuery.projection(check, null); Assert.assertTrue(ids.isEmpty()); // Check that the channels remain ids = iQuery.projection( "select ch.id from Channel ch where ch.pixels.image.id = " + imageId, null); Assert.assertFalse(ids.isEmpty()); // Check that the image remains ids = iQuery.projection( "select id from Image where id = " + imageId, null); Assert.assertFalse(ids.isEmpty()); } /** * Deletes the whole image. */ public void testImage() throws Exception { final long imageId = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); final Delete2 dc = Requests.delete("Image", imageId); callback(true, client, dc); // Check that data is gone List<?> l = iQuery.projection("select i.id from Image i where i.id = " + imageId, null); Assert.assertTrue(l.isEmpty()); } /** * Deletes the whole image using the subclass name {@link ImageI}. */ public void testImageI() throws Exception { final long imageId = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); final Delete2 dc = Requests.delete("ImageI", imageId); callback(true, client, dc); // Check that data is gone List<?> l = iQuery.projection("select i.id from Image i where i.id = " + imageId, null); Assert.assertTrue(l.isEmpty()); } /** * Uses the /Image delete specification to remove an Image and its * annotations simply linked annotation. This is the most basic case. */ @Test(groups = "ticket:2769") public void testImageWithAnnotations() throws Exception { // Create test data final long imageId = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); ImageAnnotationLink link = new ImageAnnotationLinkI(); link.link(new ImageI(imageId, false), new TagAnnotationI()); link = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link); final long annId = link.getChild().getId().getValue(); // Perform delete final Delete2 dc = Requests.delete("Image", imageId); callback(true, client, dc); // Check that the annotation is gone List<?> ids = iQuery.projection( "select ann.id from Annotation ann where ann.id = :id", new ParametersI().addId(annId)); Assert.assertTrue(ids.isEmpty()); } /** * Uses the /Image delete specification to remove an Image and attempts to * remove its annotations. If those annotations are multiply linked, * however, the attempted delete is rolled back (via a savepoint) * * As of 4.4.2, only a warning is returned for the annotationlink_child_annotation fk. */ @Test(groups = {"ticket:2769", "ticket:2780"}) public void testImageWithSharedAnnotations() throws Exception { // Create test data final long imageId1 = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); final long imageId2 = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); TagAnnotation tag = new TagAnnotationI(); tag = (TagAnnotation) iUpdate.saveAndReturnObject(tag); ImageAnnotationLink link1 = new ImageAnnotationLinkI(); link1.link(new ImageI(imageId1, false), tag); link1 = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link1); ImageAnnotationLink link2 = new ImageAnnotationLinkI(); link2.link(new ImageI(imageId2, false), tag); link2 = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link2); // Perform delete final Delete2 dc = Requests.delete("Image", imageId1); callback(true, client, dc); // Check that data is gone List<?> ids = iQuery.projection( "select img.id from Image img where img.id = :id", new ParametersI().addId(imageId1)); Assert.assertTrue(ids.isEmpty()); // Check that the annotation remains ids = iQuery.projection( "select ann.id from Annotation ann where ann.id = :id", new ParametersI().addId(tag.getId().getValue())); Assert.assertFalse(ids.isEmpty()); } /** * Deletes a project and all its datasets though no images are created. */ public void testProjectNoImage() throws Exception { // Create test data Project p = new ProjectI(); p.setName(omero.rtypes.rstring("name")); Dataset d = new DatasetI(); d.setName(p.getName()); p.linkDataset(d); p = (Project) iUpdate.saveAndReturnObject(p); final long id = p.getId().getValue(); // Do Delete final Delete2 dc = Requests.delete("Project", id); callback(true, client, dc); // Check that data is gone List<?> ids; ids = iQuery.projection("select p.id from Project p where p.id = " + id, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select d.id from Dataset d where d.id = " + id, null); Assert.assertTrue(ids.isEmpty()); } /** * Deletes a project and all its datasets which have images. */ public void testProject() throws Exception { final long iid = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); // Create test data Project p = new ProjectI(); p.setName(omero.rtypes.rstring("name")); Dataset d = new DatasetI(); d.setName(p.getName()); p.linkDataset(d); d.linkImage(new ImageI(iid, false)); p = (Project) iUpdate.saveAndReturnObject(p); d = p.linkedDatasetList().get(0); final long pid = p.getId().getValue(); final long did = d.getId().getValue(); // Do Delete final Delete2 dc = Requests.delete("Project", pid); callback(true, client, dc); // Check that data is gone List<?> ids; ids = iQuery.projection("select p.id from Project p where p.id = " + pid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select d.id from Dataset d where d.id = " + did, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select i.id from Image i where i.id = " + iid, null); Assert.assertTrue(ids.isEmpty()); } /** * Deletes a very simple plate to ensure that the "/Image+WS" spec is * working. */ public void testSimplePlate() throws Exception { final long iid = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); // Create test data Plate p = createPlate(iid); p = (Plate) iUpdate.saveAndReturnObject(p); final long pid = p.getId().getValue(); Well w = p.copyWells().get(0); final long wid = w.getId().getValue(); WellSample ws = w.getWellSample(0); final long wsid = ws.getId().getValue(); // Do Delete final Delete2 dc = Requests.delete("Plate", pid); callback(true, client, dc); // Check that data is gone List<?> ids; ids = iQuery.projection("select p.id from Plate p where p.id = " + pid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select w.id from Well w where w.id = " + wid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select ws.id from WellSample ws where ws.id = " + wsid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select i.id from Image i where i.id = " + iid, null); Assert.assertTrue(ids.isEmpty()); } /** * Deletes a very simple image/annotation graph, to guarantee that the * basic options are working */ public void testSimpleImageWithAnnotation() throws Exception { final long iid = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); // Create test data ImageAnnotationLink link = new ImageAnnotationLinkI(); link.link(new ImageI(iid, false), new TagAnnotationI()); link = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link); final long lid = link.getId().getValue(); final long aid = link.getChild().getId().getValue(); // Do Delete final Delete2 dc = Requests.delete("Image", iid); callback(true, client, dc); // Check that data is gone List<?> ids; ids = iQuery.projection("select i.id from Image i where i.id = " + iid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select l.id from ImageAnnotationLink l where l.id = " + lid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select a.id from Annotation a where a.id = " + aid, null); Assert.assertTrue(ids.isEmpty()); } /** * Attempts to use the ILink type for deleting all links which point * at an annotation. */ public void testDeleteAllAnnotationLinks() throws Exception { // Create test data AnnotationAnnotationLink link = new AnnotationAnnotationLinkI(); link.link(new TagAnnotationI(), new TagAnnotationI()); link = (AnnotationAnnotationLink) iUpdate.saveAndReturnObject(link); final long lid = link.getId().getValue(); final long pid = link.getParent().getId().getValue(); final long cid = link.getChild().getId().getValue(); // Do Delete final Delete2 dc = Requests.delete("Annotation", cid); callback(true, client, dc); // Make sure the parent annotation still exists, but both the annotation // link and the annotation that was linked to (the child) are gone. List<?> ids; ids = iQuery.projection("select p.id from Annotation p where p.id = " + pid, null); Assert.assertFalse(ids.isEmpty()); ids = iQuery.projection("select l.id from AnnotationAnnotationLink l where l.id = " + lid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select c.id from Annotation c where c.id = " + cid, null); Assert.assertTrue(ids.isEmpty()); } /** * Uses {@link SkipHead} to prevent a delete from happening. */ public void testKeepImageAnnotation() throws Exception { // Create test data final long iid = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); ImageAnnotationLink link = new ImageAnnotationLinkI(); link.link(new ImageI(iid, false), new TagAnnotationI()); link = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link); final long lid = link.getId().getValue(); final long pid = link.getParent().getId().getValue(); final long cid = link.getChild().getId().getValue(); // Do Delete final ChildOption option = Requests.option(null, "TagAnnotation"); final Delete2 dc = Requests.delete("Image", pid, option); callback(true, client, dc); // Make sure the image is deleted but the annotation remains. List<?> ids; ids = iQuery.projection("select p.id from Image p where p.id = " + pid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select l.id from ImageAnnotationLink l where l.id = " + lid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select c.id from Annotation c where c.id = " + cid, null); Assert.assertFalse(ids.isEmpty()); } /** * Tests overriding the {@link ChildOption#excludeType} setting by a hard-code * value to the graph request factory. These are well-known "unshared" annotations, * that should be deleted, regardless of the setting. */ public void testDontKeepImageAnnotationIfUnsharedNS() throws Exception { // Create test data FileAnnotation file = new FileAnnotationI(); file.setNs(omero.rtypes.rstring("openmicroscopy.org/omero/import/companionFile")); final long iid = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); ImageAnnotationLink link = new ImageAnnotationLinkI(); link.link(new ImageI(iid, false), file); link = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link); final long lid = link.getId().getValue(); final long pid = link.getParent().getId().getValue(); final long cid = link.getChild().getId().getValue(); // Do Delete final ChildOption option = Requests.option(null, "FileAnnotation"); final Delete2 dc = Requests.delete("Image", pid, option); callback(true, client, dc); // Make sure the image and annotation are deleted. List<?> ids; ids = iQuery.projection("select p.id from Image p where p.id = " + pid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select l.id from ImageAnnotationLink l where l.id = " + lid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select c.id from Annotation c where c.id = " + cid, null); Assert.assertTrue(ids.isEmpty()); } /** * Tests overriding the {@link ChildOption#excludeType} setting by setting * a namespace which should always be deleted (an "unshared" annotation). */ public void testDontKeepImageAnnotationIfRequestedNS() throws Exception { // Create test data FileAnnotation file = new FileAnnotationI(); file.setNs(omero.rtypes.rstring("keepme")); final long iid = iUpdate.saveAndReturnObject(mmFactory.createImage()).getId().getValue(); ImageAnnotationLink link = new ImageAnnotationLinkI(); link.link(new ImageI(iid, false), file); link = (ImageAnnotationLink) iUpdate.saveAndReturnObject(link); long lid = link.getId().getValue(); long pid = link.getParent().getId().getValue(); long cid = link.getChild().getId().getValue(); // Do Delete final ChildOption option = Requests.option(null, "FileAnnotation", null, "keepme"); final Delete2 dc = Requests.delete("Image", pid, option); callback(true, client, dc); // Make sure the image and annotation are deleted. List<?> ids; ids = iQuery.projection("select p.id from Image p where p.id = " + pid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select l.id from ImageAnnotationLink l where l.id = " + lid, null); Assert.assertTrue(ids.isEmpty()); ids = iQuery.projection("select c.id from Annotation c where c.id = " + cid, null); Assert.assertTrue(ids.isEmpty()); } /** * This method is copied from DeleteServiceTest to reproduce an issue * in which KEEP;excludes= was not being taken into account. */ @Test public void testDeleteObjectWithAnnotationWithoutNS() throws Exception { Screen obj = new ScreenI(); obj.setName(omero.rtypes.rstring("testDelete")); obj = (Screen) iUpdate.saveAndReturnObject(obj); String type = "Screen"; final long id = obj.getId().getValue(); List<Long> annotationIds = createNonSharableAnnotation(obj, null); List<Long> annotationIdsNS = createNonSharableAnnotation(obj, "TEST"); final ChildOption option = Requests.option(null, "Annotation", null, "TEST"); final Delete2 dc = Requests.delete(type, id, option); callback(true, client, dc); ParametersI param = new ParametersI(); param.addId(obj.getId().getValue()); String hql = "select s from Screen s where id = :id"; Assert.assertTrue(iQuery.projection(hql, param).isEmpty()); param = new ParametersI(); param.addIds(annotationIds); Assert.assertFalse(annotationIds.isEmpty()); hql = "select id from Annotation where id in (:ids)"; List<?> ids = iQuery.projection(hql, param); Assert.assertEquals(annotationIds.size(), ids.size()); param = new ParametersI(); param.addIds(annotationIdsNS); Assert.assertFalse(annotationIdsNS.isEmpty()); ids = iQuery.projection(hql, param); Assert.assertTrue(ids.isEmpty()); } private List<Long> createNonSharableAnnotation(Screen obj, String ns) throws Exception { TermAnnotation ta = new TermAnnotationI(); if (ns != null) { ta.setNs(omero.rtypes.rstring(ns)); } ScreenAnnotationLink link = new ScreenAnnotationLinkI(); link.link((Screen) obj.proxy(), ta); link = (ScreenAnnotationLink) iUpdate.saveAndReturnObject(link); return Arrays.asList(link.getChild().getId().getValue()); } // original files // @Test(groups = "ticket:7314") public void testOriginalFileAnnotation() throws Exception { final FileAnnotationI ann = mockAnnotation(); final OriginalFile file = ann.getFile(); final long id = file.getId().getValue(); // Do Delete final Delete2 dc = Requests.delete("OriginalFile", id); callback(true, client, dc); assertGone(file); assertGone(ann); } /** * This is not possible without nulling the FileAnnotation.file field. * So, the FileAnnotation must be deleted if its file is. */ @Test(groups = "ticket:7314") public void testOriginalFileAnnotationWithKeep() throws Exception { final FileAnnotationI ann = mockAnnotation(); final OriginalFile file = ann.getFile(); final long id = file.getId().getValue(); // Do Delete final ChildOption option = Requests.option(null, "Annotation"); final Delete2 dc = Requests.delete("OriginalFile", id, option); callback(true, client, dc); assertGone(ann); assertGone(file); } private FileAnnotationI mockAnnotation() throws Exception { OriginalFile file = (OriginalFileI) new IceMapper().map(ObjectFactory.createFile()); FileAnnotationI ann = new FileAnnotationI(); ann.setFile(file); ann = (FileAnnotationI) iUpdate.saveAndReturnObject(ann); return ann; } private void assertGone(IObject obj) throws Exception { final IObject test = assertLoadObject(obj); Assert.assertNull(test); } private IObject assertLoadObject(IObject obj) throws ApiUsageException, Exception { final String kls = IceMapper.omeroClass(obj.getClass().getName(), true).getSimpleName(); final List<List<RType>> objects = iQuery.projection( "select x from " + kls + " x where x.id = " + obj.getId().getValue(), null); if (objects.isEmpty()) { return null; } else { final RObject object = (RObject) objects.get(0).get(0); return object.getValue(); } } // // Helpers // private long importImage() throws Throwable { final File imageFile = ResourceUtils.getFile("classpath:tinyTest.d3d.dv"); final Pixels pixels = importFile(imageFile, "dv").get(0); return pixels.getImage().getId().getValue(); } private Plate createPlate(long imageId) throws Exception { Plate p = new PlateI(); p.setRows(omero.rtypes.rint(1)); p.setColumns(omero.rtypes.rint(1)); p.setName(omero.rtypes.rstring("plate")); // now make wells Well well = new WellI(); well.setRow(omero.rtypes.rint(0)); well.setColumn(omero.rtypes.rint(0)); WellSample sample = new WellSampleI(); sample.setImage(new ImageI(imageId, false)); well.addWellSample(sample); p.addWell(well); return p; } }