diff --git a/build.gradle b/build.gradle index 5f42e34e1..4f7cdac2b 100644 --- a/build.gradle +++ b/build.gradle @@ -38,7 +38,6 @@ ext { dependencies { testImplementation("org.testng:testng:7.5") testImplementation("jmock:jmock:1.+") - testImplementation('org.openmicroscopy:omero-common-test:5.7.4') api('org.openmicroscopy:omero-renderer:5.6.4') diff --git a/src/test/java/ome/testing/CreatePojosFixture.java b/src/test/java/ome/testing/CreatePojosFixture.java new file mode 100644 index 000000000..7d361b43e --- /dev/null +++ b/src/test/java/ome/testing/CreatePojosFixture.java @@ -0,0 +1,326 @@ +/* + * Copyright 2006-2014 University of Dundee. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ + +package ome.testing; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import ome.api.IAdmin; +import ome.api.IQuery; +import ome.api.IUpdate; +import ome.model.IObject; +import ome.model.annotations.DatasetAnnotationLink; +import ome.model.annotations.ImageAnnotationLink; +import ome.model.annotations.TagAnnotation; +import ome.model.annotations.TextAnnotation; +import ome.model.containers.Dataset; +import ome.model.containers.DatasetImageLink; +import ome.model.containers.Project; +import ome.model.containers.ProjectDatasetLink; +import ome.model.core.Image; +import ome.model.meta.Experimenter; +import ome.model.meta.ExperimenterGroup; +import ome.system.EventContext; +import ome.system.Login; +import ome.system.ServiceFactory; +import ome.util.ShallowCopy; + +/** + * setUp and tearDown must be called properly to make these work. + * + * @author josh + * + */ +public class CreatePojosFixture { + /** + * creates a new fixture logged in as a newly created user. requires an + * admin service factory in order to create user and should NOT be used from + * the server side. + */ + public static CreatePojosFixture withNewUser(ServiceFactory sf) { + CreatePojosFixture fixture = new CreatePojosFixture(); + + IAdmin rootAdmin = sf.getAdminService(); + String G_NAME = UUID.randomUUID().toString(); + fixture.g = new ExperimenterGroup(); + fixture.g.setName(G_NAME); + fixture.g.setLdap(false); + fixture.g = new ExperimenterGroup(rootAdmin.createGroup(fixture.g), + false); + + fixture.TESTER = "TESTER-" + UUID.randomUUID().toString(); + fixture.e = new Experimenter(); + fixture.e.setOmeName(fixture.TESTER); + fixture.e.setFirstName("Mr."); + fixture.e.setLastName("Allen"); + fixture.e.setLdap(false); + fixture.e = new Experimenter(rootAdmin.createUser(fixture.e, G_NAME), + false); + + Login testLogin = new Login(fixture.TESTER, "ome", G_NAME, "Test"); + ServiceFactory factory = new ServiceFactory(testLogin); + fixture.setServices(factory); + + fixture.init = true; + + return fixture; + } + + private CreatePojosFixture() { + } + + /** requires an admin service factory in order to create user. */ + public CreatePojosFixture(ServiceFactory factory) { + setServices(factory); + EventContext ec = iAdmin.getEventContext(); + e = new Experimenter(ec.getCurrentUserId(), false); + g = new ExperimenterGroup(ec.getCurrentGroupId(), false); + TESTER = ec.getCurrentUserName(); + init = true; + } + + private void setServices(ServiceFactory factory) { + iAdmin = factory.getAdminService(); + iQuery = factory.getQueryService(); + iUpdate = factory.getUpdateService(); + } + + protected IAdmin iAdmin; + + protected IQuery iQuery; + + protected IUpdate iUpdate; + + protected boolean init = false; + + protected List toAdd = new ArrayList(), + needId = new ArrayList(); + + public void createAllPojos() throws Exception { + init(); + projects(); + datasets(); + pdlinks(); + images(); + dilinks(); + annotations(); + } + + public void deleteAllPojos() throws Exception { + for (int i = toAdd.size() - 1; i >= 0; i--) { + iUpdate.deleteObject(toAdd.get(i)); + } + iAdmin.deleteExperimenter(e); + // TODO iAdmin.deleteGroup(g); + } + + public void init() { + if (!init) { + // moved to ctor + } + } + + public void pdi() { + projects(); + datasets(); + images(); + pdlinks(); + dilinks(); + } + + public void projects() { + init(); + pr9090 = project(null, "root project without links"); + pr9091 = project(null, "root project with own annotations"); + pr9092 = project(null, "root project with foreign annotations"); + pu9990 = project(e, "user project without links"); + pu9991 = project(e, "user project with own annotations"); + pu9992 = project(e, "user project with foreign annotations"); + saveAndClear(); + } + + public void datasets() { + init(); + dr7070 = dataset(null, "root dataset without links"); + dr7071 = dataset(null, "root dataset with own annotations"); + dr7072 = dataset(null, "root dataset with foreign annotations"); + du7770 = dataset(e, "user dataset without links"); + du7771 = dataset(e, "user dataset with own annotations"); + du7772 = dataset(e, "user dataset with foreign annotations"); + saveAndClear(); + } + + // TODO we aren't passing in Experimenter here + public void pdlinks() { + init(); + pdlink(pr9091, dr7071); + pdlink(pr9092, dr7071); + pdlink(pr9091, dr7072); + pdlink(pr9092, dr7072); + + pdlink(pu9991, du7771); + pdlink(pu9992, du7771); + pdlink(pu9991, du7772); + pdlink(pu9992, du7772); + saveAndClear(); + } + + public void images() { + init(); + ir5050 = image(null, ""); + ir5051 = image(null, ""); + ir5052 = image(null, ""); + iu5550 = image(e, ""); + iu5551 = image(e, ""); + iu5552 = image(e, ""); + // cgcpaths + iu5580 = image(e, ""); + iu5581 = image(e, ""); + iu5582 = image(e, ""); + iu5583 = image(e, ""); + iu5584 = image(e, ""); + iu5585 = image(e, ""); + iu5586 = image(e, ""); + iu5587 = image(e, ""); + iu5588 = image(e, ""); + saveAndClear(); + } + + public void dilinks() { + init(); + dilink(null, dr7071, ir5051); + dilink(null, dr7071, ir5052); + dilink(e, dr7072, ir5051); + dilink(e, dr7072, ir5052); + + dilink(null, du7771, iu5551); + dilink(null, du7771, iu5552); + dilink(e, du7772, iu5551); + dilink(e, du7772, iu5552); + saveAndClear(); + } + + public void annotations() { + init(); + datasetann(null, dr7071, "roots annotation"); + datasetann(e, dr7072, "users annotation"); + datasetann(null, du7771, "roots annotation"); + datasetann(e, du7772, "users annotation"); + + imageann(null, ir5051, "roots annotation"); + imageann(e, ir5052, "users annotation"); + imageann(null, iu5551, "roots annotation"); + imageann(e, iu5552, "users annotation"); + saveAndClear(); + } + + + // ~ Helpers + // ========================================================================= + + protected T push(T obj) { + toAdd.add(obj); + T copy = new ShallowCopy().copy(obj); + copy.unload(); + needId.add(copy); + return copy; + } + + protected void saveAndClear() { + IObject[] retVal = iUpdate.saveAndReturnArray(toAdd + .toArray(new IObject[toAdd.size()])); + IObject[] unloaded = needId.toArray(new IObject[needId.size()]); + for (int i = 0; i < retVal.length; i++) { + unloaded[i].setId(retVal[i].getId()); + } + toAdd.clear(); + needId.clear(); + } + + protected Project project(Experimenter owner, String name) { + Project p = new Project(); + p.getDetails().setOwner(owner); + p.setName(name); + p = push(p); + return p; + } + + protected Dataset dataset(Experimenter owner, String name) { + Dataset d = new Dataset(); + d.getDetails().setOwner(owner); + d.setName(name); + d = push(d); + return d; + } + + protected ProjectDatasetLink pdlink(Project prj, Dataset ds) { + ProjectDatasetLink link = new ProjectDatasetLink(); + link.link(prj, ds); + link = push(link); + return link; + } + + protected Image image(Experimenter e, String name) { + Image i = new Image(); + i.getDetails().setOwner(e); + i.setName(name); + i = push(i); + return i; + } + + protected DatasetImageLink dilink(Experimenter user, Dataset ds, Image i) { + DatasetImageLink link = new DatasetImageLink(); + link.link(ds, i); + link.getDetails().setOwner(user); + link = push(link); + return link; + } + + protected DatasetAnnotationLink datasetann(Experimenter user, Dataset d, + String name) { + TextAnnotation dann = new TagAnnotation(); + dann.setNs(name); + dann.getDetails().setOwner(user); + DatasetAnnotationLink link = new DatasetAnnotationLink(); + link.link(d.proxy(), dann); + link = push(link); + return link; + } + + protected ImageAnnotationLink imageann(Experimenter user, Image i, + String name) { + TextAnnotation iann = new TagAnnotation(); + iann.setNs(name); + iann.getDetails().setOwner(user); + ImageAnnotationLink link = new ImageAnnotationLink(); + link.link(i.proxy(), iann); + link = push(link); + return link; + } + + // static class Data { + public String TESTER; + + public Experimenter e; + + public ExperimenterGroup g; + + public Project pr9090, pr9091, pr9092, pu9990, pu9991, pu9992; + + public Dataset dr7070, dr7071, dr7072, du7770, du7771, du7772; + + public Image ir5050, ir5051, ir5052, iu5550, iu5551, iu5552, iu5580, + iu5581, iu5582, iu5583, iu5584, iu5585, iu5586, iu5587, iu5588; + + public List asIdList(IObject... iobjs) { + List list = new ArrayList(); + for (IObject i : iobjs) { + list.add(i.getId()); + } + return list; + } +} diff --git a/src/test/java/ome/testing/DataProviderBuilder.java b/src/test/java/ome/testing/DataProviderBuilder.java new file mode 100644 index 000000000..8e41a9e41 --- /dev/null +++ b/src/test/java/ome/testing/DataProviderBuilder.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2017 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 ome.testing; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import ome.model.IObject; + +import org.testng.annotations.DataProvider; + +/** + * Utility class for building return values for {@link DataProvider} methods. Instances of this builder can still be used even after + * {@link DataProviderBuilder#build()} has been called. + * @author m.t.b.carroll@dundee.ac.uk + * @since 5.4.1 + */ +public class DataProviderBuilder { + + private List> args = Collections.singletonList(Collections.emptyList()); + + /** + * Provide test methods with an additional argument that iterates through every value of an {@link java.lang.Enum}. + * @param enumClass the enumeration class whose values are to be iterated through + * @return this builder with the additional argument noted + */ + public DataProviderBuilder add(Class> enumClass) { + final Enum[] enums = enumClass.getEnumConstants(); + final List> newArgs = new ArrayList<>(args.size() * enums.length); + for (final List arg : args) { + for (final Enum e : enums) { + final List newArg = new ArrayList<>(arg.size() + 1); + newArg.addAll(arg); + newArg.add(e); + newArgs.add(newArg); + } + } + args = newArgs; + return this; + } + + /** + * Provide test methods with an additional argument that iterates through an instance of every given kind of model + * object. + * @param objectClasses the kinds of model object that are to be iterated through + * @return this builder with the additional argument noted + * @throws ReflectiveOperationException if the model object could not be instantiated + */ + public DataProviderBuilder add(Collection> objectClasses) + throws ReflectiveOperationException { + final List objects = new ArrayList<>(objectClasses.size()); + for (final Class objectClass : objectClasses) { + objects.add(objectClass.newInstance()); + } + final List> newArgs = new ArrayList<>(args.size() * objects.size()); + for (final List arg : args) { + for (final IObject o : objects) { + final List newArg = new ArrayList<>(arg.size() + 1); + newArg.addAll(arg); + newArg.add(o); + newArgs.add(newArg); + } + } + args = newArgs; + return this; + } + + /** + * Provide test methods with an additional argument that iterates through Boolean values. + * @param isNullable if {@code null} should be included along with {@code true} and {@code false} + * @return this builder with the additional argument noted + */ + public DataProviderBuilder addBoolean(boolean isNullable) { + final List> newArgs = new ArrayList<>(args.size() * (isNullable ? 3 : 2)); + for (final List arg : args) { + List newArg; + newArg = new ArrayList<>(arg.size() + 1); + newArg.addAll(arg); + newArg.add(Boolean.FALSE); + newArgs.add(newArg); + newArg = new ArrayList<>(arg.size() + 1); + newArg.addAll(arg); + newArg.add(Boolean.TRUE); + newArgs.add(newArg); + if (isNullable) { + newArg = new ArrayList<>(arg.size() + 1); + newArg.addAll(arg); + newArg.add(null); + newArgs.add(newArg); + } + } + args = newArgs; + return this; + } + + /** + * @return the return value of a {@link DataProvider} that provides the arguments noted by this builder + */ + public Object[][] build() { + final Object[][] argsArray = new Object[args.size()][]; + int index = 0; + for (final List arg : args) { + argsArray[index++] = arg.toArray(); + } + return argsArray; + } +} diff --git a/src/test/java/ome/testing/InterceptingServiceFactory.java b/src/test/java/ome/testing/InterceptingServiceFactory.java new file mode 100644 index 000000000..a7fd5343b --- /dev/null +++ b/src/test/java/ome/testing/InterceptingServiceFactory.java @@ -0,0 +1,193 @@ +/* + * Copyright 2008 Glencoe Software, Inc. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ + +package ome.testing; + +import ome.api.IAdmin; +import ome.api.IAnalysis; +import ome.api.IConfig; +import ome.api.IDelete; +import ome.api.ILdap; +import ome.api.IPixels; +import ome.api.IContainer; +import ome.api.IQuery; +import ome.api.IRenderingSettings; +import ome.api.IRepositoryInfo; +import ome.api.ISession; +import ome.api.IShare; +import ome.api.ITypes; +import ome.api.IUpdate; +import ome.api.JobHandle; +import ome.api.RawFileStore; +import ome.api.RawPixelsStore; +import ome.api.Search; +import ome.api.ServiceInterface; +import ome.api.ThumbnailStore; +import ome.conditions.ApiUsageException; +import ome.model.meta.Session; +import ome.system.ServiceFactory; +import omeis.providers.re.RenderingEngine; + +import org.aopalliance.intercept.MethodInterceptor; +import org.springframework.aop.framework.ProxyFactory; + +/** + * Wraps all returned services with the given interceptor; + * + * @author Josh Moore, josh at glencoesoftware.com + * @since 3.0-Beta3.1 + */ +public class InterceptingServiceFactory extends ServiceFactory { + + final ServiceFactory sf; + final MethodInterceptor[] interceptors; + + public InterceptingServiceFactory(ServiceFactory sf, MethodInterceptor... interceptors) { + this.sf = sf; + this.interceptors = interceptors; + } + + @SuppressWarnings("unchecked") + T wrap(T service) { + ProxyFactory factory = new ProxyFactory(); + factory.setInterfaces(service.getClass().getInterfaces()); + for (MethodInterceptor i : interceptors) { + factory.addAdvice(i); + } + factory.setTarget(service); + return (T) factory.getProxy(); + } + + @Override + protected String getDefaultContext() { + return null; + } + + @Override + public void closeSession() throws ApiUsageException { + sf.closeSession(); + } + + @Override + public JobHandle createJobHandle() { + return wrap(sf.createJobHandle()); + } + + @Override + public RawFileStore createRawFileStore() { + return wrap(sf.createRawFileStore()); + } + + @Override + public RawPixelsStore createRawPixelsStore() { + return wrap(sf.createRawPixelsStore()); + } + + @Override + public RenderingEngine createRenderingEngine() { + return wrap(sf.createRenderingEngine()); + } + + @Override + public Search createSearchService() { + return wrap(sf.createSearchService()); + } + + @Override + public ThumbnailStore createThumbnailService() { + return wrap(sf.createThumbnailService()); + } + + @Override + public IAdmin getAdminService() { + return wrap(sf.getAdminService()); + } + + @Override + public IAnalysis getAnalysisService() { + return wrap(sf.getAnalysisService()); + } + + @Override + public IConfig getConfigService() { + return wrap(sf.getConfigService()); + } + + @Override + public IDelete getDeleteService() { + return wrap(sf.getDeleteService()); + } + + @Override + public ILdap getLdapService() { + return wrap(sf.getLdapService()); + } + + @Override + public IPixels getPixelsService() { + return wrap(sf.getPixelsService()); + } + + @Override + public IContainer getContainerService() { + return wrap(sf.getContainerService()); + } + + @Override + public IQuery getQueryService() { + return wrap(sf.getQueryService()); + } + + @Override + public IRenderingSettings getRenderingSettingsService() { + return wrap(sf.getRenderingSettingsService()); + } + + @Override + public IRepositoryInfo getRepositoryInfoService() { + return wrap(sf.getRepositoryInfoService()); + } + + @Override + public T getServiceByClass(Class klass) { + return wrap(sf.getServiceByClass(klass)); + } + + @Override + public Session getSession() throws ApiUsageException { + return sf.getSession(); + } + + @Override + public ISession getSessionService() { + return wrap(sf.getSessionService()); + } + + @Override + public IShare getShareService() { + return wrap(sf.getShareService()); + } + + @Override + public ITypes getTypesService() { + return wrap(sf.getTypesService()); + } + + @Override + public IUpdate getUpdateService() { + return wrap(sf.getUpdateService()); + } + + @Override + public void setSession(Session session) throws ApiUsageException { + sf.setSession(session); + } + + @Override + public String toString() { + return sf.toString(); + } + +} diff --git a/src/test/java/ome/testing/MockServiceFactory.java b/src/test/java/ome/testing/MockServiceFactory.java new file mode 100644 index 000000000..3e4d19647 --- /dev/null +++ b/src/test/java/ome/testing/MockServiceFactory.java @@ -0,0 +1,113 @@ +/* + * ome.testing.MockServiceFactory + * + * Copyright 2006 University of Dundee. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ +package ome.testing; + +import ome.api.IAdmin; +import ome.api.IAnalysis; +import ome.api.IConfig; +import ome.api.IContainer; +import ome.api.IPixels; +import ome.api.IQuery; +import ome.api.ITypes; +import ome.api.IUpdate; +import ome.system.ServiceFactory; +import omeis.providers.re.RenderingEngine; + +import org.jmock.Mock; + +/** + * JMock'ed ServiceFactory whose public fields + * can be set like: + * + * + * mockServiceFactory.mockUpdate = mock(IUpdate.class); + * + * + * and later used like: + * + * + * mockServiceFactory.mockUpdate.expects( once() ).method( "saveObject" ); + * + * + * when the test-case subclasses {@link org.jmock.MockObjectTestCase}. + * + * @author Josh Moore      josh.moore@gmx.de + * @version 3.0 + * @since 3.0 + * @see org.jmock.MockObjectTestCase + */ +public class MockServiceFactory extends ServiceFactory { + + @Override + protected String getDefaultContext() { + return null; + } + + public Mock mockAdmin = new Mock(IAdmin.class); + + @Override + public IAdmin getAdminService() { + return (IAdmin) mockAdmin.proxy(); + } + + public Mock mockAnalysis = new Mock(IAnalysis.class); + + @Override + public IAnalysis getAnalysisService() { + return (IAnalysis) mockAnalysis.proxy(); + } + + public Mock mockPixels = new Mock(IPixels.class); + + @Override + public IPixels getPixelsService() { + return (IPixels) mockPixels.proxy(); + } + + public Mock mockConfig = new Mock(IConfig.class); + + @Override + public IConfig getConfigService() { + return (IConfig) mockConfig.proxy(); + } + + public Mock mockContainer = new Mock(IContainer.class); + + @Override + public IContainer getContainerService() { + return (IContainer) mockContainer.proxy(); + } + + public Mock mockQuery = new Mock(IQuery.class); + + @Override + public IQuery getQueryService() { + return (IQuery) mockQuery.proxy(); + } + + public Mock mockRendering = new Mock(RenderingEngine.class); + + public RenderingEngine getRenderingService() { + return (RenderingEngine) mockRendering.proxy(); + } + + public Mock mockUpdate = new Mock(IUpdate.class); + + @Override + public IUpdate getUpdateService() { + return (IUpdate) mockUpdate.proxy(); + } + + public Mock mockTypes = new Mock(ITypes.class); + + @Override + public ITypes getTypesService() { + return (ITypes) mockTypes.proxy(); + } + +} diff --git a/src/test/java/ome/testing/OMEData.java b/src/test/java/ome/testing/OMEData.java new file mode 100644 index 000000000..a6cba3665 --- /dev/null +++ b/src/test/java/ome/testing/OMEData.java @@ -0,0 +1,215 @@ +/* + * ome.testing + * + * Copyright 2006 University of Dundee. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ + +package ome.testing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; + +import javax.sql.DataSource; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.support.rowset.SqlRowSet; +import org.springframework.jdbc.support.rowset.SqlRowSetMetaData; + +/** + * abstract data container for testing. Sub-classes can set whatever values it + * would like in init(). After the OMEData instance is inserted + * into the test class by Spring, it SHOULD not be changed, but this is a matter + * of opionon. Setting the same seed value for two independent + * Data instances is also assumed to create identical values. + * + * @author Josh Moore      josh.moore@gmx.de + * @version 1.0 + * @since 1.0 + */ +public class OMEData { + + final static String emptyColl = "Collections may not be empty.\n" + + "You are currently trying to run a test on an OME database\n" + + "that does not appear to have the needed data.\n" + + "\n" + + "There must be at least one:\n" + + "project,dataset,image,experimenter,classification,category,category group,image annotation and dataset annotation\n" + + "\n" + + "Testing results would be unpredictable without test data.\n" + + "Please fill your database and retry."; + + private static Logger log = LoggerFactory.getLogger(OMEData.class); + + boolean initialized = false; + + DataSource ds; + + Map properties; + + Map values = new HashMap(); + + long seed; + + Random rnd; + + String[] files = new String[] {"test_data.properties"}; + + public void setDataSource(DataSource dataSource) { + this.ds = dataSource; + } + + public OMEData() { + init(); + } + + public OMEData(String[] files) { + this.files = files; + init(); + } + + void init() { + properties = SqlPropertiesParser.parse(files); + seed = System.currentTimeMillis(); + rnd = new Random(seed); + } + + /* allows for storing arbitrary objects in data */ + public void put(String propertyKey, Object value) { + toCache(propertyKey, value); + } + + public List get(String propertyKey) { + + if (inCache(propertyKey)) { + return (List) fromCache(propertyKey); + } + + Object obj = properties.get(propertyKey); + if (obj == null) { + return null; + } else if (obj instanceof List) { + toCache(propertyKey, obj); + return (List) obj; + } else if (obj instanceof String) { + String sql = (String) obj; + List result = runSql(sql); + toCache(propertyKey, result); + return result; + } else { + throw new RuntimeException("Error in properties. Not expecting " + + obj == null ? null : obj.getClass().getName()); + } + } + + List getRandomNumber(List l, Number number) { + + if (number == null) { + return null; + } + + if (l == null || l.size() == 0) { + log.warn(emptyColl); + return null; + } + + List ordered = new ArrayList(l); + List result = new ArrayList(); + + while (ordered.size() > 0 && result.size() < number.longValue()) { + int choice = randomChoice(ordered.size()); + result.add(ordered.remove(choice)); + } + + return result; + + } + + public List getMax(String propertyKey, int maximum) { + List l = get(propertyKey); + return getRandomNumber(l, new Integer(maximum)); + + } + + public List getPercent(String propertyKey, double percent) { + List l = get(propertyKey); + return getRandomNumber(l, new Double(l.size() * percent)); + + } + + public Object getRandom(String propertyKey) { + List l = get(propertyKey); + List result = getRandomNumber(l, new Integer(1)); + + if (result == null || result.size() < 1) { + return null; + } + + return result.get(0); + } + + public Object getFirst(String propertyKey) { + List l = get(propertyKey); + + if (l == null || l.size() == 0) { + log.warn(emptyColl); + return null; + } + + return l.get(0); + } + + boolean inCache(String key) { + return values.containsKey(key); + } + + void toCache(String key, Object value) { + values.put(key, value); + } + + Object fromCache(String key) { + return values.get(key); + } + + /** + * returns a list of results from the sql statement. if there is more than + * one column in the result set, a map from column name to Object is + * returned, else the Object itself. + * + * @param sql + * @return + */ + List runSql(String sql) { + JdbcTemplate jt = new JdbcTemplate(ds); + SqlRowSet rows = jt.queryForRowSet(sql); + List result = new ArrayList(); + while (rows.next()) { + SqlRowSetMetaData meta = rows.getMetaData(); + int count = meta.getColumnCount(); + if (count > 1) { + Map cols = new HashMap(); + String[] names = meta.getColumnNames(); + for (int i = 0; i < names.length; i++) { + cols.put(names[i], rows.getObject(names[i])); + } + result.add(cols); + } else { + result.add(rows.getObject(1)); + } + } + log.debug("SQL:" + sql + "\n\nResult:" + result); + return result; + } + + public int randomChoice(int size) { + double value = (size - 1) * rnd.nextDouble(); + return (new Double(value)).intValue(); + } + +} diff --git a/src/test/java/ome/testing/ObjectFactory.java b/src/test/java/ome/testing/ObjectFactory.java new file mode 100644 index 000000000..94c38ea46 --- /dev/null +++ b/src/test/java/ome/testing/ObjectFactory.java @@ -0,0 +1,225 @@ +/* + * $Id$ + * + * Copyright 2006 University of Dundee. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ +package ome.testing; + +import ome.model.core.Channel; +import ome.model.core.Image; +import ome.model.core.LogicalChannel; +import ome.model.core.OriginalFile; +import ome.model.core.Pixels; +import ome.model.core.PlaneInfo; +import ome.model.display.ChannelBinding; +import ome.model.display.PlaneSlicingContext; +import ome.model.display.QuantumDef; +import ome.model.display.RenderingDef; +import ome.model.display.Thumbnail; +import ome.model.enums.AcquisitionMode; +import ome.model.enums.DimensionOrder; +import ome.model.enums.Family; +import ome.model.enums.PhotometricInterpretation; +import ome.model.enums.PixelsType; +import ome.model.enums.RenderingModel; +import ome.model.enums.UnitsLength; +import ome.model.enums.UnitsTime; +import ome.model.stats.StatsInfo; +import ome.model.units.Length; +import ome.model.units.Time; + +/** + * these method serve as a both client and test data store. An object that has + * no id is "new"; an object with an id is detached and can represent something + * serialized from IQuery. + * + * NOTE: this is a bit dangerous, causing model builds to fail sometimes. where + * else could it live? + */ +public class ObjectFactory { + + public static OriginalFile createFile() { + OriginalFile ofile = new OriginalFile(); + ofile.setName("testing"); + ofile.setPath("/dev/null"); + ofile.setHash("abc"); + ofile.setSize(1L); + ofile.setMimetype("text/plain"); + + return ofile; + } + + public static Thumbnail createThumbnails(Pixels p) { + Thumbnail t = new Thumbnail(); + t.setMimeType("txt"); + t.setSizeX(1); + t.setSizeY(1); + p.addThumbnail(t); + return t; + } + + public static Pixels createPixelGraph(Pixels example) { + return createPixelGraphWithChannels(example, 1); + } + + public static Channel createChannel(Channel example) { + Channel ch = new Channel(); + LogicalChannel lc = new LogicalChannel(); + StatsInfo si = new StatsInfo(); + PhotometricInterpretation pi = new PhotometricInterpretation("RGB"); + lc.setPhotometricInterpretation(pi); + si.setGlobalMax(0.0); + si.setGlobalMin(0.0); + ch.setStatsInfo(si); + ch.setLogicalChannel(lc); + return ch; + } + + public static Pixels createPixelGraphWithChannels(Pixels example, int channelCount) { + + Pixels p = new Pixels(); + PhotometricInterpretation pi = new PhotometricInterpretation(); + AcquisitionMode mode = new AcquisitionMode(); + PixelsType pt = new PixelsType(); + DimensionOrder dO = new DimensionOrder(); + Image i = new Image(); + Channel[] c = new Channel[channelCount]; + LogicalChannel[] lc = new LogicalChannel[channelCount]; + StatsInfo[] si = new StatsInfo[channelCount]; + PlaneInfo[] pl = new PlaneInfo[channelCount]; + for (int w = 0; w < channelCount; w++) { + c[w] = new Channel(); + lc[w] = new LogicalChannel(); + si[w] = new StatsInfo(); + pl[w] = new PlaneInfo(); + } + + if (example != null) { + p.setId(example.getId()); + p.setVersion(example.getVersion()); + + // everything else unloaded. + pt.setId(example.getPixelsType().getId()); + pt.unload(); + dO.setId(example.getDimensionOrder().getId()); + dO.unload(); + i.setId(example.getImage().getId()); + i.unload(); + for (int w = 0; w < channelCount; w++) { + c[w].setId(example.getChannel(w).getId()); + c[w].unload(); + } + // Not needed but useful + p.addPlaneInfo(example.iteratePlaneInfo().next()); + (p.iteratePlaneInfo().next()).unload(); + } + + else { + + mode.setValue("Wide-field"); + pi.setValue("RGB"); + + pt.setValue("int8"); + pt.setBitSize(8); + + dO.setValue("XYZTC"); + + for (int w = 0; w < channelCount; w++) { + c[w].setPixels(p); + lc[w].setPhotometricInterpretation(pi); + + // Not required but useful + si[w].setGlobalMax(new Double(0.0)); + si[w].setGlobalMin(new Double(0.0)); + c[w].setLogicalChannel(lc[w]); + c[w].setStatsInfo(si[w]); + pl[w].setTheC(new Integer(w)); + pl[w].setTheZ(new Integer(0)); + pl[w].setTheT(new Integer(0)); + + Time deltaT = new Time(0.0, UnitsTime.SECOND); + pl[w].setDeltaT(deltaT); + p.addPlaneInfo(pl[w]); + + } + + i.setName("test"); + i.addPixels(p); + + } + + Length mm1 = new Length(1.0, UnitsLength.MILLIMETER); + p.setSizeX(new Integer(1)); + p.setSizeY(new Integer(1)); + p.setSizeZ(new Integer(1)); + p.setSizeC(new Integer(1)); + p.setSizeT(new Integer(1)); + p.setPhysicalSizeX(mm1); + p.setPhysicalSizeY(mm1); + p.setPhysicalSizeZ(mm1); + p.setSha1("09bc7b2dcc9a510f4ab3a40c47f7a4cb77954356"); // "pixels" + p.setPixelsType(pt); + p.setDimensionOrder(dO); + p.setImage(i); + + for (int w = 0; w < channelCount; w++) { + p.addChannel(c[w]); + } + + return p; + } + + public static ChannelBinding createChannelBinding() { + // Prereqs for binding + + Family family = new Family(); + family.setValue("linear"); + + ChannelBinding binding = new ChannelBinding(); + binding.setActive(Boolean.FALSE); + binding.setCoefficient(new Double(1)); + binding.setAlpha(new Integer(1)); + binding.setBlue(new Integer(1)); + binding.setGreen(new Integer(1)); + binding.setRed(new Integer(1)); + binding.setFamily(family); + binding.setInputEnd(new Double(1.0)); + binding.setInputStart(new Double(1.0)); + binding.setNoiseReduction(Boolean.FALSE); + + return binding; + } + + public static RenderingDef createRenderingDef() { + // Prereqs for RenderingDef + RenderingModel model = new RenderingModel(); + model.setValue("rgb"); + + QuantumDef qdef = new QuantumDef(); + qdef.setBitResolution(new Integer(1)); + qdef.setCdEnd(new Integer(1)); + qdef.setCdStart(new Integer(1)); + + RenderingDef def = new RenderingDef(); + def.setDefaultT(new Integer(1)); + def.setDefaultZ(new Integer(1)); + def.setModel(model); + def.setPixels(ObjectFactory.createPixelGraph(null)); + def.setQuantization(qdef); + + return def; + } + + public static PlaneSlicingContext createPlaneSlicingContext() { + PlaneSlicingContext enhancement = new PlaneSlicingContext(); + enhancement.setConstant(Boolean.FALSE); + enhancement.setLowerLimit(new Integer(1)); + enhancement.setPlanePrevious(new Integer(1)); + enhancement.setPlaneSelected(new Integer(1)); + enhancement.setUpperLimit(new Integer(1)); + + return enhancement; + + } +} diff --git a/src/test/java/ome/testing/Report.java b/src/test/java/ome/testing/Report.java new file mode 100644 index 000000000..e0b7820b5 --- /dev/null +++ b/src/test/java/ome/testing/Report.java @@ -0,0 +1,93 @@ +/* + * $Id$ + * + * Copyright 2008 Glencoe Software, Inc. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ + +package ome.testing; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.jamonapi.MonitorFactory; + +/** + * Used as a simple print out of {@link MonitorFactory} results. + * + * @author Josh Moore, josh at glencoesoftware.com + * @since 3.0-Beta3 + */ +public class Report { + + static int LABEL = 0; + static int HITS = 1; + static int AVG = 2; + static int TOTAL = 3; + static int STDDEV = 4; + static int LASTVALUE = 5; + static int MIN = 6; + static int MAX = 7; + static int ACTIVE = 8; + static int AVGACTIVE = 9; + static int MAXACTIVE = 10; + static int FIRSTACCESS = 11; + static int LASTACCESS = 12; + + String[] header; + Object[][] data; + + /** + * Saves the current data from {@link MonitorFactory} and then resets all + * values. + */ + public Report() { + header = MonitorFactory.getHeader(); + data = MonitorFactory.getData(); + MonitorFactory.reset(); + } + + @Override + public String toString() { + if (header == null) { + return "====== No report ======="; + } + int[] labels = new int[] { LABEL, AVG, MIN, MAX, TOTAL, HITS }; + StringBuilder sb = new StringBuilder(); + for (int l : labels) { + sb.append(header[l]); + for (int i = 0; i < 8 - header[l].length(); i++) { + sb.append(" "); + } + sb.append("\t"); + } + sb.append("\n"); + + Map ordering = new HashMap(); + for (int i = 0; i < data.length; i++) { + StringBuilder line = new StringBuilder(); + for (int l : labels) { + Object d = data[i][l]; + if (d instanceof Double) { + line.append(String.format("%3.2e\t", (Double) d)); + } else { + line.append(d + "\t"); + } + } + line.append("\n"); + ordering.put((String) data[i][LABEL], line.toString()); + } + List keys = new ArrayList(ordering.keySet()); + Collections.sort(keys); + + for (String key : keys) { + sb.append(ordering.get(key)); + } + + return sb.toString(); + } + +} diff --git a/src/test/java/ome/testing/SqlPropertiesParser.java b/src/test/java/ome/testing/SqlPropertiesParser.java new file mode 100644 index 000000000..c9ab0196a --- /dev/null +++ b/src/test/java/ome/testing/SqlPropertiesParser.java @@ -0,0 +1,116 @@ +/* + * ome.testing.SqlPropertiesParser + * + * Copyright 2006 University of Dundee. All rights reserved. + * Use is subject to license terms supplied in LICENSE.txt + */ + +package ome.testing; + +import java.io.InputStream; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; + +/** + * utility to parse a properties file. See "resources/test_queries.properties" + * for an explanation of the format. + * + * @author Josh Moore      josh.moore@gmx.de + * @version 1.0 + * @since 1.0 + */ +public abstract class SqlPropertiesParser { + + private static Logger log = LoggerFactory.getLogger(SqlPropertiesParser.class); + + static class MyPropertyPlaceholderConfigurer extends + PropertyPlaceholderConfigurer { + @Override + protected void processProperties( + ConfigurableListableBeanFactory beanFactoryToProcess, + Properties props) throws BeansException { + } + + public String doIt(String property) { + try { + return parseStringValue(property, this.mergeProperties(), + new HashSet()); + } catch (Exception e) { + throw new RuntimeException( + "Error in evaluating embedded properties.", e); + } + } + } + + static MyPropertyPlaceholderConfigurer prc = new MyPropertyPlaceholderConfigurer(); + + protected static void load(Properties props, String filename) { + InputStream is = SqlPropertiesParser.class.getClassLoader() + .getResourceAsStream(filename); + + try { + props.load(is); + + } catch (Exception e) { + throw new RuntimeException("Failed to parse properties file " + + filename, e); + } finally { + if (null != is) { + try { + is.close(); + } catch (Exception e) { + throw new RuntimeException( + "Failed to close properties file " + filename, e); + } + } + } + + } + + /* last one wins */ + public static Map parse(String[] filenames) { + // Get strings from files + Map result = new HashMap(); + Properties props = new Properties(); + for (int i = 0; i < filenames.length; i++) { + load(props, filenames[i]); + } + + // Put them into a map converting embedded ${...} + prc.setProperties(props); + prc.postProcessBeanFactory(null); + for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { + String name = (String) en.nextElement(); + result.put(name, prc.doIt(props.getProperty(name))); + } + + // Do extra parsing where necessary + for (Iterator it = result.keySet().iterator(); it.hasNext();) { + String name = (String) it.next(); + String value = (String) result.get(name); + if (!value.startsWith("select")) { + String[] strValues = value.split("\\s*,\\s*"); + Long[] longValues = new Long[strValues.length]; + for (int i = 0; i < strValues.length; i++) { + longValues[i] = Long.valueOf(strValues[i]); + } + result.put(name, Arrays.asList(longValues)); + } + } + + return result; + + } +}