/* * $Id$ * * Copyright 2006-2014 University of Dundee. All rights reserved. * Use is subject to license terms supplied in LICENSE.txt */ package ome.server.itests.update; import java.sql.Timestamp; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.TimeUnit; import ome.api.ITypes; import ome.api.Search; import ome.conditions.TryAgain; import ome.model.acquisition.Instrument; import ome.model.acquisition.Objective; import ome.model.acquisition.ObjectiveSettings; import ome.model.annotations.CommentAnnotation; import ome.model.annotations.LongAnnotation; import ome.model.annotations.TagAnnotation; import ome.model.containers.Dataset; import ome.model.containers.Project; import ome.model.containers.ProjectDatasetLink; import ome.model.core.Channel; import ome.model.core.Image; import ome.model.core.OriginalFile; import ome.model.core.Pixels; import ome.model.display.ChannelBinding; import ome.model.display.CodomainMapContext; import ome.model.display.RenderingDef; import ome.model.display.Thumbnail; import ome.model.enums.Correction; import ome.model.enums.Immersion; import ome.model.enums.Medium; import ome.model.enums.UnitsLength; import ome.model.jobs.ImportJob; import ome.model.jobs.JobStatus; import ome.model.meta.Experimenter; import ome.model.meta.ExperimenterGroup; import ome.model.roi.Line; import ome.model.roi.Rectangle; import ome.model.roi.Roi; import ome.model.roi.Shape; import ome.model.units.Length; import ome.parameters.Parameters; import ome.services.util.Executor; import ome.system.ServiceFactory; import ome.testing.ObjectFactory; import org.hibernate.LockOptions; import org.hibernate.Session; import org.springframework.transaction.annotation.Transactional; import org.testng.annotations.Test; public class UpdateTest extends AbstractUpdateTest { @Test(enabled=false) public void testSaveSimpleObject() throws Exception { Pixels p = ObjectFactory.createPixelGraph(null); p = iUpdate.saveAndReturnObject(p); // FIXME This can no longer be done this way. // List logs = securitySystem.getCurrentEvent().collectLogs(null); // assertTrue(logs.size() > 0); Pixels check = (Pixels) iQuery.findByQuery("select p from Pixels p " + " left outer join fetch p.channels " + " where p.id = :id", new Parameters().addId(p.getId())); assertTrue("channel ids differ", equalCollections(p .unmodifiableChannels(), check.unmodifiableChannels())); } @Test(enabled=false) public void test_uh_oh_duplicate_rows_0() throws Exception { String name = "SIMPLE:" + System.currentTimeMillis(); Project p = new Project(); p.setName(name); p = iUpdate.saveAndReturnObject(p); Project compare = iQuery.findByString(Project.class, "name", name); assertTrue(p.getId().equals(compare.getId())); Project send = new Project(); send.setName(p.getName()); send.setId(p.getId()); send.setVersion(p.getVersion()); // This is important. send.setDescription("...test..."); Project test = iUpdate.saveAndReturnObject(send); assertTrue(p.getId().equals(test.getId())); iQuery.findByString(Project.class, "name", name); } @Test(enabled=false) public void test_images_pixels() throws Exception { Image image = new Image(); image.setName("test"); Pixels active = ObjectFactory.createPixelGraph(null); image.addPixels(active); image = iUpdate.saveAndReturnObject(image); active = image.getPrimaryPixels(); Pixels other = ObjectFactory.createPixelGraph(null); image.addPixels(other); iUpdate.saveAndReturnObject(image); } @Test(enabled=false) public void test_index_save() throws Exception { RenderingDef def = ObjectFactory.createRenderingDef(); CodomainMapContext enhancement = ObjectFactory .createPlaneSlicingContext(); ChannelBinding binding = ObjectFactory.createChannelBinding(); // What we're interested in def.addChannelBinding(binding); def.addCodomainMapContext(enhancement); def = iUpdate.saveAndReturnObject(def); } @Test(enabled=false) public void test_index_save_order() throws Exception { RenderingDef def = ObjectFactory.createRenderingDef(); ChannelBinding binding1 = ObjectFactory.createChannelBinding(); binding1.setInputStart(new Double(1.0)); ChannelBinding binding2 = ObjectFactory.createChannelBinding(); binding2.setInputStart(new Double(2.0)); ChannelBinding binding3 = ObjectFactory.createChannelBinding(); binding3.setInputStart(new Double(3.0)); def.addChannelBinding(binding1); def.addChannelBinding(binding2); def.addChannelBinding(binding3); def = iUpdate.saveAndReturnObject(def); } @Test(enabled=false) public void test_experimenters_groups() throws Exception { Experimenter e = new Experimenter(); ExperimenterGroup g_1 = new ExperimenterGroup(); ExperimenterGroup g_2 = new ExperimenterGroup(); e.setOmeName("j.b." + System.currentTimeMillis()); e.setFirstName(" Joe "); e.setLastName(" Brown "); e.setLdap(false); g_1.setName("DEFAULT: " + System.currentTimeMillis()); g_2.setName("NOTDEFAULT: " + System.currentTimeMillis()); g_1.setLdap(false); g_2.setLdap(false); // The instances must be unloaded to prevent spurious deletes! // Need versions. See: // http://trac.openmicroscopy.org.uk/ome/ticket/118 // http://trac.openmicroscopy.org.uk/ome/ticket/346 e = iUpdate.saveAndReturnObject(e); g_1 = iUpdate.saveAndReturnObject(g_1); g_2 = iUpdate.saveAndReturnObject(g_2); g_1.unload(); g_2.unload(); // No longer unloading the experimenter (3.0-Beta2.3) since // it is necessary to set the index on the map // e.unload(); e.linkExperimenterGroup(g_1); e.linkExperimenterGroup(g_2); iUpdate.saveObject(e); Experimenter test = (Experimenter) iQuery .findByQuery(" select e from Experimenter e " + " join fetch e.groupExperimenterMap m " + " join fetch m.parent p " + " where e.id = :id " + "and index(m) = 0", new Parameters().addId(e.getId())); assertNotNull(test.getPrimaryGroupExperimenterMap()); assertTrue(test.getPrimaryGroupExperimenterMap().parent().getName() .startsWith("DEFAULT")); } @Test(enabled = false, groups = "broken") // This test copies the previous one, changing the relationship // to image/pixels since they are not protected by the security // system. The answer is NO. This cannot be done. A loaded // Image with a loaded pixels collection must be used to save // a new Pixels, otherwise it can not properly set the "index" // field. public void test_image_pixels() throws Exception { Image img = new Image(); Pixels pix1 = new Pixels(); Pixels pix2 = new Pixels(); // The instances must be unloaded to prevent spurious deletes! // Need versions. See: // http://trac.openmicroscopy.org.uk/ome/ticket/118 // http://trac.openmicroscopy.org.uk/ome/ticket/346 img.setName("j.b." + System.currentTimeMillis()); img = iUpdate.saveAndReturnObject(img); img.unload(); pix1 = ObjectFactory.createPixelGraph(null); pix1.setImage(img); pix1 = iUpdate.saveAndReturnObject(pix1); pix2 = ObjectFactory.createPixelGraph(null); pix2.setImage(img); pix2 = iUpdate.saveAndReturnObject(pix2); // Rest deleted. Trying only to handle _backRefs. } @Test(enabled=false) /** attempt to reproduce an error seen on the client side */ public void test_save_array() throws Exception { loginRoot(); Long e = -1L; List<Experimenter> es = iQuery.findAll(Experimenter.class, null); for (Experimenter experimenter : es) { Long l = experimenter.getId(); if (!l.equals(new Long(0L))) { e = l; } } Project[] ps = new Project[] { new Project(), new Project(), new Project() }; for (Project project : ps) { project.setName("save-array"); } ps[0].getDetails().setOwner(new Experimenter(e, false)); ps[1].getDetails().setOwner(new Experimenter(e, false)); Dataset[] ds = new Dataset[] { new Dataset(), new Dataset() }; for (Dataset dataset : ds) { dataset.setName("save-array"); } for (Dataset dataset : ds) { for (Project project : ps) { project.linkDataset(dataset); } } iUpdate.saveAndReturnArray(ps); } // ~ Problems with values returned by update // ========================================================================= String err = "obj is loaded, set is not null AND not filled!"; @Test(enabled=false, groups = { "broken", "ticket:346" }) public void testAddingReturnsNonEmptySets() throws Exception { // using the add method works Pixels p = ObjectFactory.createPixelGraph(null); Thumbnail tb = ObjectFactory.createThumbnails(p); assertPixels(tb); // passing it in as a proxy is ok. p = ObjectFactory.createPixelGraph(null); p = iUpdate.saveAndReturnObject(p); p = new Pixels(p.getId(), false); tb = ObjectFactory.createThumbnails(p); tb.setPixels(p); assertPixels(tb); // issues with using the setter with a non-proxy p = ObjectFactory.createPixelGraph(null); tb = new Thumbnail(); tb.setMimeType(""); tb.setSizeX(1); tb.setSizeY(1); tb.setPixels(p); assertPixels(tb); } protected void assertPixels(Thumbnail tb) { Thumbnail test = iUpdate.saveAndReturnObject(tb); Thumbnail copy = iQuery.get(test.getClass(), test.getId()); assertFalse(err, copy.getPixels().isLoaded() && copy.getPixels().sizeOfThumbnails() == 0); assertFalse(err, test.getPixels().isLoaded() && test.getPixels().sizeOfThumbnails() == 0); } @Test(enabled=false, groups = { "broken", "ticket:346" }) public void testLinkingReturnsNonEmptySets() throws Exception { // using the link methods does what it's supposed to Project p = new Project(); p.setName("test"); Dataset d = new Dataset(); d.setName("test"); p.linkDataset(d); ProjectDatasetLink link = (ProjectDatasetLink) p.collectDatasetLinks( null).get(0); assertLink(link); // and using proxies works p = iUpdate.saveAndReturnObject(p); p = new Project(p.getId(), false); d = iUpdate.saveAndReturnObject(d); d = new Dataset(d.getId(), false); link = new ProjectDatasetLink(); link.link(p, d); assertLink(link); // but there are issues with passing in non-proxies when not using the // reverse methods. p = new Project(); p.setName("test"); d = new Dataset(); d.setName("test"); link = new ProjectDatasetLink(); link.link(p, d); assertLink(link); } @Test(enabled=false, groups = { "jobs", "ticket:667" }) public void testLinkingUnidirectionally() throws Exception { ITypes t = this.factory.getTypesService(); ImportJob job = new ImportJob(); OriginalFile file = new OriginalFile(); file.setPath(""); file.setHash(""); file.setName(""); file.setSize(0L); job.linkOriginalFile(file); job.setImageDescription("test"); job.setImageName("image name"); job.setUsername("root"); job.setGroupname("system"); job.setType("Test"); job.setMessage("foo"); job.setSubmitted(new Timestamp(System.currentTimeMillis())); job.setScheduledFor(new Timestamp(System.currentTimeMillis())); job.setStatus(t.getEnumeration(JobStatus.class, "Submitted")); iUpdate.saveObject(job); } @Test public void testRootCanDeleteObjectFromOtherGroup() { // This creates a user in a new group Experimenter e = loginNewUser(); Image i = new Image("rootCanDeleteObjectFromOtherGroup"); i = this.iUpdate.saveAndReturnObject(i); loginRootKeepGroup(); this.iUpdate.deleteObject(i); } @Test(enabled = false, groups = "ticket:1001") public void testOptimisticLockingOnLinks() { Experimenter e2 = loginNewUser(); Experimenter e1 = loginNewUser(); Project p1 = new Project("p1"); Dataset d1 = new Dataset("d1"); p1.linkDataset(d1); p1 = iUpdate.saveAndReturnObject(p1); ProjectDatasetLink link = new ProjectDatasetLink(); link.setParent(new Project(p1.getId(), false)); link .setChild(new Dataset(p1.linkedDatasetList().get(0).getId(), false)); iUpdate.saveObject(link); loginUser(e2.getOmeName()); p1.linkDataset(new Dataset("d2")); iUpdate.saveObject(p1); } @Test(enabled=false) public void testMultiThreadedPostJta() throws Exception { class T extends Thread { @Override public void run() { iUpdate.saveAndReturnObject(new Project("multi-thread-jta")); } }; List<T> ts = new ArrayList<T>(); for (int i = 0; i < 4; i++) { T t = new T(); ts.add(t); } for (T t : ts) { t.join(); } } @Test public void testPixelsIndexStartsWith0() throws Exception { Pixels p = ObjectFactory.createPixelGraph(null); // p.setDimensionOrder(iQuery.findAll(DimensionOrder.class, null).get(0)); Image i = iUpdate.saveAndReturnObject(p.getImage()); assertEquals(1, i.sizeOfPixels()); assertNotNull(i.collectPixels(null).get(0)); } @Test(groups ="ticket:1183") public void testSaveAndReturnWithAnnotation() { Project p = new Project("ticket:1183"); p.linkAnnotation(new CommentAnnotation()); p = iUpdate.saveAndReturnObject(p); p.setDescription("something else"); iUpdate.saveAndReturnObject(p); } @Test(groups ="ticket:1183") public void testImageWithObjectSettings() { Image i = ObjectFactory.createPixelGraph(null).getImage(); ObjectiveSettings os = new ObjectiveSettings(); Immersion imm = new Immersion("Air"); Correction corr = new Correction("Other"); Instrument instr = new Instrument(); Objective obj = new Objective(imm, corr, instr); os.setObjective(obj); os.setMedium(new Medium("Other")); os.setRefractiveIndex(0.0); i.setObjectiveSettings(os); i = iUpdate.saveAndReturnObject(i); assertNotNull(i.getObjectiveSettings()); i = iUpdate.saveAndReturnObject(i); assertNotNull(i.getObjectiveSettings()); i.setObjectiveSettings(new ObjectiveSettings(i.getObjectiveSettings().getId(),false)); i = iUpdate.saveAndReturnObject(i); } @Test(groups = "ticket:2547") public void testChannelMoveWithFullArrayGoesToEnd() { Pixels p = ObjectFactory.createPixelGraphWithChannels(null, 3); Image i = p.getImage(); i = iUpdate.saveAndReturnObject(i); p = i.getPrimaryPixels(); Set<Long> ids = new HashSet<Long>(); assertEquals(3, p.sizeOfChannels()); for (Channel ch : p.unmodifiableChannels()) { assertNotNull(ch); ids.add(ch.getId()); } // Now add another channel Pixels extra = ObjectFactory.createPixelGraph(null); p.addChannel(extra.getChannel(0)); i = iUpdate.saveAndReturnObject(i); p = i.getPrimaryPixels(); assertEquals(4, p.sizeOfChannels()); assertFalse(ids.contains(p.getChannel(3).getId())); } @Test(groups = "ticket:2547") public void testChannelMoveWithSpaceFillsSpace() { Pixels p = ObjectFactory.createPixelGraphWithChannels(null, 3); p.setChannel(1, null); Image i = p.getImage(); i = iUpdate.saveAndReturnObject(i); p = i.getPrimaryPixels(); Set<Long> ids = new HashSet<Long>(); assertEquals(3, p.sizeOfChannels()); assertNotNull(p.getChannel(0)); ids.add(p.getChannel(0).getId()); // Middle should be empty assertNull(p.getChannel(1)); assertNotNull(p.getChannel(2)); ids.add(p.getChannel(2).getId()); // Now add a channel to the front Pixels extra = ObjectFactory.createPixelGraph(null); Channel old = p.getChannel(0); p.setChannel(0, extra.getChannel(0)); p.setChannel(1, old); i = iUpdate.saveAndReturnObject(i); p = i.getPrimaryPixels(); assertEquals(3, p.sizeOfChannels()); assertFalse(ids.contains(p.getChannel(0).getId())); } @Test(groups = "ticket:2547") public void testChannelToSpaceChangesNothing() { Pixels p = ObjectFactory.createPixelGraphWithChannels(null, 3); p.setChannel(1, null); Image i = p.getImage(); i = iUpdate.saveAndReturnObject(i); p = i.getPrimaryPixels(); Set<Long> ids = new HashSet<Long>(); assertEquals(3, p.sizeOfChannels()); assertNotNull(p.getChannel(0)); ids.add(p.getChannel(0).getId()); // Middle should be empty assertNull(p.getChannel(1)); assertNotNull(p.getChannel(2)); ids.add(p.getChannel(2).getId()); // Now add a channel to the space Pixels extra = ObjectFactory.createPixelGraph(null); p.setChannel(1, extra.getChannel(0)); i = iUpdate.saveAndReturnObject(i); p = i.getPrimaryPixels(); assertEquals(3, p.sizeOfChannels()); assertFalse(ids.contains(p.getChannel(1).getId())); } @Test(groups = {"ticket:1679", "ticket:2547"}) public void testRoiShapeIndexIssue() { Image image = iUpdate.saveAndReturnObject(new_Image("")); Roi roi = new Roi(); roi.setImage(image); roi = iUpdate.saveAndReturnObject(roi); for (int i = 0; i < 3; i++) { Rectangle rect = new Rectangle(); rect.setX(19.0); rect.setY(21.0); rect.setWidth(10.0); rect.setHeight(10.0); rect.setTheZ(i); rect.setTheT(0); roi.addShape(rect); } roi = iUpdate.saveAndReturnObject(roi); Shape shape = roi.getShape(0); roi.removeShape(shape); roi = iUpdate.saveAndReturnObject(roi); iQuery.findAllByQuery("select r from Roi r join fetch r.shapes", null); } @Test(groups = "ticket:2547") public void testRemoveGroups() { Experimenter e = loginNewUser(); // Just used to create the group Experimenter e2 = loginNewUserInOtherUsersGroup(e); loginRoot(); ExperimenterGroup[] groups = iAdmin.containedGroups(e2.getId()); int j = -1; for (int i = 0; i < groups.length; i++) { if (groups[i].getId().equals(1)) { continue; } j = i; } iAdmin.removeGroups(e2, groups[j]); iAdmin.lookupGroups(); } /** * This method primarily used while walking through the debugger. */ @Test(groups = "ticket:3978") public void testSaveSingleAnnotation() { TagAnnotation tag = new TagAnnotation(); tag.setTextValue("ticket:3978"); tag = iUpdate.saveAndReturnObject(tag); // This prevents reloading annotationLinks tag.putAt(tag.ANNOTATIONLINKS, null); // This does not yet prevent reloading the previous event. tag.getDetails().shallowCopy(tag.getDetails().shallowCopy()); tag = iUpdate.saveAndReturnObject(tag); // EventContext ec = iAdmin.getEventContext(); // SessionStats stats = sessionManager.getSessionStats(ec.getCurrentSessionUuid()); // stats.sqlCount(); } protected void assertLink(ProjectDatasetLink link) { ProjectDatasetLink test = iUpdate.saveAndReturnObject(link); ProjectDatasetLink copy = iQuery.get(test.getClass(), test.getId()); assertFalse(err, copy.parent().isLoaded() && copy.parent().sizeOfDatasetLinks() == 0); assertFalse(err, copy.child().isLoaded() && copy.child().sizeOfProjectLinks() == 0); assertFalse(err, test.parent().isLoaded() && test.parent().sizeOfDatasetLinks() == 0); assertFalse(err, test.child().isLoaded() && test.child().sizeOfProjectLinks() == 0); } /** * iobject->details->events->sessions->events grows with each new * write action. These should be stripped periodically from return * values. */ @Test(groups = "ticket:3131") public void testEventsInSessionsAreCleared() throws Exception { LongAnnotation la = new LongAnnotation(); la.setNs("ticket:3131-A"); la = iUpdate.saveAndReturnObject(la); la.setNs("ticket:3131-B"); la = iUpdate.saveAndReturnObject(la); la.setNs("ticket:3131-C"); la = iUpdate.saveAndReturnObject(la); assertEquals(-1, la.getDetails().getUpdateEvent().getSession().sizeOfEvents()); indexObject(la); Search search = factory.createSearchService(); search.onlyType(LongAnnotation.class); search.byFullText("3131"); la = (LongAnnotation) search.next(); // In this case, the session is not even loaded. assertFalse(la.getDetails().getUpdateEvent().getSession().isLoaded()); /* assertEquals(-1, la.getDetails().getUpdateEvent().getSession().sizeOfEvents()); */ } @Test(groups = "ticket:2710") public void testRoiWithoutImage() { Roi r = new Roi(); iUpdate.saveAndReturnObject(r); } @Test public void testRoiWithStrokeWidth() { Roi r = new Roi(); Line l = new Line(); l.setStrokeWidth(new Length(1.0, UnitsLength.MILLIMETER)); r.addShape(l); iUpdate.saveAndReturnObject(r); } @Test(groups = "ticket:5639") public void testCatchDeadlockException() throws Exception { /* HibernateInterceptor ht = (HibernateInterceptor) this.applicationContext.getBean("hibernateHandler"); SQLErrorCodeSQLExceptionTranslator trans = (SQLErrorCodeSQLExceptionTranslator) ht.getJdbcExceptionTranslator(); if (trans == null) { trans = new SQLEr ht.setJdbcExceptionTranslator(jdbcExceptionTranslator) } String[] loserCodes = trans.getSqlErrorCodes().getDeadlockLoserCodes(); String[] newLoserCodes; if (loserCodes != null) { newLoserCodes = new String[loserCodes.length+1]; System.arraycopy(loserCodes, 0, newLoserCodes, 0, loserCodes.length); } else { newLoserCodes = new String[1]; } newLoserCodes[newLoserCodes.length-1] = "40P01"; trans.getSqlErrorCodes().setDeadlockLoserCodes(newLoserCodes); */ loginNewUser(); final Image i1 = iUpdate.saveAndReturnObject(new_Image("catchDeadLock1")); final Image i2 = iUpdate.saveAndReturnObject(new_Image("catchDeadLock2")); final CyclicBarrier barrier1 = new CyclicBarrier(2); final CyclicBarrier barrier2 = new CyclicBarrier(2); class T extends Thread { long first, second; String name; Exception e; public T(String name, long first, long second) { super(name); this.name = name; this.first = first; this.second = second; } @Override public void run() { try { executor.execute(loginAop.p, new Executor.SimpleWork(this, name) { @Transactional(readOnly = false) public Object doWork(Session session, ServiceFactory sf) { try { session.get(Image.class, first, LockOptions.UPGRADE); barrier1.await(5, TimeUnit.SECONDS); session.get(Image.class, second, LockOptions.UPGRADE); } catch (RuntimeException rt) { throw rt; } catch (Exception exc) { throw new RuntimeException(e); } finally { try { barrier2.await(5, TimeUnit.SECONDS); } catch (Exception e) { throw new RuntimeException(e); } } return null; } }); } catch (Exception e) { this.e = e; } } } final T t1 = new T("thread1", i1.getId(), i2.getId()); final T t2 = new T("thread2", i2.getId(), i1.getId()); t1.start(); t2.start(); t1.join(); t2.join(); if (t1.e == null) { assertEquals(TryAgain.class, t2.e.getClass()); } else if (t2.e == null) { assertEquals(TryAgain.class, t1.e.getClass()); } else { t1.e.printStackTrace(); t2.e.printStackTrace(); fail("Expected exactly one exception"); } } }