/*
* Copyright 2011 Glencoe Software, Inc. All rights reserved.
* Use is subject to license terms supplied in LICENSE.txt
*/
package ome.services.blitz.test;
import static omero.rtypes.rstring;
import static omero.rtypes.rtime;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import omero.RType;
import omero.ServerError;
import omero.cmd.Chown;
import omero.cmd.HandleI;
import omero.cmd.IRequest;
import omero.cmd._HandleTie;
import omero.cmd.State;
import omero.cmd.graphs.ChownFacadeI;
import omero.model.AnnotationAnnotationLink;
import omero.model.AnnotationAnnotationLinkI;
import omero.model.Dataset;
import omero.model.DatasetI;
import omero.model.ExperimenterGroupI;
import omero.model.FileAnnotation;
import omero.model.FileAnnotationI;
import omero.model.IObject;
import omero.model.Image;
import omero.model.ImageAnnotationLink;
import omero.model.ImageAnnotationLinkI;
import omero.model.ImageI;
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 org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
@Test(groups = { "integration", "chown" })
@SuppressWarnings("deprecation")
public class ChownITest extends AbstractGraphTest {
long newUserId = 0L;
@BeforeMethod
protected void setupNewGroup() throws Exception {
newUserId = root.newGroup();
root.addUserToGroup(
user.getCurrentEventContext().getCurrentUserId(), newUserId);
user.getCurrentEventContext(); // RELOAD.
}
IRequest newChown(String type, long id, long user) {
return newChown(type, id, user, null);
}
IRequest newChown(String type, long id, long user,
Map<String, String> options) {
ChownFacadeI chown = (ChownFacadeI) ic.findObjectFactory(Chown.ice_staticId()).create("");
chown.type = type;
chown.id = id;
chown.options = options;
chown.user = user;
return chown;
}
/**
* Demonstrates a simple usage. No intention of showing validity, but can be
* given as an example to people.
*/
public void testBasicUsageOfChown() throws Exception {
// Setup data
long imageId = makeImage();
// Do chown and wait on completion.
IRequest chown = newChown("/Image", imageId, newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 1000);
// Non-null response signals completion.
assertNotNull(handle.getResponse());
// Cancelling is not possible after completion.
assertFalse(handle.cancel());
// Make sure that the FAILURE flag is not set.
assertFalse(handle.getStatus().flags.contains(State.FAILURE));
}
//
// Phase 1: basic validation
//
/**
* Simple test showing that if a link is found between two non-user groups
* that the chmod will fail.
*/
@Test(groups = "ticket:6422")
public void testDatasetImageLinkKeepFails() throws Exception {
// Create data
Image i = new ImageI();
i.setName(rstring("ticket:6422"));
Dataset d = new DatasetI();
d.setName(rstring("ticket:6422"));
i.linkDataset(d);
i = assertSaveAndReturn(i);
Map<String, String> options = new HashMap<String, String>();
options.put("/DatasetImageLink", "KEEP");
IRequest chown = newChown("/Image", i.getId().getValue(), newUserId, options);
_HandleTie handle = doChown(chown);
block(handle, 5, 1000);
assertFailure(handle);
}
/**
* Like {@link #testDatasetImageLinkFails()} but with the option to delete
* the link turned on, the chown is successful.
*/
@Test(groups = "ticket:6422")
public void testDatasetImageLinkForcePasses() throws Exception {
// Create data
Image i = new ImageI();
i.setName(rstring("ticket:6422"));
Dataset d = new DatasetI();
d.setName(rstring("ticket:6422"));
i.linkDataset(d);
i = assertSaveAndReturn(i);
IRequest chown = newChown("/Image", i.getId().getValue(), newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 1000);
assertSuccess(handle);
}
/**
* Attempts to use the /Image/Pixels/Channel specification to chown the
* channels added during {@link #makeImage()}. This should fail the group
* validity tests.
*/
public void testChownChannels() throws Exception {
// Create test data
long imageId = makeImage();
List<List<RType>> channelIds = assertProjection(
"select ch.id from Channel ch where ch.pixels.image.id = "
+ imageId, null);
int size = channelIds.size();
assertTrue(size > 0);
// Perform chown
IRequest chown = newChown("/Image/Pixels/Channel",
imageId, newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 500);
assertFailure(handle);
}
/**
* Like {@link #testChownChannels()} this should fail since it's not really
* possible for the rdef to exist alone. This should somehow be detectable
* by clients.
*/
public void testChownRenderingDef() throws Exception {
// Create test data
long imageId = makeImage();
String check = "select rdef.id from RenderingDef rdef where rdef.pixels.image.id = "
+ imageId;
List<List<RType>> ids = assertProjection(check, null);
assertTrue(ids.size() > 0);
// Perform chown
IRequest chown = newChown("/Image/Pixels/RenderingDef", imageId,
newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 500);
assertFailure(handle);
}
/**
* chown the whole image.
*/
@SuppressWarnings("rawtypes")
public void testImage() throws Exception {
long imageId = makeImage();
IRequest chown = newChown("/Image", imageId, newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 500);
assertSuccess(handle);
// For anyone logged into the old group, it should seem to disappear
List l = assertProjection("select i.id from Image i where i.id = "
+ imageId, null);
assertEquals(0, l.size());
// Logger into new group.
changeToNewGroup();
// For anyone logged into the new group, it should be present
l = assertProjection("select i.id from Image i where i.id = "
+ imageId, null);
assertEquals(1, l.size());
}
//
// Phase 2: annotation validation
//
/**
* Uses the /Image specification to chown an Image and its
* annotations simply linked annotation. This is the most basic case.
*/
@Test(groups = "ticket:6297")
public void testImageWithAnnotations() throws Exception {
// Create test data
long imageId = makeImage();
ImageAnnotationLink link = new ImageAnnotationLinkI();
link.link(new ImageI(imageId, false), new TagAnnotationI());
link = assertSaveAndReturn(link);
long annId = link.getChild().getId().getValue();
// Perform chown
IRequest chown = newChown("/Image", imageId, newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 500);
assertSuccess(handle);
// Check that image and ann are gone
assertDoesNotExist("Annotation", annId);
assertDoesNotExist("Image", imageId);
// Logging into the other group should reverse the situation
changeToNewGroup();
assertDoesExist("Annotation", annId);
assertDoesExist("Image", imageId);
}
/**
* Uses the /Image specification to chown an Image and attempts to
* remove its annotations. If those annotations are multiply linked,
* however, the attempted chown is rolled back (via a savepoint)
*/
@Test(groups = { "ticket:6297" })
public void testImageWithSharedAnnotations() throws Exception {
// Create test data
long imageId1 = makeImage();
long imageId2 = makeImage();
TagAnnotation tag = new TagAnnotationI();
tag = assertSaveAndReturn(tag);
long tagId = tag.getId().getValue();
ImageAnnotationLink link1 = new ImageAnnotationLinkI();
link1.link(new ImageI(imageId1, false), tag);
link1 = assertSaveAndReturn(link1);
ImageAnnotationLink link2 = new ImageAnnotationLinkI();
link2.link(new ImageI(imageId2, false), tag);
link2 = assertSaveAndReturn(link2);
// Perform chown
IRequest chown = newChown("/Image", imageId1, newUserId);
_HandleTie handle = doChown(chown);
block(handle, 5, 500);
assertSuccess(handle);
// Check that image and ann are gone
assertDoesExist("Annotation", tagId);
assertDoesExist("Image", imageId2);
assertDoesNotExist("Image", imageId1);
// Logging into the other group should reverse the situation
changeToNewGroup();
assertDoesNotExist("Annotation", tagId);
assertDoesNotExist("Image", imageId2);
assertDoesExist("Image", imageId1);
}
/**
* Chown a project and all its datasets though no images are created.
*/
@SuppressWarnings("rawtypes")
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 = assertSaveAndReturn(p);
long pid = p.getId().getValue();
long did = p.linkedDatasetList().get(0).getId().getValue();
// Do Delete
IRequest chown = newChown("/Project", pid, newUserId);
doChown(chown);
// Make sure its been moved.
assertDoesNotExist("Project", pid);
assertDoesNotExist("Dataset", did);
changeToNewGroup();
assertDoesExist("Project", pid);
assertDoesExist("Dataset", did);
}
/**
* Chown a project and all its datasets which have images.
*/
public void testProject() throws Exception {
long iid = makeImage();
// 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 = assertSaveAndReturn(p);
d = p.linkedDatasetList().get(0);
long pid = p.getId().getValue();
long did = d.getId().getValue();
// Do Delete
IRequest chown = newChown("/Project", pid, newUserId);
doChown(chown);
// Make sure its been moved.
assertDoesNotExist("Project", pid);
assertDoesNotExist("Dataset", did);
assertDoesNotExist("Image", iid);
changeToNewGroup();
assertDoesExist("Project", pid);
assertDoesExist("Dataset", did);
assertDoesExist("Image", iid);
}
/**
* Chown a very simple plate to ensure that the "/Image+WS" spec is
* working.
*/
public void testSimplePlate() throws Exception {
long iid = makeImage();
// Create test data
Plate p = createPlate(iid);
p = assertSaveAndReturn(p);
long pid = p.getId().getValue();
Well w = p.copyWells().get(0);
long wid = w.getId().getValue();
WellSample ws = w.getWellSample(0);
long wsid = ws.getId().getValue();
// Do Delete
IRequest chown = newChown("/Plate", pid, newUserId);
doChown(chown);
// Make sure its moved
assertDoesNotExist("Plate", pid);
assertDoesNotExist("Well", wid);
assertDoesNotExist("WellSample", wsid);
assertDoesNotExist("Image", iid);
changeToNewGroup();
assertDoesExist("Plate", pid);
assertDoesExist("Well", wid);
assertDoesExist("WellSample", wsid);
assertDoesExist("Image", iid);
}
/**
* Chown a very simple image/annotation graph, to guarantee that the basic
* options are working
*/
public void testSimpleImageWithAnnotation() throws Exception {
long iid = makeImage();
// Create test data
ImageAnnotationLink link = new ImageAnnotationLinkI();
link.link(new ImageI(iid, false), new TagAnnotationI());
link = assertSaveAndReturn(link);
long lid = link.getId().getValue();
long aid = link.getChild().getId().getValue();
// Do Delete
IRequest chown = newChown("/Image", iid, newUserId);
doChown(chown);
// Make sure its moved
assertDoesNotExist("Image", iid);
assertDoesNotExist("ImageAnnotationLink", lid);
assertDoesNotExist("Annotation", aid);
changeToNewGroup();
assertDoesExist("Image", iid);
assertDoesExist("ImageAnnotationLink", lid);
assertDoesExist("Annotation", aid);
}
/**
* Attempts to use the ILink type for chown'ing all links which point at an
* annotation.
*/
public void testChownAllAnnotationLinks() throws Exception {
// Create test data
AnnotationAnnotationLink link = new AnnotationAnnotationLinkI();
link.link(new TagAnnotationI(), new TagAnnotationI());
link = assertSaveAndReturn(link);
long lid = link.getId().getValue();
long pid = link.getParent().getId().getValue();
long cid = link.getChild().getId().getValue();
// Do Delete
IRequest chown = newChown("/Annotation", cid, newUserId);
doChown(chown);
// Make sure the parent annotation still exists, but both the annotation
// link and the annotation that was linked to (the child) are gone.
assertDoesExist("Annotation", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid); // Deleted
assertDoesNotExist("Annotation", cid);
changeToNewGroup();
assertDoesNotExist("Annotation", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid);
assertDoesExist("Annotation", cid);
}
/**
* Uses the {@link GraphEntry.Op#KEEP} setting to prevent a chown from
* happening.
*/
public void testKeepAnnotation() throws Exception {
// Create test data
AnnotationAnnotationLink link = new AnnotationAnnotationLinkI();
link.link(new TagAnnotationI(), new TagAnnotationI());
link = assertSaveAndReturn(link);
long lid = link.getId().getValue();
long pid = link.getParent().getId().getValue();
long cid = link.getChild().getId().getValue();
// Do Delete
Map<String, String> options = new HashMap<String, String>();
options.put("/TagAnnotation", "KEEP");
IRequest chown = newChown("/Annotation", cid, newUserId, options);
doChown(chown);
// Make sure everything stays put.
assertDoesExist("Annotation", pid);
assertDoesExist("AnnotationAnnotationLink", lid);
assertDoesExist("Annotation", cid);
changeToNewGroup();
assertDoesNotExist("Annotation", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid);
assertDoesNotExist("Annotation", cid);
}
/**
* Uses the {@link GraphEntry.Op#KEEP} setting to prevent a chown from
* happening.
*/
public void testKeepImageAnnotation() throws Exception {
// Create test data
long iid = makeImage();
ImageAnnotationLink link = new ImageAnnotationLinkI();
link.link(new ImageI(iid, false), new TagAnnotationI());
link = assertSaveAndReturn(link);
long lid = link.getId().getValue();
long pid = link.getParent().getId().getValue();
long cid = link.getChild().getId().getValue();
// Do Delete
Map<String, String> options = new HashMap<String, String>();
options.put("/TagAnnotation", "KEEP");
IRequest chown = newChown("/Image", pid, newUserId, options);
doChown(chown);
assertDoesNotExist("Image", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid); // Deleted
assertDoesExist("Annotation", cid);
changeToNewGroup();
assertDoesExist("Image", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid);
assertDoesNotExist("Annotation", cid);
}
/**
* Tests overriding the {@link GraphEntry.Op#KEEP} setting by a hard-code
* value in spec.xml. These are well-known "unshared" annotations, that
* should be chown'd, regardless of KEEP.
*/
@SuppressWarnings("rawtypes")
public void testDontKeepImageAnnotationIfUnsharedNS() throws Exception {
// Create test data
FileAnnotation file = new FileAnnotationI();
file.setNs(omero.rtypes
.rstring("openmicroscopy.org/omero/import/companionFile"));
long iid = makeImage();
ImageAnnotationLink link = new ImageAnnotationLinkI();
link.link(new ImageI(iid, false), file);
link = assertSaveAndReturn(link);
long lid = link.getId().getValue();
long pid = link.getParent().getId().getValue();
long cid = link.getChild().getId().getValue();
// Do Delete
Map<String, String> options = new HashMap<String, String>();
options.put("/FileAnnotation", "KEEP");
IRequest chown = newChown("/Image", pid, newUserId, options);
doChown(chown);
assertDoesNotExist("Image", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid);
assertDoesNotExist("Annotation", cid);
changeToNewGroup();
assertDoesExist("Image", pid);
assertDoesExist("AnnotationAnnotationLink", lid);
assertDoesExist("Annotation", cid);
}
/**
* Tests overriding the {@link GraphEntry.Op#KEEP} setting by setting a
* namespace which should always be chown'd (an "unshared" annotation).
*/
public void testDontKeepImageAnnotationIfRequestedNS() throws Exception {
// Create test data
FileAnnotation file = new FileAnnotationI();
file.setNs(omero.rtypes.rstring("keepme"));
long iid = makeImage();
ImageAnnotationLink link = new ImageAnnotationLinkI();
link.link(new ImageI(iid, false), file);
link = assertSaveAndReturn(link);
long lid = link.getId().getValue();
long pid = link.getParent().getId().getValue();
long cid = link.getChild().getId().getValue();
// Do Delete
Map<String, String> options = new HashMap<String, String>();
options.put("/FileAnnotation", "KEEP;excludes=keepme");
IRequest chown = newChown("/Image", pid, newUserId, options);
doChown(chown);
assertDoesNotExist("Image", pid);
assertDoesNotExist("AnnotationAnnotationLink", lid);
assertDoesNotExist("Annotation", cid);
changeToNewGroup();
assertDoesExist("Image", pid);
assertDoesExist("AnnotationAnnotationLink", lid);
assertDoesExist("Annotation", cid);
}
/**
* This method is copied from DeleteServiceTest to reproduce an issue in
* which KEEP;excludes= is not being taken into acount.
*/
@Test
public void testChownObjectWithAnnotationWithoutNS() throws Exception {
Screen obj = new ScreenI();
obj.setName(omero.rtypes.rstring("testChownObjectWithAnnotationWithoutNS"));
obj = assertSaveAndReturn(obj);
String type = "/Screen";
long id = obj.getId().getValue();
List<Long> annotationIds = createNonSharableAnnotation(obj, null);
List<Long> annotationIdsNS = createNonSharableAnnotation(obj, "TEST");
Map<String, String> options = new HashMap<String, String>();
options.put("/Annotation", "KEEP;excludes=TEST");
doChown(newChown(type, id, newUserId, options));
ParametersI param = new ParametersI();
param.addId(obj.getId().getValue());
String sql = "select s from Screen s where id = :id";
assertEquals(0, assertFindByQuery(sql, param).size());
param = new ParametersI();
param.addIds(annotationIds);
assertTrue(annotationIds.size() > 0);
sql = "select i from Annotation as i where i.id in (:ids)";
List<IObject> l = assertFindByQuery(sql, param);
assertEquals(obj + "-->" + l.toString(), annotationIds.size(), l.size());
param = new ParametersI();
param.addIds(annotationIdsNS);
assertTrue(annotationIdsNS.size() > 0);
sql = "select i from Annotation as i where i.id in (:ids)";
l = assertFindByQuery(sql, param);
assertEquals(obj + "-->" + l.toString(), 0, l.size());
}
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 = assertSaveAndReturn(link);
return Arrays.asList(link.getChild().getId().getValue());
}
//
// Helpers
//
private void changeToNewGroup() throws ServerError {
user.sf.setSecurityContext(new ExperimenterGroupI(newUserId, false), null);
}
private _HandleTie doChown(IRequest chown) throws Exception {
Ice.Identity id = new Ice.Identity("handle", "chown");
HandleI handle = new HandleI(1000);
handle.setSession(user.sf);
handle.initialize(id, chown, null);
handle.run();
// Client side this would need a try/finally { handle.close() }
return new _HandleTie(handle);
}
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;
}
}