Java tutorial
/* * The Gemma project * * Copyright (c) 2006 University of British Columbia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package ubic.gemma.testing; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.sql.DataSource; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.SessionFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.io.Resource; import org.springframework.core.io.support.EncodedResource; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.TestingAuthenticationProvider; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests; import org.springframework.test.jdbc.SimpleJdbcTestUtils; import ubic.gemma.genome.taxon.service.TaxonService; import ubic.gemma.model.association.BioSequence2GeneProduct; import ubic.gemma.model.common.auditAndSecurity.Contact; import ubic.gemma.model.common.description.BibliographicReference; import ubic.gemma.model.common.description.DatabaseEntry; import ubic.gemma.model.common.description.ExternalDatabase; import ubic.gemma.model.common.description.ExternalDatabaseService; import ubic.gemma.model.common.quantitationtype.QuantitationType; import ubic.gemma.model.expression.arrayDesign.ArrayDesign; import ubic.gemma.model.expression.arrayDesign.TechnologyType; import ubic.gemma.model.expression.bioAssay.BioAssay; import ubic.gemma.model.expression.biomaterial.BioMaterial; import ubic.gemma.model.expression.designElement.CompositeSequence; import ubic.gemma.model.expression.experiment.ExpressionExperiment; import ubic.gemma.model.genome.Gene; import ubic.gemma.model.genome.Taxon; import ubic.gemma.model.genome.biosequence.BioSequence; import ubic.gemma.model.genome.gene.GeneProduct; import ubic.gemma.model.genome.sequenceAnalysis.BlatResult; import ubic.gemma.persistence.Persister; import ubic.gemma.security.authentication.UserManager; import ubic.gemma.util.CompassUtils; /** * subclass for tests that need the container and use the database * * @author pavlidis * @version $Id: BaseSpringContextTest.java,v 1.17 2013/05/09 18:29:35 ptan Exp $ */ @ContextConfiguration(locations = { "classpath*:ubic/gemma/testDataSource.xml", "classpath*:ubic/gemma/applicationContext-security.xml", "classpath*:ubic/gemma/applicationContext-search.xml", "classpath*:ubic/gemma/applicationContext-hibernate.xml", "classpath*:ubic/gemma/applicationContext-component-scan.xml", "classpath*:ubic/gemma/testContext-jms.xml", "classpath*:ubic/gemma/applicationContext-serviceBeans.xml", "classpath*:ubic/gemma/applicationContext-schedule.xml" }) public abstract class BaseSpringContextTest extends AbstractJUnit4SpringContextTests implements InitializingBean { protected static final int RANDOM_STRING_LENGTH = 10; protected static final int TEST_ELEMENT_COLLECTION_SIZE = 5; private static ArrayDesign readOnlyad = null; private static ExpressionExperiment readOnlyee = null; @Autowired protected ExternalDatabaseService externalDatabaseService; protected HibernateDaoSupport hibernateSupport = new HibernateDaoSupport() { }; protected Log log = LogFactory.getLog(getClass()); @Autowired protected Persister persisterHelper; /** * The SimpleJdbcTemplate that this base class manages, available to subclasses. (Datasource; autowired at setteer) */ protected SimpleJdbcTemplate simpleJdbcTemplate; @Autowired protected TaxonService taxonService; private AuthenticationTestingUtil authenticationTestingUtil; @Autowired protected PersistentDummyObjectHelper testHelper; private String sqlScriptEncoding; /** * @param commonName e.g. mouse,human,rat * @return */ public Taxon getTaxon(String commonName) { return this.taxonService.findByCommonName(commonName); } /** * @throws Exception */ @Override final public void afterPropertiesSet() throws Exception { SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL); hibernateSupport.setSessionFactory(this.getBean(SessionFactory.class)); CompassUtils.deleteCompassLocks(); this.authenticationTestingUtil = new AuthenticationTestingUtil(); this.authenticationTestingUtil.setUserManager(this.getBean(UserManager.class)); runAsAdmin(); } /** * Run as a regular user. * * @param userName */ protected final void runAsUser(String userName) { authenticationTestingUtil.switchToUser(this.applicationContext, userName); } /** * Elevate to administrative privileges (tests normally run this way, this can be used to set it back if you called * runAsUser). This gets called before each test, no need to run it yourself otherwise. */ protected final void runAsAdmin() { authenticationTestingUtil.grantAdminAuthority(this.applicationContext); } /** * Set the DataSource, typically provided via Dependency Injection. */ @Autowired public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); } /** * @param persisterHelper the persisterHelper to set */ public void setPersisterHelper(Persister persisterHelper) { this.persisterHelper = persisterHelper; } /** * Specify the encoding for SQL scripts, if different from the platform encoding. * * @see #executeSqlScript */ public void setSqlScriptEncoding(String sqlScriptEncoding) { this.sqlScriptEncoding = sqlScriptEncoding; } public void setTaxonService(TaxonService taxonService) { this.taxonService = taxonService; } /** * Convenience shortcut for RandomStringUtils.randomAlphabetic( 10 ) (or something similar to that) * * @return */ public String randomName() { return RandomStringUtils.randomAlphabetic(10); } protected void addTestAnalyses(ExpressionExperiment ee) { testHelper.addTestAnalyses(ee); } /** * Count the rows in the given table. * * @param tableName table name to count rows in * @return the number of rows in the table */ protected int countRowsInTable(String tableName) { return SimpleJdbcTestUtils.countRowsInTable(this.simpleJdbcTemplate, tableName); } /** * Convenience method for deleting all rows from the specified tables. Use with caution outside of a transaction! * * @param names the names of the tables from which to delete * @return the total number of rows deleted from all specified tables */ protected int deleteFromTables(String... names) { return SimpleJdbcTestUtils.deleteFromTables(this.simpleJdbcTemplate, names); } /** * Execute the given SQL script. Use with caution outside of a transaction! * <p> * The script will normally be loaded by classpath. There should be one statement per line. Any semicolons will be * removed. <b>Do not use this method to execute DDL if you expect rollback.</b> * * @param sqlResourcePath the Spring resource path for the SQL script * @param continueOnError whether or not to continue without throwing an exception in the event of an error * @throws DataAccessException if there is an error executing a statement and continueOnError was <code>false</code> */ protected void executeSqlScript(String sqlResourcePath, boolean continueOnError) throws DataAccessException { Resource resource = this.applicationContext.getResource(sqlResourcePath); SimpleJdbcTestUtils.executeSqlScript(this.simpleJdbcTemplate, new EncodedResource(resource, this.sqlScriptEncoding), continueOnError); } /** * Convenience method to obtain instance of any bean by name. Use this only when necessary, you should wire your * tests by injection instead. * * @param name * @return */ protected <T> T getBean(String name, Class<T> t) { try { return this.applicationContext.getBean(name, t); } catch (BeansException e) { throw new RuntimeException(e); } catch (Exception e) { throw new RuntimeException(e); } } /** * @param t * @return */ protected <T> T getBean(Class<T> t) { return this.applicationContext.getBean(t); } /** * @return */ protected Gene getTestPeristentGene() { return testHelper.getTestPeristentGene(); } public Gene getTestPeristentGene(Taxon taxon) { return testHelper.getTestPeristentGene(taxon); } /** * Convenience method to provide an ArrayDesign that can be used to fill non-nullable associations in test objects. * The ArrayDesign is provided with some CompositeSequenece DesignElements if desired. If composite seequences are * created, they are each associated with a single generated Reporter. * * @param numCompositeSequences The number of CompositeSequences to populate the ArrayDesign with. * @param randomNames If true, probe names will be random strings; otherwise they will be 0_at....N_at * @return */ protected ArrayDesign getTestPersistentArrayDesign(int numCompositeSequences, boolean randomNames) { return testHelper.getTestPersistentArrayDesign(numCompositeSequences, randomNames, true); } public Collection<BioSequence2GeneProduct> getTestPersistentBioSequence2GeneProducts(BioSequence bioSequence) { return testHelper.getTestPersistentBioSequence2GeneProducts(bioSequence); } /** * Convenience method to provide an ArrayDesign that can be used to fill non-nullable associations in test objects. * The ArrayDesign is provided with some CompositeSequenece DesignElements if desired. If composite seequences are * created, they are each associated with a single generated Reporter. * * @param numCompositeSequences The number of CompositeSequences to populate the ArrayDesign with. * @param randomNames If true, probe names will be random strings; otherwise they will be 0_at....N_at * @param doSequence add sequences to the array design that is created. Faster to avoid if you can. * @return */ protected ArrayDesign getTestPersistentArrayDesign(int numCompositeSequences, boolean randomNames, boolean doSequence, boolean readOnly) { if (readOnly) { if (readOnlyad == null) { readOnlyad = testHelper.getTestPersistentArrayDesign(numCompositeSequences, randomNames, doSequence); } return readOnlyad; } return testHelper.getTestPersistentArrayDesign(numCompositeSequences, randomNames, doSequence); } /** * Convenience method to provide an ArrayDesign that can be used to fill non-nullable associations in test objects. * * @param probeNames will be assigned to each CompositeSequence in the ArrayDesign * @param taxon of the ArrayDesign * @return ArrayDesign with no TechnologyType */ protected ArrayDesign getTestPersistentArrayDesign(List<String> probeNames, Taxon taxon) { ArrayDesign ad = ArrayDesign.Factory.newInstance(); ad.setShortName("Generic_" + taxon.getCommonName() + "_" + RandomStringUtils.randomAlphabetic(10)); ad.setName("Generic test platform for " + taxon.getCommonName()); ad.setTechnologyType(TechnologyType.NONE); ad.setPrimaryTaxon(taxon); for (int i = 0; i < probeNames.size(); i++) { // Reporter reporter = Reporter.Factory.newInstance(); CompositeSequence compositeSequence = CompositeSequence.Factory.newInstance(); compositeSequence.setName(probeNames.get(i)); // compositeSequence.getComponentReporters().add( reporter ); compositeSequence.setArrayDesign(ad); ad.getCompositeSequences().add(compositeSequence); BioSequence bioSequence = getTestPersistentBioSequence(); compositeSequence.setBiologicalCharacteristic(bioSequence); bioSequence.setBioSequence2GeneProduct(this.getTestPersistentBioSequence2GeneProducts(bioSequence)); } for (CompositeSequence cs : ad.getCompositeSequences()) { cs.setArrayDesign(ad); } assert (ad.getCompositeSequences().size() == probeNames.size()); return (ArrayDesign) persisterHelper.persist(ad); } /** * @return EE with no data; just bioassays, biomaterials, quantitation types and (minimal) array designs. */ protected ExpressionExperiment getTestPersistentBasicExpressionExperiment() { return testHelper.getTestPersistentBasicExpressionExperiment(); } protected BibliographicReference getTestPersistentBibliographicReference(String accession) { return testHelper.getTestPersistentBibliographicReference(accession); } /** * Convenience method to provide a DatabaseEntry that can be used to fill non-nullable associations in test objects. * * @return */ protected BioAssay getTestPersistentBioAssay(ArrayDesign ad) { return testHelper.getTestPersistentBioAssay(ad); } /** * Convenience method to provide a DatabaseEntry that can be used to fill non-nullable associations in test objects. * * @return */ protected BioAssay getTestPersistentBioAssay(ArrayDesign ad, BioMaterial bm) { return testHelper.getTestPersistentBioAssay(ad, bm); } /** * @return */ protected BioMaterial getTestPersistentBioMaterial() { return testHelper.getTestPersistentBioMaterial(); } /** * @return */ protected BioMaterial getTestPersistentBioMaterial(Taxon tax) { return testHelper.getTestPersistentBioMaterial(tax); } /** * @return */ protected BioSequence getTestPersistentBioSequence() { return testHelper.getTestPersistentBioSequence(); } /** * @param querySequence * @return */ protected BlatResult getTestPersistentBlatResult(BioSequence querySequence) { return testHelper.getTestPersistentBlatResult(querySequence); } /** * Convenience method to get a (fairly) complete randomly generated persisted expression experiment. * * @param readOnly If the test only needs to read, a new data set might not be created. * @return */ protected ExpressionExperiment getTestPersistentCompleteExpressionExperiment(boolean readOnly) { if (readOnly) { if (readOnlyee == null) { log.info("Initializing test expression experimement (one-time for read-only tests)"); readOnlyee = testHelper.getTestExpressionExperimentWithAllDependencies(); } return readOnlyee; } ExpressionExperiment ee = testHelper.getTestExpressionExperimentWithAllDependencies(); return ee; } /** * Convenience method to get a (fairly) complete randomly generated persisted expression experiment. * * @param doSequence Should the Arraydesign sequence information be filled in? (slower) * @return */ protected ExpressionExperiment getTestPersistentCompleteExpressionExperimentWithSequences() { return testHelper.getTestExpressionExperimentWithAllDependencies(true); } /** * Convenience method to provide a Contact that can be used to fill non-nullable associations in test objects. * * @return */ protected Contact getTestPersistentContact() { return testHelper.getTestPersistentContact(); } /** * Change the number of elements created in collections (basically controls the size of test data sets). This * needn't be called unless the test needs larger data sets. FCall {@link resetTestCollectionSize} after you are * done. * * @param size */ protected void setTestCollectionSize(int size) { testHelper.setTestElementCollectionSize(size); } /** * Restore to default. */ protected void resetTestCollectionSize() { testHelper.resetTestElementCollectionSize(); } /** * Get a database entry from a fictitious database. * * @return */ protected DatabaseEntry getTestPersistentDatabaseEntry() { return getTestPersistentDatabaseEntry(null, RandomStringUtils.randomAlphabetic(10)); } /** * Convenience method to provide a DatabaseEntry that can be used to fill non-nullable associations in test objects. * The accession and ExternalDatabase name are set to random strings. * * @return */ protected DatabaseEntry getTestPersistentDatabaseEntry(ExternalDatabase ed) { return getTestPersistentDatabaseEntry(null, ed); } protected DatabaseEntry getTestPersistentDatabaseEntry(String ed) { return getTestPersistentDatabaseEntry(null, ed); } /** * Convenience method to provide a DatabaseEntry that can be used to fill non-nullable associations in test objects. * The accession and ExternalDatabase name are set to random strings. * * @return */ protected DatabaseEntry getTestPersistentDatabaseEntry(String accession, ExternalDatabase ed) { return testHelper.getTestPersistentDatabaseEntry(accession, ed); } protected DatabaseEntry getTestPersistentDatabaseEntry(String accession, String ed) { return testHelper.getTestPersistentDatabaseEntry(accession, ed); } /** * Convenience method to provide an ExpressionExperiment that can be used to fill non-nullable associations in test * objects. This implementation does NOT fill in associations of the created object. * * @return */ protected ExpressionExperiment getTestPersistentExpressionExperiment() { return testHelper.getTestPersistentExpressionExperiment(); } /** * Convenience method to provide an ExpressionExperiment that can be used to fill non-nullable associations in test * objects. This implementation does NOT fill in associations of the created object. * * @return */ protected ExpressionExperiment getTestPersistentExpressionExperiment(Collection<BioAssay> bioAssays) { return testHelper.getTestPersistentExpressionExperiment(bioAssays); } /** * Convenience method to provide an ExpressionExperiment that can be used to fill non-nullable associations in test * objects. This implementation does NOT fill in associations of the created object except for the creation of * persistent BioMaterials and BioAssays so that database taxon lookups for this experiment will work. * * @return */ protected ExpressionExperiment getTestPersistentExpressionExperiment(Taxon taxon) { return testHelper.getTestPersistentExpressionExperiment(taxon); } /** * @param gene * @return */ protected GeneProduct getTestPersistentGeneProduct(Gene gene) { return testHelper.getTestPersistentGeneProduct(gene); } /** * Convenience method to provide a QuantitationType that can be used to fill non-nullable associations in test * objects. * * @return */ protected QuantitationType getTestPersistentQuantitationType() { return testHelper.getTestPersistentQuantitationType(); } } final class AuthenticationTestingUtil { /** * @param userManager the userManager to set */ public void setUserManager(UserManager userManager) { this.userManager = userManager; } private UserManager userManager; /** * Grant authority to a test user, with admin privileges, and put the token in the context. This means your tests * will be authorized to do anything an administrator would be able to do. */ protected void grantAdminAuthority(ApplicationContext ctx) { ProviderManager providerManager = (ProviderManager) ctx.getBean("authenticationManager"); providerManager.getProviders().add(new TestingAuthenticationProvider()); // Grant all roles to test user. TestingAuthenticationToken token = new TestingAuthenticationToken("administrator", "administrator", new GrantedAuthority[] { new GrantedAuthorityImpl("GROUP_ADMIN") }); token.setAuthenticated(true); putTokenInContext(token); } /** * Grant authority to a test user, with regular user privileges, and put the token in the context. This means your * tests will be authorized to do anything that user could do */ protected void switchToUser(ApplicationContext ctx, String username) { UserDetails user = userManager.loadUserByUsername(username); List<GrantedAuthority> authrs = new ArrayList<GrantedAuthority>(user.getAuthorities()); ProviderManager providerManager = (ProviderManager) ctx.getBean("authenticationManager"); providerManager.getProviders().add(new TestingAuthenticationProvider()); TestingAuthenticationToken token = new TestingAuthenticationToken(username, "testing", authrs); token.setAuthenticated(true); putTokenInContext(token); } /** * @param token */ private static void putTokenInContext(AbstractAuthenticationToken token) { SecurityContextHolder.getContext().setAuthentication(token); } }