/* * Copyright (C) 2015 University of Dundee & Open Microscopy Environment. * 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.chown; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import omero.RLong; import omero.RType; import omero.ServerError; import omero.cmd.Chmod2; import omero.cmd.Chown2; import omero.cmd.Delete2; import omero.gateway.util.Requests; import omero.model.Annotation; import omero.model.CommentAnnotationI; import omero.model.Dataset; import omero.model.DatasetImageLink; import omero.model.DatasetImageLinkI; import omero.model.Experiment; import omero.model.Experimenter; import omero.model.ExperimenterGroup; import omero.model.ExperimenterGroupI; import omero.model.ExperimenterI; import omero.model.IObject; import omero.model.Image; import omero.model.ImageAnnotationLink; import omero.model.ImageAnnotationLinkI; import omero.model.Instrument; import omero.model.Pixels; import omero.model.Plate; import omero.model.RectangleI; import omero.model.Roi; import omero.model.RoiI; import omero.model.TagAnnotation; import omero.model.TagAnnotationI; import omero.model.Thumbnail; import omero.sys.EventContext; import omero.sys.Parameters; import omero.sys.ParametersI; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import com.google.common.collect.ImmutableMap; import integration.AbstractServerTest; /** * Tests that only appropriate users may use {@link Chown2} and that others' data is left unchanged. * @author m.t.b.carroll@dundee.ac.uk * @since 5.1.2 */ public class PermissionsTest extends AbstractServerTest { private final List<Long> testImages = Collections.synchronizedList(new ArrayList<Long>()); private ExperimenterGroup systemGroup, otherGroup; /** * Set up admin and non-admin users who are not a member of the groups created by tests. * @throws Exception unexpected */ @BeforeClass public void setupOtherGroup() throws Exception { systemGroup = new ExperimenterGroupI(iAdmin.getSecurityRoles().systemGroupId, false); otherGroup = new ExperimenterGroupI(iAdmin.getEventContext().groupId, false); } /** * Clear the list of test images. */ @BeforeClass public void clearTestImages() { testImages.clear(); } /** * Delete the test images then clear the list. * @throws Exception unexpected */ @AfterClass public void deleteTestImages() throws Exception { final Delete2 delete = Requests.delete("Image", testImages); doChange(root, root.getSession(), delete, true); clearTestImages(); } /** * Add the given annotation to the given image. * @param image an image * @param annotation an annotation * @return the new loaded link from the image to the annotation * @throws ServerError unexpected */ private ImageAnnotationLink annotateImage(Image image, Annotation annotation) throws ServerError { if (image.isLoaded() && image.getId() != null) { image = (Image) image.proxy(); } if (annotation.isLoaded() && annotation.getId() != null) { annotation = (Annotation) annotation.proxy(); } final ImageAnnotationLink link = new ImageAnnotationLinkI(); link.setParent(image); link.setChild(annotation); return (ImageAnnotationLink) iUpdate.saveAndReturnObject(link); } /** * Add a comment, tag and a ROI to the given image. * @param image an image * @return the new model objects * @throws ServerError unexpected */ private List<IObject> annotateImage(Image image) throws ServerError { if (image.isLoaded() && image.getId() != null) { image = (Image) image.proxy(); } final List<IObject> annotationObjects = new ArrayList<IObject>(); for (final Annotation annotation : new Annotation[] {new CommentAnnotationI(), new TagAnnotationI()}) { final ImageAnnotationLink link = annotateImage(image, annotation); annotationObjects.add(link.proxy()); annotationObjects.add(link.getChild().proxy()); } Roi roi = new RoiI(); roi.addShape(new RectangleI()); roi.setImage((Image) image.proxy()); roi = (Roi) iUpdate.saveAndReturnObject(roi); annotationObjects.add(roi.proxy()); annotationObjects.add(roi.getShape(0).proxy()); final ParametersI params = new ParametersI().addId(image.getId()); final Pixels pixels = (Pixels) iQuery.findByQuery("FROM Pixels WHERE image.id = :id", params); Thumbnail thumbnail = mmFactory.createThumbnail(); thumbnail.setPixels((Pixels) pixels.proxy()); thumbnail = (Thumbnail) iUpdate.saveAndReturnObject(thumbnail); annotationObjects.add(thumbnail.proxy()); return annotationObjects; } /** * Assert that the given object is owned by the given owner. * @param object a model object * @param expectedOwner a user's event context * @throws ServerError unexpected */ private void assertOwnedBy(IObject object, EventContext expectedOwner) throws ServerError { assertOwnedBy(Collections.singleton(object), expectedOwner); } /** * Assert that the given objects are owned by the given owner. * @param objects some model objects * @param expectedOwner a user's event context * @throws ServerError unexpected */ private void assertOwnedBy(Collection<? extends IObject> objects, EventContext expectedOwner) throws ServerError { if (objects.isEmpty()) { throw new IllegalArgumentException("must assert about some objects"); } for (final IObject object : objects) { final String objectName = object.getClass().getName() + '[' + object.getId().getValue() + ']'; final String query = "SELECT details.owner.id FROM " + object.getClass().getSuperclass().getSimpleName() + " WHERE id = " + object.getId().getValue(); final List<List<RType>> results = iQuery.projection(query, null); final long actualOwnerId = ((RLong) results.get(0).get(0)).getValue(); Assert.assertEquals(actualOwnerId, expectedOwner.userId, objectName); } } /** * Test a specific case of using {@link Chown2} with owner's shared annotations in a private group. * @param isDataOwner if the user submitting the {@link Chown2} request owns the data in the group * @param isAdmin if the user submitting the {@link Chown2} request is a member of the system group * @param isGroupOwner if the user submitting the {@link Chown2} request owns the group itself * @param isRecipientInGroup if the user receiving data by means of the {@link Chown2} request is a member of the data's group * @param isExpectSuccess if the chown is expected to succeed * @throws Exception unexpected */ @Test(dataProvider = "chown annotation test cases") public void testChownAnnotationPrivate(boolean isDataOwner, boolean isAdmin, boolean isGroupOwner, boolean isRecipientInGroup, boolean isExpectSuccess) throws Exception { /* set up the users and group for this test case */ final EventContext importer, chowner, recipient; final ExperimenterGroup dataGroup; importer = newUserAndGroup("rw----", isDataOwner && isGroupOwner); final long dataGroupId = importer.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); recipient = newUserInGroup(isRecipientInGroup ? dataGroup : otherGroup, false); if (isDataOwner) { chowner = importer; } else { chowner = newUserInGroup(dataGroup, isGroupOwner); } if (isAdmin) { addUsers(systemGroup, Collections.singletonList(chowner.userId), false); } /* note which objects were used to annotate an image */ final List<IObject> imageAnnotations; final List<ImageAnnotationLink> tagLinksOnOtherImage = new ArrayList<ImageAnnotationLink>(); /* import and annotate an image */ init(importer); final Image image = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy(); final long imageId = image.getId().getValue(); testImages.add(imageId); imageAnnotations = annotateImage(image); /* tag another image with the tags from the first image */ final Image otherImage = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy(); testImages.add(otherImage.getId().getValue()); for (final IObject annotation : imageAnnotations) { if (annotation instanceof TagAnnotation) { final ImageAnnotationLink link = (ImageAnnotationLink) annotateImage(otherImage, (TagAnnotation) annotation); tagLinksOnOtherImage.add((ImageAnnotationLink) link.proxy()); } } disconnect(); /* perform the chown */ init(chowner); final Chown2 chown = Requests.chown("Image", imageId, recipient.userId); doChange(client, factory, chown, isExpectSuccess); disconnect(); if (!isExpectSuccess) { return; } /* check that the objects' ownership is all as expected */ final Set<Long> imageLinkIds = new HashSet<Long>(); logRootIntoGroup(dataGroupId); assertOwnedBy(image, recipient); for (final IObject annotation : imageAnnotations) { if (annotation instanceof TagAnnotation) { assertOwnedBy(annotation, importer); } else if (annotation instanceof ImageAnnotationLink) { imageLinkIds.add(annotation.getId().getValue()); } else { assertOwnedBy(annotation, recipient); } } assertOwnedBy(tagLinksOnOtherImage, importer); /* check that the image's links to the tags that were also linked to the other image were deleted */ final String query = "SELECT COUNT(id) FROM ImageAnnotationLink WHERE id IN (:ids)"; final ParametersI params = new ParametersI().addIds(imageLinkIds); final List<List<RType>> results = iQuery.projection(query, params); final long remainingLinkCount = ((RLong) results.get(0).get(0)).getValue(); Assert.assertEquals(remainingLinkCount, imageLinkIds.size() - tagLinksOnOtherImage.size()); disconnect(); } /** * Test a specific case of using {@link Chown2} with owner's and others' annotations in a read-annotate group. * @param isDataOwner if the user submitting the {@link Chown2} request owns the data in the group * @param isAdmin if the user submitting the {@link Chown2} request is a member of the system group * @param isGroupOwner if the user submitting the {@link Chown2} request owns the group itself * @param isRecipientInGroup if the user receiving data by means of the {@link Chown2} request is a member of the data's group * @param isExpectSuccess if the chown is expected to succeed * @throws Exception unexpected */ @Test(dataProvider = "chown annotation test cases") public void testChownAnnotationReadAnnotate(boolean isDataOwner, boolean isAdmin, boolean isGroupOwner, boolean isRecipientInGroup, boolean isExpectSuccess) throws Exception { /* set up the users and group for this test case */ final EventContext importer, annotator, chowner, recipient; final ExperimenterGroup dataGroup; importer = newUserAndGroup("rwra--", isDataOwner && isGroupOwner); final long dataGroupId = importer.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); recipient = newUserInGroup(isRecipientInGroup ? dataGroup : otherGroup, false); if (isDataOwner) { chowner = importer; } else { chowner = newUserInGroup(dataGroup, isGroupOwner); } if (isAdmin) { addUsers(systemGroup, Collections.singletonList(chowner.userId), false); } annotator = newUserInGroup(dataGroup, false); /* note which objects were used to annotate an image */ final List<IObject> ownerAnnotations, otherAnnotations; /* import and annotate an image */ init(importer); final Image image = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy(); final long imageId = image.getId().getValue(); testImages.add(imageId); ownerAnnotations = annotateImage(image); disconnect(); /* have another user annotate the image */ init(annotator); otherAnnotations = annotateImage(image); disconnect(); /* perform the chown */ init(chowner); final Chown2 chown = Requests.chown("Image", imageId, recipient.userId); doChange(client, factory, chown, isExpectSuccess); disconnect(); if (!isExpectSuccess) { return; } /* check that the objects' ownership is all as expected */ logRootIntoGroup(dataGroupId); assertOwnedBy(image, recipient); assertOwnedBy(ownerAnnotations, importer); assertOwnedBy(otherAnnotations, annotator); disconnect(); } /** * @return a variety of test cases for annotation chown */ @DataProvider(name = "chown annotation test cases") public Object[][] provideChownAnnotationCases() { int index = 0; final int IS_DATA_OWNER = index++; final int IS_ADMIN = index++; final int IS_GROUP_OWNER = index++; final int IS_RECIPIENT_IN_GROUP = index++; final int IS_EXPECT_SUCCESS = index++; final boolean[] booleanCases = new boolean[]{false, true}; final List<Object[]> testCases = new ArrayList<Object[]>(); for (final boolean isDataOwner : booleanCases) { for (final boolean isAdmin : booleanCases) { for (final boolean isGroupOwner : booleanCases) { for (final boolean isRecipientInGroup : booleanCases) { if (isAdmin && isGroupOwner) { /* not an interesting case */ continue; } final Object[] testCase = new Object[index]; testCase[IS_DATA_OWNER] = isDataOwner; testCase[IS_ADMIN] = isAdmin; testCase[IS_GROUP_OWNER] = isGroupOwner; testCase[IS_RECIPIENT_IN_GROUP] = isRecipientInGroup; testCase[IS_EXPECT_SUCCESS] = isAdmin || isGroupOwner && isRecipientInGroup; // DEBUG: if (isDataOwner == true && isAdmin == true && isGroupOwner == true && // isRecipientInGroup == true) testCases.add(testCase); } } } } return testCases.toArray(new Object[testCases.size()][]); } /** * Test a specific case of using {@link Chown2} on an image that is in a dataset. * @param isImageOwner if the user who owns the dataset also owns the image * @param isLinkOwner if the user who owns the dataset also linked the image to the dataset * @param groupPermissions the permissions on the group in which the data exists * @throws Exception unexpected */ @Test(dataProvider = "chown container test cases") public void testChownImageInDataset(boolean isImageOwner, boolean isLinkOwner, String groupPermissions) throws Exception { /* set up the users and group for this test case */ final EventContext datasetOwner, imageOwner, linkOwner, recipient; final ExperimenterGroup dataGroup; datasetOwner = newUserAndGroup(groupPermissions, true); final long dataGroupId = datasetOwner.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); recipient = newUserInGroup(dataGroup, false); if (isImageOwner) { imageOwner = datasetOwner; linkOwner = isLinkOwner ? datasetOwner : newUserInGroup(dataGroup, false); } else { imageOwner = newUserInGroup(dataGroup, true); linkOwner = isLinkOwner ? datasetOwner : imageOwner; } /* create a dataset */ init(datasetOwner); final Dataset dataset = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset()).proxy(); disconnect(); /* create an image */ init(imageOwner); final Image image = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy(); final long imageId = image.getId().getValue(); testImages.add(imageId); disconnect(); /* move the image into the dataset */ init(linkOwner); DatasetImageLink link = new DatasetImageLinkI(); link.setParent(dataset); link.setChild(image); link = (DatasetImageLink) iUpdate.saveAndReturnObject(link); disconnect(); /* perform the chown */ init(imageOwner); final Chown2 chown = Requests.chown("Image", imageId, recipient.userId); doChange(client, factory, chown, true); disconnect(); /* check that the objects' ownership is all as expected */ logRootIntoGroup(dataGroupId); assertOwnedBy(dataset, datasetOwner); assertOwnedBy(image, recipient); final boolean isExpectLink = "rwrw--".equals(groupPermissions); if (isExpectLink) { assertExists(link); assertOwnedBy(link, linkOwner); } else { assertDoesNotExist(link); } disconnect(); } /** * Test a specific case of using {@link Chown2} on a dataset that contains an image. * @param isImageOwner if the user who owns the dataset also owns the image * @param isLinkOwner if the user who owns the dataset also linked the image to the dataset * @param groupPermissions the permissions on the group in which the data exists * @throws Exception unexpected */ @Test(dataProvider = "chown container test cases") public void testChownDatasetWithImage(boolean isImageOwner, boolean isLinkOwner, String groupPermissions) throws Exception { /* set up the users and group for this test case */ final EventContext datasetOwner, imageOwner, linkOwner, recipient; final ExperimenterGroup dataGroup; datasetOwner = newUserAndGroup(groupPermissions, true); final long dataGroupId = datasetOwner.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); recipient = newUserInGroup(dataGroup, false); if (isImageOwner) { imageOwner = datasetOwner; linkOwner = isLinkOwner ? datasetOwner : newUserInGroup(dataGroup, false); } else { imageOwner = newUserInGroup(dataGroup, true); linkOwner = isLinkOwner ? datasetOwner : imageOwner; } /* create a dataset */ init(datasetOwner); final Dataset dataset = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset()).proxy(); final long datasetId = dataset.getId().getValue(); disconnect(); /* create an image */ init(imageOwner); final Image image = (Image) iUpdate.saveAndReturnObject(mmFactory.createImage()).proxy(); final long imageId = image.getId().getValue(); testImages.add(imageId); disconnect(); /* move the image into the dataset */ init(linkOwner); DatasetImageLink link = new DatasetImageLinkI(); link.setParent(dataset); link.setChild(image); link = (DatasetImageLink) iUpdate.saveAndReturnObject(link); disconnect(); /* perform the chown */ init(datasetOwner); final Chown2 chown = Requests.chown("Dataset", datasetId, recipient.userId); doChange(client, factory, chown, true); disconnect(); /* check that the objects' ownership is all as expected */ logRootIntoGroup(dataGroupId); assertOwnedBy(dataset, recipient); assertOwnedBy(image, isImageOwner ? recipient : imageOwner); assertOwnedBy(link, isImageOwner ? recipient : linkOwner); disconnect(); } /** * @return a variety of test cases for container chown */ @DataProvider(name = "chown container test cases") public Object[][] provideChownContainerCases() { int index = 0; final int IS_IMAGE_OWNER = index++; final int IS_LINK_OWNER = index++; final int GROUP_PERMS = index++; final boolean[] booleanCases = new boolean[]{false, true}; final String[] permsCases = new String[]{"rw----", "rwr---", "rwra--", "rwrw--"}; final List<Object[]> testCases = new ArrayList<Object[]>(); for (final boolean isImageOwner : booleanCases) { for (final boolean isLinkOwner : booleanCases) { for (final String groupPerms : permsCases) { if (!(isImageOwner && isLinkOwner || "rwrw--".equals(groupPerms))) { /* test case does not make sense */ continue; } final Object[] testCase = new Object[index]; testCase[IS_IMAGE_OWNER] = isImageOwner; testCase[IS_LINK_OWNER] = isLinkOwner; testCase[GROUP_PERMS] = groupPerms; // DEBUG: if (isImageOwner == true && isLinkOwner == true && "rwr---".equals(groupPerms)) testCases.add(testCase); } } } return testCases.toArray(new Object[testCases.size()][]); } /** * Test chown on an image whose instrument is shared with another's image. * @param groupPermissions the permissions on the group in which the chown is to occur * @throws Exception unexpected */ @Test(dataProvider = "image sharing test cases") public void testSharedInstrument(String groupPermissions) throws Exception { /* set up the users and group for this test case */ final EventContext imageOwner, projectionOwner, recipient; final ExperimenterGroup dataGroup; imageOwner = newUserAndGroup("rwrw--", true); final long dataGroupId = imageOwner.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); projectionOwner = newUserInGroup(dataGroup, false); recipient = newUserInGroup(dataGroup, false); /* create an image with an instrument */ init(imageOwner); Image image = mmFactory.createImage(); image.setInstrument(mmFactory.createInstrument()); image = (Image) iUpdate.saveAndReturnObject(image); final long imageId = image.getId().getValue(); testImages.add(imageId); final Instrument instrument = (Instrument) image.getInstrument().proxy(); image = (Image) image.proxy(); disconnect(); /* another user projects the image */ init(projectionOwner); Image projection = mmFactory.createImage(); projection.setInstrument(instrument); projection = (Image) iUpdate.saveAndReturnObject(projection); final long projectionId = projection.getId().getValue(); testImages.add(projectionId); projection = (Image) projection.proxy(); disconnect(); /* chmod the group to the required permissions */ logRootIntoGroup(dataGroupId); final Chmod2 chmod = Requests.chmod("ExperimenterGroup", dataGroupId, groupPermissions); doChange(client, factory, chmod, true); disconnect(); /* perform the chown */ init(imageOwner); final Chown2 chown = Requests.chown("Image", imageId, recipient.userId); doChange(client, factory, chown, true); disconnect(); /* check that the objects' ownership is all as expected */ logRootIntoGroup(dataGroupId); assertOwnedBy(image, recipient); assertOwnedBy(projection, projectionOwner); assertOwnedBy(instrument, imageOwner); disconnect(); } /** * Test chown on an image that is used in the same experiment as another's image. * @param groupPermissions the permissions on the group in which the chown is to occur * @throws Exception unexpected */ @Test(dataProvider = "image sharing test cases") public void testSharedExperiment(String groupPermissions) throws Exception { /* set up the users and group for this test case */ final EventContext imageOwner, otherImageOwner, recipient; final ExperimenterGroup dataGroup; imageOwner = newUserAndGroup("rwrw--", true); final long dataGroupId = imageOwner.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); otherImageOwner = newUserInGroup(dataGroup, false); recipient = newUserInGroup(dataGroup, false); /* create an image with an experiment */ init(imageOwner); Image image = mmFactory.createImage(); image.setExperiment(mmFactory.simpleExperiment()); image = (Image) iUpdate.saveAndReturnObject(image); final long imageId = image.getId().getValue(); testImages.add(imageId); final Experiment experiment = (Experiment) image.getExperiment().proxy(); image = (Image) image.proxy(); disconnect(); /* another user's image is part of the same experiment */ init(otherImageOwner); Image otherImage = mmFactory.createImage(); otherImage.setExperiment(experiment); otherImage = (Image) iUpdate.saveAndReturnObject(otherImage); final long otherImageId = otherImage.getId().getValue(); testImages.add(otherImageId); otherImage = (Image) otherImage.proxy(); disconnect(); /* chmod the group to the required permissions */ logRootIntoGroup(dataGroupId); final Chmod2 chmod = Requests.chmod("ExperimenterGroup", dataGroupId, groupPermissions); doChange(client, factory, chmod, true); disconnect(); /* perform the chown */ init(imageOwner); final Chown2 chown = Requests.chown("Image", imageId, recipient.userId); doChange(client, factory, chown, true); disconnect(); /* check that the objects' ownership is all as expected */ logRootIntoGroup(dataGroupId); assertOwnedBy(image, recipient); assertOwnedBy(otherImage, otherImageOwner); assertOwnedBy(experiment, imageOwner); disconnect(); } /** * @return group permissions for image sharing test cases */ @DataProvider(name = "image sharing test cases") public Object[][] provideImageSharingCases() { int index = 0; final int GROUP_PERMS = index++; final String[] permsCases = new String[]{"rwr---", "rwra--", "rwrw--"}; final List<Object[]> testCases = new ArrayList<Object[]>(); for (final String groupPerms : permsCases) { final Object[] testCase = new Object[index]; testCase[GROUP_PERMS] = groupPerms; // DEBUG: if ("rwr---".equals(groupPerms)) testCases.add(testCase); } return testCases.toArray(new Object[testCases.size()][]); } /* for dataset to plate test cases */ private enum Target { DATASET, IMAGES, PLATE }; /** * Test chown on a dataset, plate, or images, where the plate's images are in the dataset. * @param groupPermissions the permissions on the group in which the chown is to occur * @param target the target of the chown operation * @throws Exception unexpected */ @Test(dataProvider = "dataset to plate test cases") public void testDatasetToPlate(String groupPermissions, Target target) throws Exception { /* set up the users and group for this test case */ final EventContext datasetOwner, plateOwner, recipient; final ExperimenterGroup dataGroup; datasetOwner = newUserAndGroup("rwrw--", true); final long dataGroupId = datasetOwner.groupId; dataGroup = new ExperimenterGroupI(dataGroupId, false); plateOwner = newUserInGroup(dataGroup, false); recipient = newUserInGroup(dataGroup, false); /* create a plate */ init(plateOwner); Plate plate = mmFactory.createPlate(2, 2, 1, 1, false); plate = (Plate) iUpdate.saveAndReturnObject(plate).proxy(); final long plateId = plate.getId().getValue(); /* find the plate's images */ final List<Long> imageIds = new ArrayList<Long>(); final String hql = "SELECT image.id FROM WellSample where well.id IN (SELECT id FROM Well WHERE plate.id = :id)"; final Parameters params = new ParametersI().addId(plateId); for (final List<RType> result : iQuery.projection(hql, params)) { final Long imageId = ((RLong) result.get(0)).getValue(); imageIds.add(imageId); } disconnect(); /* the images should be owned by the dataset owner */ logRootIntoGroup(dataGroupId); final Experimenter datasetOwnerActual = new ExperimenterI(datasetOwner.userId, false); final List<IObject> images = iQuery.findAllByQuery("FROM Image WHERE id IN (:ids)", new ParametersI().addIds(imageIds)); Assert.assertEquals(images.size(), imageIds.size()); for (final IObject image : images) { image.getDetails().setOwner(datasetOwnerActual); } iUpdate.saveCollection(images); disconnect(); /* create the dataset and link the images to it */ init(datasetOwner); final Dataset dataset = (Dataset) iUpdate.saveAndReturnObject(mmFactory.simpleDataset()).proxy(); final long datasetId = dataset.getId().getValue(); final List<DatasetImageLink> links = new ArrayList<DatasetImageLink>(images.size()); for (final IObject image : images) { DatasetImageLink link = new DatasetImageLinkI(); link.setParent(dataset); link.setChild((Image) image.proxy()); links.add((DatasetImageLink) iUpdate.saveAndReturnObject(link).proxy()); } disconnect(); /* check that the objects' ownership is all as expected */ logRootIntoGroup(dataGroupId); assertOwnedBy(dataset, datasetOwner); assertOwnedBy(images, datasetOwner); assertOwnedBy(links, datasetOwner); assertOwnedBy(plate, plateOwner); disconnect(); /* perform the chown */ init(datasetOwner); final Chown2 chown; switch (target) { case DATASET: chown = Requests.chown("Dataset", datasetId, recipient.userId); break; case IMAGES: chown = Requests.chown("Image", imageIds, recipient.userId); break; case PLATE: chown = Requests.chown("Plate", plateId, recipient.userId); break; default: chown = null; Assert.fail("unexpected target for chown"); } doChange(client, factory, chown, true); disconnect(); logRootIntoGroup(dataGroupId); /* check that the objects' ownership is all as expected */ switch (target) { case DATASET: assertOwnedBy(dataset, recipient); assertOwnedBy(images, datasetOwner); assertOwnedBy(links, datasetOwner); assertOwnedBy(plate, plateOwner); break; case IMAGES: assertOwnedBy(dataset, datasetOwner); assertOwnedBy(images, recipient); assertOwnedBy(links, datasetOwner); assertOwnedBy(plate, plateOwner); break; case PLATE: assertOwnedBy(dataset, datasetOwner); assertOwnedBy(images, datasetOwner); assertOwnedBy(links, datasetOwner); assertOwnedBy(plate, recipient); break; } /* delete the objects as clean-up */ final Delete2 delete = new Delete2(); delete.targetObjects = ImmutableMap.of( "Dataset", Collections.singletonList(datasetId), "Plate", Collections.singletonList(plateId)); doChange(client, factory, delete, true); disconnect(); } /** * @return a variety of test cases for dataset to plate */ @DataProvider(name = "dataset to plate test cases") public Object[][] provideDatasetToPlateCases() { int index = 0; final int GROUP_PERMS = index++; final int TARGET = index++; final String[] permsCases = new String[]{"rwr---", "rwra--", "rwrw--"}; final List<Object[]> testCases = new ArrayList<Object[]>(); for (final String groupPerms : permsCases) { for (final Target target : Target.values()) { final Object[] testCase = new Object[index]; testCase[GROUP_PERMS] = groupPerms; testCase[TARGET] = target; // DEBUG: if ("rwr---".equals(groupPerms) && target == Target.DATASET) testCases.add(testCase); } } return testCases.toArray(new Object[testCases.size()][]); } }