Commits

Anonymous committed 569f828

CSVDataSet handles blank columns in csv file
New log parsers - shared log parser (multiple threads take turns on the same access log), order preserving parser (multiple threads take turns on the same access log AND the ordering in the log is preserved)
Improvements to session filter

  • Participants
  • Parent commits c0ec9ba
  • Branches rel-2-1

Comments (0)

Files changed (12)

File src/components/org/apache/jmeter/config/CSVDataSet.java

 			String delim = getDelimiter();
 			if (delim.equals("\\t"))
 				delim = "\t";// Make it easier to enter a Tab
-			String[] lineValues = JOrphanUtils.split(server.readLine(getFilename()), delim);
+			String[] lineValues = JOrphanUtils.split(server.readLine(getFilename()), delim,false);
 			for (int a = 0; a < vars.length && a < lineValues.length; a++) {
 				this.getThreadContext().getVariables().put(vars[a], lineValues[a]);
 			}

File src/core/org/apache/jmeter/engine/StandardJMeterEngine.java

 	}
 
 	protected void notifyTestListenersOfEnd() {
+        log.info("Notifying test listeners of end of test");
 		Iterator iter = testListeners.getSearchResults().iterator();
 		while (iter.hasNext()) {
 			TestListener tl = (TestListener) iter.next();
 	}
 
 	public synchronized void threadFinished(JMeterThread thread) {
-		allThreads.remove(thread);
-		log.info("Ending thread " + thread.getThreadNum());
-		if (!serialized && allThreads.size() == 0 && !schcdule_run) {
-			log.info("Stopping test");
-			stopTest();
-		}
+		try {
+            allThreads.remove(thread);
+            log.info("Ending thread " + thread.getThreadNum());
+            if (!serialized && allThreads.size() == 0 && !schcdule_run) {
+            	log.info("Stopping test");
+            	stopTest();
+            }
+        } catch (Throwable e) {
+            log.fatalError("Call to threadFinished should never throw an exception - this can deadlock JMeter",e);
+        }
 	}
 
 	public synchronized void stopTest() {

File src/core/org/apache/jmeter/services/FileServer.java

 	}
 
 	public void setBasedir(String basedir) throws IOException {
-		log.info("Setting basedir to: " + basedir);
 		if (filesOpen()) {
 			throw new IOException("Files are still open, cannot change base directory");
 		}
 	}
 
 	public synchronized void reserveFile(String filename) {
-		log.info("filename = " + filename + " base = " + base);
 		if (!files.containsKey(filename)) {
 			Object[] file = new Object[] { new File(base, filename), null };
 			files.put(filename, file);
 	 */
 	public synchronized void closeFile(String name) throws IOException {
 		Object[] file = (Object[]) files.get(name);
-		if (file[1] != null) {
+		if (file != null && file.length == 2 && file[1] != null) {
 			((Reader) file[1]).close();
 			file[1] = null;
 		}
 
 	/**
 	 * Method will get a random file in a base directory
+     * TODO hey, not sure this method belongs here.  FileServer is for threadsafe
+     * File access relative to current test's base directory.  
 	 * 
 	 * @param basedir
 	 * @return

File src/jorphan/org/apache/jorphan/util/JOrphanUtils.java

 	 *            Character to split the string on
 	 * @return Array of all the tokens.
 	 */
-	public static String[] split(String splittee, String splitChar) {
+	public static String[] split(String splittee, String splitChar,boolean truncate) {
 		if (splittee == null || splitChar == null) {
 			return new String[0];
 		}
 		int spot;
-		while ((spot = splittee.indexOf(splitChar + splitChar)) != -1) {
-			splittee = splittee.substring(0, spot + splitChar.length())
-					+ splittee.substring(spot + 2 * splitChar.length(), splittee.length());
-		}
+        if(truncate) {
+    		while ((spot = splittee.indexOf(splitChar + splitChar)) != -1) {
+    			splittee = splittee.substring(0, spot + splitChar.length())
+    					+ splittee.substring(spot + 2 * splitChar.length(), splittee.length());
+    		}
+            if(splittee.startsWith(splitChar)) splittee = splittee.substring(splitChar.length());
+        }
 		Vector returns = new Vector();
 		int start = 0;
 		int length = splittee.length();
 			if (spot > 0) {
 				returns.addElement(splittee.substring(start, spot));
 			}
+            else
+            {
+                returns.addElement("");
+            }
 			start = spot + splitChar.length();
 		}
 		if (start < length) {
 		returns.copyInto(values);
 		return values;
 	}
+    
+    public static String[] split(String splittee,String splitChar)
+    {
+        return split(splittee,splitChar,true);
+    }
 
 	private static final String SPACES = "                                 ";
 
 
 		return slice;
 	}
-
-	public static class Test extends TestCase {
-		public void testReplace1() {
-			assertEquals("xyzdef", replaceFirst("abcdef", "abc", "xyz"));
-		}
-
-		public void testReplace2() {
-			assertEquals("axyzdef", replaceFirst("abcdef", "bc", "xyz"));
-		}
-
-		public void testReplace3() {
-			assertEquals("abcxyz", replaceFirst("abcdef", "def", "xyz"));
-		}
-
-		public void testReplace4() {
-			assertEquals("abcdef", replaceFirst("abcdef", "bce", "xyz"));
-		}
-
-		public void testReplace5() {
-			assertEquals("abcdef", replaceFirst("abcdef", "alt=\"\" ", ""));
-		}
-
-		public void testReplace6() {
-			assertEquals("abcdef", replaceFirst("abcdef", "alt=\"\" ", ""));
-		}
-
-		public void testReplace7() {
-			assertEquals("alt=\"\"", replaceFirst("alt=\"\"", "alt=\"\" ", ""));
-		}
-
-		public void testReplace8() {
-			assertEquals("img src=xyz ", replaceFirst("img src=xyz alt=\"\" ", "alt=\"\" ", ""));
-		}
-
-		public void testSplit1() {
-			String in = "a,bc,,"; // Test ignore trailing split characters
-			String out[] = split(in, ",");
-			assertEquals(2, out.length);
-			assertEquals("a", out[0]);
-			assertEquals("bc", out[1]);
-		}
-
-		public void testSplit2() {
-			String in = ",,a,bc"; // Test leading split characters
-			String out[] = split(in, ",");
-			assertEquals("Should detect the leading split chars; ", 2, out.length - 2);
-			assertEquals("", out[0]);
-			assertEquals("", out[1]);
-			assertEquals("a", out[2]);
-			assertEquals("bc", out[3]);
-		}
-	}
 }

File src/protocol/http/org/apache/jmeter/protocol/http/sampler/AccessLogSampler.java

 import org.apache.jmeter.samplers.SampleResult;
 import org.apache.jmeter.testbeans.TestBean;
 import org.apache.jmeter.testelement.TestCloneable;
+import org.apache.jmeter.testelement.ThreadListener;
 import org.apache.jmeter.threads.JMeterContextService;
 import org.apache.jorphan.logging.LoggingManager;
 import org.apache.jorphan.util.JMeterException;
  * @author Peter Lin
  * @version $Revision$ last updated $Date$
  */
-public class AccessLogSampler extends HTTPSampler implements TestBean {
+public class AccessLogSampler extends HTTPSampler implements TestBean,ThreadListener {
 	private static Logger log = LoggingManager.getLoggerForClass();
 
 	public static final String DEFAULT_CLASS = "org.apache.jmeter.protocol.http.util.accesslog.TCLogParser";
                     {
                         instantiateParser();
                         s.PARSER = (LogParser)((TestCloneable)PARSER).clone();
+                        if(filter != null)
+                        {
+                            s.PARSER.setFilter(s.filter);
+                        }
                     }
 				} catch (Exception e) {
 					log.warn("Could not clone cloneable filter", e);
 		if (PARSER != null) {
 			PARSER.close();
 		}
+        filter = null;
 		started = false;
 		super.testEnded();
 	}
 		started = true;
 		super.testStarted();
 	}
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.testelement.AbstractTestElement#threadFinished()
+     */
+    public void threadFinished() {
+        if(PARSER instanceof ThreadListener)
+            ((ThreadListener)PARSER).threadFinished();
+        if(filter instanceof ThreadListener)
+            ((ThreadListener)filter).threadFinished();
+    }
 }

File src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/Filter.java

 
 package org.apache.jmeter.protocol.http.util.accesslog;
 
+import org.apache.jmeter.testelement.TestElement;
+
 /**
  * Description:<br>
  * <br>
 	 * @param path
 	 * @return boolean
 	 */
-	public boolean isFiltered(String path);
+	public boolean isFiltered(String path,TestElement sampler);
 
 	/**
 	 * In case the user wants to replace the file extension, log parsers should

File src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/LogFilter.java

 import java.util.ArrayList;
 
 import org.apache.jmeter.junit.JMeterTestCase;
+import org.apache.jmeter.testelement.TestElement;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.oro.text.regex.Pattern;
 import org.apache.oro.text.regex.Perl5Compiler;
 	 * @param path
 	 * @return boolean
 	 */
-	public boolean isFiltered(String path) {
+	public boolean isFiltered(String path,TestElement el) {
 		// we do a quick check to see if any
 		// filters are set. If not we just
 		// return false to be efficient.
 
 		public void testReplaceExtension() {
 			testf.setReplaceExtension("html", "jsp");
-			testf.isFiltered(TESTSTR);// set the required variables
+			testf.isFiltered(TESTSTR,null);// set the required variables
 			assertEquals(TESTSTROUT, testf.filter(TESTSTR));
 		}
 
 				String theFile = td.file;
 				boolean expect = td.exclfile;
 
-				testf.isFiltered(theFile);
+				testf.isFiltered(theFile,null);
 				String line = testf.filter(theFile);
 				if (line != null) {
 					assertTrue("Expect to accept " + theFile, expect);
 				String theFile = td.file;
 				boolean expect = td.inclfile;
 
-				testf.isFiltered(theFile);
+				testf.isFiltered(theFile,null);
 				String line = testf.filter(theFile);
 				if (line != null) {
 					assertTrue("Expect to accept " + theFile, expect);
 				String theFile = td.file;
 				boolean expect = td.exclpatt;
 
-				assertEquals(!expect, testf.isFiltered(theFile));
+				assertEquals(!expect, testf.isFiltered(theFile,null));
 				String line = testf.filter(theFile);
 				if (line != null) {
 					assertTrue("Expect to accept " + theFile, expect);
 				String theFile = td.file;
 				boolean expect = td.inclpatt;
 
-				assertEquals(!expect, testf.isFiltered(theFile));
+				assertEquals(!expect, testf.isFiltered(theFile,null));
 				String line = testf.filter(theFile);
 				if (line != null) {
 					assertTrue("Expect to accept " + theFile, expect);

File src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/OrderPreservingLogParser.java

+package org.apache.jmeter.protocol.http.util.accesslog;
+
+import org.apache.jmeter.testelement.TestElement;
+
+public class OrderPreservingLogParser extends SharedTCLogParser {
+
+    public OrderPreservingLogParser() {
+        super();
+    }
+
+    public OrderPreservingLogParser(String source) {
+        super(source);
+    }
+
+    /**
+     * parse a set number of lines from the access log. Keep in mind the number
+     * of lines parsed will depend the filter and number of lines in the log.
+     * The method returns the actual lines parsed.
+     * 
+     * @param count
+     * @return lines parsed
+     */
+    public synchronized int parseAndConfigure(int count, TestElement el) {
+        return this.parse(el, count);
+    }
+
+}

File src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SessionFilter.java

 package org.apache.jmeter.protocol.http.util.accesslog;
 
 import java.io.Serializable;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
 
+import org.apache.jmeter.protocol.http.control.CookieManager;
+import org.apache.jmeter.protocol.http.sampler.HTTPSampler;
 import org.apache.jmeter.testelement.TestCloneable;
+import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.ThreadListener;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.logging.LoggingManager;
 import org.apache.log.Logger;
  * @author mstover
  * 
  */
-public class SessionFilter implements Filter, Serializable, TestCloneable {
+public class SessionFilter implements Filter, Serializable, TestCloneable,ThreadListener {
+    private static final long serialVersionUID = 1;
 	static Logger log = LoggingManager.getLoggerForClass();
 
 	/**
-	 * This object is static across multiple threads in a test, via clone()
+	 * These objects are static across multiple threads in a test, via clone()
 	 * method.
 	 */
-	protected List excludedIps;
+	protected Map cookieManagers;
+    protected Set managersInUse;
+    
+    protected CookieManager lastUsed;
 
-	String ipAddress;
-
-	/*
+    /*
 	 * (non-Javadoc)
 	 * 
 	 * @see org.apache.jmeter.protocol.http.util.accesslog.LogFilter#excPattern(java.lang.String)
 	 */
 	protected boolean hasExcPattern(String text) {
-		synchronized (excludedIps) {
-			boolean exclude = false;
-			for (Iterator x = excludedIps.iterator(); x.hasNext();) {
-				if (text.indexOf((String) x.next()) > -1) {
-					exclude = true;
-					break;
-				}
-			}
-			if (!exclude) {
-				ipAddress = getIpAddress(text);
-				excludedIps.add(ipAddress);
-			}
-			return exclude;
-		}
+        return false;
 	}
 
 	protected String getIpAddress(String logLine) {
 	 * @see org.apache.jmeter.protocol.http.util.accesslog.Filter#reset()
 	 */
 	public void reset() {
-		ipAddress = null;
+		cookieManagers.clear();
 	}
 
 	public Object clone() {
+        if(cookieManagers == null)
+        {
+            cookieManagers = Collections.synchronizedMap(new HashMap());
+        }
+        if(managersInUse == null)
+        {
+            managersInUse = Collections.synchronizedSet(new HashSet());
+        }
 		SessionFilter f = new SessionFilter();
-		f.excludedIps = excludedIps;
+        f.cookieManagers = cookieManagers;
+        f.managersInUse = managersInUse;
 		return f;
 	}
 
 	 * 
 	 */
 	public SessionFilter() {
-		excludedIps = new LinkedList();
 	}
 
 	/*
 	 * 
 	 * @see org.apache.jmeter.protocol.http.util.accesslog.Filter#isFiltered(java.lang.String)
 	 */
-	public boolean isFiltered(String path) {
-		if (ipAddress != null) {
-			log.debug("looking for ip address: " + ipAddress + " in line: " + path);
-			return !(path.indexOf(ipAddress) > -1);
-		} else
-			return hasExcPattern(path);
+	public boolean isFiltered(String path,TestElement sampler) {
+		String ipAddr = getIpAddress(path);
+        CookieManager cm = getCookieManager(ipAddr);
+        ((HTTPSampler)sampler).setCookieManager(cm);   
+        return false;
 	}
+    
+    protected CookieManager getCookieManager(String ipAddr)
+    {
+        CookieManager cm = null;
+        // First have to release the cookie we were using so other
+        // threads stuck in wait can move on
+        synchronized(managersInUse)
+        {
+            if(lastUsed != null)
+            {
+                managersInUse.remove(lastUsed);
+                managersInUse.notify(); 
+            }
+        }
+        // let notified threads move on and get lock on managersInUse
+        if(lastUsed != null)
+        {
+            Thread.yield();
+        }
+        // here is the core routine to find appropriate cookie manager and
+        // check it's not being used.  If used, wait until whoever's using it gives
+        // it up
+        synchronized(managersInUse)
+        {
+            cm = (CookieManager)cookieManagers.get(ipAddr);
+            if(cm == null)
+            {
+                cm = new CookieManager();
+                cookieManagers.put(ipAddr,cm);
+            } 
+            while(managersInUse.contains(cm))
+            {
+                try {
+                    managersInUse.wait();
+                } catch (InterruptedException e) {
+                    log.info("SessionFilter wait interrupted");
+                }
+            }
+            managersInUse.add(cm);
+            lastUsed = cm;
+        }
+        return cm;
+    }
 
 	/*
 	 * (non-Javadoc)
 	 */
 	public void setReplaceExtension(String oldextension, String newextension) {
 	}
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.testelement.ThreadListener#threadFinished()
+     */
+    public void threadFinished() {
+        synchronized(managersInUse)
+        {
+            managersInUse.remove(lastUsed);
+            managersInUse.notify(); 
+        }        
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.jmeter.testelement.ThreadListener#threadStarted()
+     */
+    public void threadStarted() {
+        // TODO Auto-generated method stub
+        
+    }
 }

File src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/SharedTCLogParser.java

 import org.apache.jmeter.services.FileServer;
 import org.apache.jmeter.testelement.TestCloneable;
 import org.apache.jmeter.testelement.TestElement;
+import org.apache.jmeter.testelement.ThreadListener;
 
 public class SharedTCLogParser extends TCLogParser implements TestCloneable {
 

File src/protocol/http/org/apache/jmeter/protocol/http/util/accesslog/TCLogParser.java

 		el.setProperty(HTTPSamplerBase.METHOD, RMETHOD);
 		if (FILTER != null) {
 			log.debug("filter is not null");
-			if (!FILTER.isFiltered(line)) {
+			if (!FILTER.isFiltered(line,el)) {
 				log.debug("line was not filtered");
 				// increment the current count
 				count++;

File test/src/org/apache/jorphan/util/TestJorphanUtils.java

+package org.apache.jorphan.util;
+
+import junit.framework.TestCase;
+
+public class TestJorphanUtils extends TestCase {
+
+    public TestJorphanUtils() {
+        super();
+        // TODO Auto-generated constructor stub
+    }
+
+    public TestJorphanUtils(String arg0) {
+        super(arg0);
+        // TODO Auto-generated constructor stub
+    }
+    
+        public void testReplace1() {
+            assertEquals("xyzdef", JOrphanUtils.replaceFirst("abcdef", "abc", "xyz"));
+        }
+
+        public void testReplace2() {
+            assertEquals("axyzdef", JOrphanUtils.replaceFirst("abcdef", "bc", "xyz"));
+        }
+
+        public void testReplace3() {
+            assertEquals("abcxyz", JOrphanUtils.replaceFirst("abcdef", "def", "xyz"));
+        }
+
+        public void testReplace4() {
+            assertEquals("abcdef", JOrphanUtils.replaceFirst("abcdef", "bce", "xyz"));
+        }
+
+        public void testReplace5() {
+            assertEquals("abcdef", JOrphanUtils.replaceFirst("abcdef", "alt=\"\" ", ""));
+        }
+
+        public void testReplace6() {
+            assertEquals("abcdef", JOrphanUtils.replaceFirst("abcdef", "alt=\"\" ", ""));
+        }
+
+        public void testReplace7() {
+            assertEquals("alt=\"\"", JOrphanUtils.replaceFirst("alt=\"\"", "alt=\"\" ", ""));
+        }
+
+        public void testReplace8() {
+            assertEquals("img src=xyz ", JOrphanUtils.replaceFirst("img src=xyz alt=\"\" ", "alt=\"\" ", ""));
+        }
+
+        public void testSplit1() {
+            String in = "a,bc,,"; // Test ignore trailing split characters
+            String out[] = JOrphanUtils.split(in, ",",true);
+            assertEquals(2, out.length);
+            assertEquals("a", out[0]);
+            assertEquals("bc", out[1]);
+        }
+
+        public void testSplit2() {
+            String in = ",,a,bc"; // Test leading split characters
+            String out[] = JOrphanUtils.split(in, ",",true);
+            assertEquals(2, out.length);
+            assertEquals("a", out[0]);
+            assertEquals("bc", out[1]);
+            out = JOrphanUtils.split(in, ",",false);
+            assertEquals("Should detect the leading split chars; ", 4, out.length);
+            assertEquals("", out[0]);
+            assertEquals("", out[1]);
+            assertEquals("a", out[2]);
+            assertEquals("bc", out[3]);
+        }
+        
+        public void testTruncate() throws Exception
+        {
+            String in = "a,b,,,d,e,,f";
+            String[] out = JOrphanUtils.split(in,",",true);
+            assertEquals("d",out[2]);
+            out = JOrphanUtils.split(in,",",false);
+            assertEquals("",out[2]);
+            
+        }
+
+}