/** * Copyright (c) 2009--2014 Red Hat, Inc. * * This software is licensed to you under the GNU General Public License, * version 2 (GPLv2). There is NO WARRANTY for this software, express or * implied, including the implied warranties of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2 * along with this software; if not, see * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. * * Red Hat trademarks are not licensed under GPLv2. No permission is * granted to use or replicate Red Hat trademarks that are incorporated * in this software or its documentation. */ package com.redhat.rhn.testing; import com.redhat.rhn.common.conf.Config; import com.redhat.rhn.common.db.datasource.DataResult; import com.redhat.rhn.common.db.datasource.ModeFactory; import com.redhat.rhn.common.db.datasource.SelectMode; import com.redhat.rhn.common.hibernate.HibernateFactory; import com.redhat.rhn.common.hibernate.HibernateRuntimeException; import com.redhat.rhn.common.localization.LocalizationService; import com.redhat.rhn.common.util.MethodUtil; import com.redhat.rhn.domain.common.LoggingFactory; import com.redhat.rhn.domain.role.RoleFactory; import com.redhat.rhn.domain.session.WebSession; import com.redhat.rhn.domain.user.User; import com.redhat.rhn.frontend.servlets.PxtCookieManager; import com.redhat.rhn.frontend.servlets.PxtSessionDelegate; import com.redhat.rhn.frontend.servlets.PxtSessionDelegateFactory; import com.redhat.rhn.frontend.struts.RequestContext; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.struts.Globals; import org.apache.struts.action.ActionMessage; import org.apache.struts.action.ActionMessages; import org.hibernate.HibernateException; import org.hibernate.Query; import org.hibernate.Session; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Serializable; import java.lang.reflect.Field; import java.net.URL; import java.util.List; import java.util.Map; /** * TestUtils, a simple package for utility functions helpful when * writing unit tests * * @version $Rev$ */ public class TestUtils { /** Prefix for temporary file names created by this class. */ private static String filePrefix = TestUtils.randomString(); // static class private TestUtils() { } /** * method to find a file relative to the calling class. primarily * useful when writing tests that need access to external data. * this lets you put the data relative to the test class file. * * @param path the path, relative to caller's location * @return URL a URL referencing the file * @throws ClassNotFoundException if the calling class can not be found * (i.e., should not happen) * @throws IOException if the specified file in an archive (eg. jar) and * it cannot be copied to a temporary location */ public static URL findTestData(String path) throws ClassNotFoundException, IOException { Throwable t = new Throwable(); StackTraceElement[] ste = t.getStackTrace(); String className = ste[1].getClassName(); Class clazz = Class.forName(className); URL ret = clazz.getResource(path); if (ret.toString().contains("!")) { // file is from an archive String tempPath = "/tmp/" + filePrefix + ret.hashCode(); InputStream input = clazz.getResourceAsStream(path); OutputStream output = new FileOutputStream(tempPath); IOUtils.copy(input, output); return new File(tempPath).toURI().toURL(); } return ret; } /** * Write a byte array to a file * @param file to write bytearray to * @param array to write out */ public static void writeByteArrayToFile(File file, byte[] array) { try { if (file.exists()) { file.delete(); } file.createNewFile(); FileOutputStream fos = new FileOutputStream(file); try { fos.write(array); } finally { fos.close(); } } catch (Exception e) { throw new RuntimeException(e); } } /** * Read whole stream into a string. * * @param stream the stream to consume * @return the contents of the stream as a string * @throws IOException if reading the file fails */ public static String readAll(InputStream stream) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); StringBuffer expected = new StringBuffer(); while (reader.ready()) { expected.append(reader.readLine()).append("\n"); } return expected.toString(); } /** * Connect to <code>url</code> and return the contents * of that location as a string. * * @param url the URL to read from * @return the contents of the URL as a string, or <code>null</code> * if <code>url</code> is <code>null</code> * @throws IOException if reading the file fails */ public static String readAll(URL url) throws IOException { if (url == null) { return null; } return readAll(url.openStream()); } /** * Get a request with a Session and a User. * @return a request with a Session and a User. */ public static RhnMockHttpServletRequest getRequestWithSessionAndUser() { LoggingFactory.clearLogId(); RhnMockHttpServletRequest req = new RhnMockHttpServletRequest(); RhnMockHttpServletResponse resp = new RhnMockHttpServletResponse(); RhnMockHttpSession session = new RhnMockHttpSession(); req.setupServerName("mymachine.rhndev.redhat.com"); req.setSession(session); User u = null; try { u = UserTestUtils.createUserInOrgOne(); } catch (Exception e) { e.printStackTrace(); } u.removePermanentRole(RoleFactory.ORG_ADMIN); Long userid = u.getId(); RequestContext requestContext = new RequestContext(req); PxtSessionDelegateFactory pxtDelegateFactory = PxtSessionDelegateFactory.getInstance(); PxtSessionDelegate pxtDelegate = pxtDelegateFactory.newPxtSessionDelegate(); WebSession s = requestContext.getWebSession(); PxtCookieManager pxtCookieManager = new PxtCookieManager(); req.addCookie(pxtCookieManager.createPxtCookie(s.getId(), req, 10)); pxtDelegate.updateWebUserId(req, resp, userid); req.addCookie(resp.getCookie("pxt-session-cookie")); req.setupAddParameter("uid", userid.toString()); return req; } /** * Finds a single instance of a persistent object. * @param query The query to find the persistent object should * be formulated to ensure a single object is returned or * an error will occur. * @return Object found or null if not * @throws Exception if there was a Hibernate related exception */ public static Object lookupTestObject(String query) throws Exception { Session session = HibernateFactory.getSession(); Query q = session.createQuery(query); return q.uniqueResult(); } /** * Finds a list of persistent objects. * @param query The query to find the persistent objects. * @return Object found or null if not * @throws Exception if there was a Hibernate related exception */ public static List lookupTestObjects(String query) throws Exception { Session session = HibernateFactory.getSession(); Query q = session.createQuery(query); return q.list(); } /** * Helper method to get a single object from the 2nd level cache by id * @param id Id of the object you want * @param queryname Queryname for the query you want to run. * queryname *MUST* have an :id attribute in it. * @return Returns the object corresponding to id * @throws Exception exception */ public static Object lookupFromCacheById(Long id, String queryname) throws Exception { Session session = HibernateFactory.getSession(); return session.getNamedQuery(queryname) .setLong("id", id) //Retrieve from cache if there .setCacheable(true) .uniqueResult(); } /** * Helper method to get a single object from the 2nd level cache by label * @param label Label of the object you want * @param queryname Queryname for the query you want to run. * queryname *MUST* have a :label attribute in it. * @return Returns the object corresponding to label * @throws Exception exception */ public static Object lookupFromCacheByLabel(String label, String queryname) throws Exception { Session session = HibernateFactory.getSession(); return session.getNamedQuery(queryname) .setString("label", label) //Retrieve from cache if there .setCacheable(true) .uniqueResult(); } /** * Print the first few lines from a stacktrace so we can figure out who the caller * is. This is similiar to doing a Thread.dumpStack() but it just doesn't spit out * as many lines of the stacktrace. * * @param depth the number of lines of the stacktrace you want to see */ public static void printWhoCalledMe(int depth) { StackTraceElement[] elements = null; try { throw new Exception("Nothing to see here"); } catch (Exception e) { elements = e.getStackTrace(); } // Only show 10 lines of the trace for (int i = 0; ((i < elements.length) && i < depth); i++) { System.out.println("Stack: [" + i + "]: " + elements[i].getClassName() + "." + elements[i].getMethodName() + " : " + elements[i].getLineNumber()); } } /** * Util to flush and evict an object from the Hibernate Session * @param obj to flush * @throws HibernateException if something bad happens */ public static void flushAndEvict(Object obj) throws HibernateException { Session session = HibernateFactory.getSession(); session.flush(); session.evict(obj); } /** * Util to reload an object from the DB using Hibernate. * @param objClass of object being looked up * @param id of object * @return Object found or NULL if not * @throws HibernateException if something goes wrong. */ public static Object reload(Class objClass, Serializable id) throws HibernateException { Session session = HibernateFactory.getSession(); session.flush(); /* * In hibernate 3, the following doesn't work: * Object obj = session.load(objClass, id); * load returns the proxy class instead of the persisted class, ie, * Filter$$EnhancerByCGLIB$$9bcc734d_2 instead of Filter. * session.get is set to not return the proxy class, so that is what we'll use. */ Object obj = session.get(objClass, id); return reload(obj); } /** * Util to reload an object using Hibernate * @param obj to be reloaded * @return Object found if not, null * @throws HibernateException if something bad happens. */ public static Object reload(Object obj) throws HibernateException { return HibernateFactory.reload(obj); } /** * Helper method to save objects to the database and flush * the session. * @param obj object to save. * @throws HibernateException HibernateException */ public static void saveAndFlush(Object obj) throws HibernateException { Session session = HibernateFactory.getSession(); session.save(obj); session.flush(); } /** * Removes an object from the database. * @param toRemove Object to be removed. * @return Number of rows affected. */ public static int removeObject(Object toRemove) { Session session = null; int numDeleted = 0; try { session = HibernateFactory.getSession(); session.delete(toRemove); numDeleted++; } catch (HibernateException he) { throw new HibernateRuntimeException("Error removing " + toRemove, he); } return numDeleted; } /** * Sets the Config to indicate we want to be in * Debug mode for Localization. Usefull for checking * if a set of strings is l10ned. * */ public static void enableLocalizationDebugMode() { Config.get().setString("java.l10n_debug", "true"); } /** * Turns of the Config setting for L10N debug mode */ public static void disableLocalizationDebugMode() { Config.get().setString("java.l10n_debug", "false"); } /** * Disable the *** ERROR: Message with id: [asciiString] not found.*** * errors. Some tests pass in non-translated strings which is OK. */ public static void disableLocalizationLogging() { Logger log = Logger.getLogger(LocalizationService.class); log.setLevel(Level.OFF); } /** * Enable the *** ERROR: Message with id: [asciiString] not found.*** * errors. Some tests pass in non-translated strings which is OK. */ public static void enableLocalizationLogging() { Logger log = Logger.getLogger(LocalizationService.class); log.setLevel(Level.WARN); } /** * Check the string to see if it passed through the LocalizationService. * @param checkMe String to check if it was l10ned * @return boolean if or not it was localized */ public static boolean isLocalized(String checkMe) { if (!Boolean.valueOf( Config.get().getString("java.l10n_debug", "false")).booleanValue()) { throw new IllegalArgumentException("java.l10n_debug is set to false. " + "This test doesnt mean anything if its set to false. "); } return (checkMe.startsWith( Config.get().getString("java.l10n_debug_marker", "$$$"))); } /** * Check the request in the ActionHelper to validate that there is a UI * message in the session. Useful for struts actions where you want to * verify that it put something in the session. * @param ah actionhelper used in the test * @param key to the i18n resource * @return boolean if it was found or not */ public static boolean validateUIMessage(ActionHelper ah, String key) { ActionMessages mess = (ActionMessages) ah.getRequest().getSession().getAttribute(Globals.MESSAGE_KEY); if (mess == null) { return false; } ActionMessage am = (ActionMessage) mess.get().next(); String value = am.getKey(); if (StringUtils.isEmpty(value)) { return false; } return value.equals(key); } /** * Return a random 13 letter string. Useful for creating unique * string labels/names in your tests. * @return String that is 13 chars long and alphanumeric */ public static String randomString() { return RandomStringUtils.randomAlphanumeric(13); } /** * Run a test query * @param mode to run * @param params map * @return DataResult List */ public static DataResult runTestQuery(String mode, Map params) { SelectMode m = ModeFactory. getMode("test_queries", mode); return m.execute(params); } /** * Search an array by calling the passsed in method name with the key as the checker * @param search array * @param methodName to call on each object in the array (can be toString()) * @param key to compare to * @return boolean if found or not */ public static boolean arraySearch(Object[] search, String methodName, Object key) { boolean found = false; for (int i = 0; i < search.length; i++) { Object value = MethodUtil.callMethod(search[i], methodName, new Object[0]); if (value.equals(key)) { found = true; } } return found; } /** * Save and reload an object from DB * @param o to save and reload. * @return Object fresh from DB */ public static Object saveAndReload(Object o) { TestUtils.saveAndFlush(o); return reload(o); } /** * Get a private field from a class. Good for testing * the inner state of a class's member variables. * * Copied from: http://snippets.dzone.com/posts/show/2242 * * @param o to check * @param fieldName to find * @return Object if found */ public static Object getPrivateField(Object o, String fieldName) { /* Check we have valid arguments */ /* Go and find the private field... */ final Field[] fields = o.getClass().getDeclaredFields(); for (int i = 0; i < fields.length; ++i) { if (fieldName.equals(fields[i].getName())) { try { fields[i].setAccessible(true); return fields[i].get(o); } catch (IllegalAccessException ex) { throw new RuntimeException(ex); } } } return null; } /** * Used to test the equals contract on objects. * The contract as specified by java.lang.Object states that if A.equals(B) is true * then B.equals(A) is also true. It also specifies that if A.equals(B) is true * then A.hashCode() will equals B.hashCode() * @param o1 object1 * @param o2 object2 * @return both objects equal */ public static boolean equalTest(Object o1, Object o2) { // both null if (o1 == null && o2 == null) { return true; } // just one null if (o1 == null || o2 == null) { return false; } if (o1.equals(o2) != o2.equals(o1)) { return false; } return o1.hashCode() == o2.hashCode(); } }