apache / jmeter

Apache JMeter open-source load testing tool for analyzing and measuring the performance of a variety of services
https://jmeter.apache.org/
Apache License 2.0
8.35k stars 2.09k forks source link

IncludeController : NullPointerException loading script in non-GUI mode if Includers use same element name #2472

Closed asfimport closed 12 years ago

asfimport commented 13 years ago

Luciana Moreira (Bug 50898): I am facing a problem which appeared after my colleague updated one of our scripts. He saved the script with the jmeter revision 1077948

I am able to load and execute my script without any problems if I do it from the GUI without providing it in the command line. However if I pass the script in the command line I get the following exception:

2010/09/20 17:12:09 ERROR - jmeter.engine.StandardJMeterEngine: Uncaught exception: java.lang.NullPointerException at org.apache.jorphan.collections.HashTree.traverseInto(HashTree.java:989) at org.apache.jorphan.collections.HashTree.traverseInto(HashTree.java:989) at org.apache.jorphan.collections.HashTree.traverseInto(HashTree.java:989) at org.apache.jorphan.collections.HashTree.traverseInto(HashTree.java:989) at org.apache.jorphan.collections.HashTree.traverse(HashTree.java:971) at org.apache.jmeter.engine.StandardJMeterEngine.run(StandardJMeterEngine.java:385) at java.lang.Thread.run(Thread.java:619)

The problem seems to be in Iterator<?> iter = list().iterator();
        while (iter.hasNext()) {
            Object item = iter.next();
            final HashTree treeItem = getTree(item);
            visitor.addNode(item, treeItem);
            treeItem.traverseInto(visitor);
        }

 I don't understand how this problem can even happen. What occurs is that treeItem is null. 
 Adding some expressions evaluation I got the following results:
 list().contains(item) => true
 containsKey(item) => false
 get(item) != null => false

 I noticed that in the script that no longer works some elements are saved differently than they used to be:
 This is how it used to work:
 <org.apache.jmeter.protocol.smtp.sampler.SmtpSampler guiclass="org.apache.jmeter.protocol.smtp.sampler.gui.SmtpSamplerGui" testclass="org.apache.jmeter.protocol.smtp.sampler.SmtpSampler" testname="SMTP 1" enabled="true">

 This is how it is now:
 <SmtpSampler guiclass="SmtpSamplerGui" testclass="SmtpSampler" testname="SMTP 1" enabled="true">

 However I do not know if this is the cause of the problem...

 Any light in this matter would be very appreciated.

Severity: normal OS: All

asfimport commented 13 years ago

Luciana Moreira (migrated from Bugzilla): After digging more into this problem I found out a work around for my script.

The problem seems to come from IncludeController. I had in my script 2 IncludeControllers They had the same name and included the same file. By changing the name of one of the IncludeControllers I am now able to also launch JMeter passing this script as parameter.

I guess this bug is related to the overridden methods equals() and hashCode from AbstractTestElement. Somehow that confused the HashMap.

asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Created attachment BUG_40973.jmx: Including Plan that reproduces the NullPointer in non gui mode

BUG_40973.jmx ````xml false false continue false 1 1 1 1317506570000 1317506570000 false www.google.com /webhp?hl=ja GET true false true false false air-j.com / GET true false true false false Rakuten.co.jp / GET true false true false false false saveConfig true true true true true true true false true true false false true false false false false false 0 true ````
asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Created attachment Test.Fragment.jmx: Included plan

asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Created attachment results-master.log: Log file

results-master.log ```` 2011/10/02 00:32:18 INFO - jmeter.util.JMeterUtils: Setting Locale to en_EN 2011/10/02 00:32:18 INFO - jmeter.JMeter: Loading user properties from: /data/decathlon/workspace/jmeter/bin/user.properties 2011/10/02 00:32:18 INFO - jmeter.JMeter: Loading system properties from: /data/decathlon/workspace/jmeter/bin/system.properties 2011/10/02 00:32:18 INFO - jmeter.JMeter: Copyright (c) 1998-2011 The Apache Software Foundation 2011/10/02 00:32:18 INFO - jmeter.JMeter: Version 2.5.1.20111001 2011/10/02 00:32:18 INFO - jmeter.JMeter: java.version=1.6.0_26 2011/10/02 00:32:18 INFO - jmeter.JMeter: java.vm.name=Java HotSpot(TM) 64-Bit Server VM 2011/10/02 00:32:18 INFO - jmeter.JMeter: os.name=Mac OS X 2011/10/02 00:32:18 INFO - jmeter.JMeter: os.arch=x86_64 2011/10/02 00:32:18 INFO - jmeter.JMeter: os.version=10.6.8 2011/10/02 00:32:18 INFO - jmeter.JMeter: file.encoding=UTF-8 2011/10/02 00:32:18 INFO - jmeter.JMeter: Default Locale=English (EN) 2011/10/02 00:32:18 INFO - jmeter.JMeter: JMeter Locale=English (EN) 2011/10/02 00:32:18 INFO - jmeter.JMeter: JMeterHome=/data/decathlon/workspace/jmeter 2011/10/02 00:32:18 INFO - jmeter.JMeter: user.dir =/data/decathlon/workspace/jmeter/bin 2011/10/02 00:32:18 INFO - jmeter.JMeter: PWD =/data/decathlon/workspace/jmeter/bin 2011/10/02 00:32:18 INFO - jmeter.JMeter: IP: 192.168.0.14 Name: MBP-PMD.local FullName: 192.168.0.14 2011/10/02 00:32:18 INFO - jmeter.services.FileServer: Default base='/data/decathlon/workspace/jmeter/bin' 2011/10/02 00:32:18 INFO - jmeter.services.FileServer: Set new base '/data/jmeter/BUG_51869' 2011/10/02 00:32:18 INFO - jmeter.JMeter: Loading file: /data/jmeter/BUG_51869/Use.Include.jmx 2011/10/02 00:32:18 INFO - jmeter.save.SaveService: Testplan (JMX) version: 2.2. Testlog (JTL) version: 2.2 2011/10/02 00:32:18 INFO - jmeter.save.SaveService: Using SaveService properties file encoding UTF-8 2011/10/02 00:32:18 INFO - jmeter.save.SaveService: Using SaveService properties file version 1050447 2011/10/02 00:32:18 INFO - jmeter.save.SaveService: Using SaveService properties version 2.1 2011/10/02 00:32:18 INFO - jmeter.save.SaveService: All converter versions present and correct 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -- try to load included module: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -failed for: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -Attempting to read it from: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Cannot find .className property for htmlParser, using default 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Parser for text/html is 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Parser for application/xhtml+xml is 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Parser for application/xml is 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Parser for text/xml is 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Parser for text/vnd.wap.wml is org.apache.jmeter.protocol.http.parser.RegexpHTMLParser 2011/10/02 00:32:19 INFO - jmeter.protocol.http.sampler.HTTPSamplerBase: Reuse SSL session context on subsequent iterations: false 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -- try to load included module: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -failed for: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -Attempting to read it from: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -- try to load included module: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -failed for: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -Attempting to read it from: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -- try to load included module: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -failed for: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.control.IncludeController: loadIncludedElements -Attempting to read it from: /data/decathlon/workspace/jmeter/bin/Test.Fragment.jmx 2011/10/02 00:32:19 INFO - jmeter.engine.StandardJMeterEngine: Listeners will be started after enabling running version 2011/10/02 00:32:19 INFO - jmeter.engine.StandardJMeterEngine: To revert to the earlier behaviour, define jmeterengine.startlistenerslater=false 2011/10/02 00:32:19 INFO - jmeter.engine.StandardJMeterEngine: Running the test! 2011/10/02 00:36:46 ERROR - jmeter.JMeter: Uncaught exception: java.lang.NullPointerException at org.apache.jorphan.collections.HashTree.traverseInto(HashTree.java:987) at org.apache.jorphan.collections.HashTree.traverseInto(HashTree.java:987) at org.apache.jorphan.collections.HashTree.traverse(HashTree.java:969) at org.apache.jmeter.engine.StandardJMeterEngine.run(StandardJMeterEngine.java:315) at java.lang.Thread.run(Thread.java:680) ````
asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): I confirm there is an issue related to hashCode and equals.

to test this hypothesis I modified HashTree#traverseInto: private void traverseInto(HashTreeTraverser visitor) {

    if (list().size() == 0) {
        visitor.processPath();
    } else {
        Iterator<?> iter = list().iterator();

        while (iter.hasNext()) {
            Object item = iter.next();
            final HashTree treeItem = getTree(item);
            visitor.addNode(item, treeItem);
            if(treeItem==null)
            {
                List<IncludeController>  list = new ArrayList<IncludeController>();
                Iterator<?> iter2 = list().iterator();
                while (iter2.hasNext()) {
                    Object item2 = iter2.next();
                    if(item2 instanceof IncludeController)
                    {
                        list.add((IncludeController)item2);
                    }
                }
                if(list.size()==2)
                {
                    IncludeController controller1 = list.get(0);
                    IncludeController controller2 = list.get(1);
                    System.out.println(controller1.equals(controller2));
                    System.out.println(controller1.hashCode());
                    System.out.println(controller2.hashCode());
                }
            }
            treeItem.traverseInto(visitor);
        }
    }
    visitor.subtractNode();
}

And it shows the following: true => Objects are equals 831453930 1248040939

According to javadocs: If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Patch relies on another more efficient iteration mode using entrySet. This method will not use hashCode so will not meet bug.

traverse(HashTreeTraverser visitor) may have same issue:

There is still the root cause to investigate regarding hashCode bug.

Regards Philippe

Created attachment BUG_50898.patch: Fix to issue

BUG_50898.patch ````diff Index: src/jorphan/org/apache/jorphan/collections/HashTree.java =================================================================== --- src/jorphan/org/apache/jorphan/collections/HashTree.java (revision 1178103) +++ src/jorphan/org/apache/jorphan/collections/HashTree.java (working copy) @@ -979,10 +979,12 @@ if (list().size() == 0) { visitor.processPath(); } else { - Iterator iter = list().iterator(); - while (iter.hasNext()) { - Object item = iter.next(); - final HashTree treeItem = getTree(item); + Set> entrySet = data.entrySet(); + for (Iterator> iterator = entrySet.iterator(); iterator.hasNext();) { + Entry entry = iterator + .next(); + Object item = entry.getKey(); + final HashTree treeItem = entry.getValue(); visitor.addNode(item, treeItem); treeItem.traverseInto(visitor); } ````
asfimport commented 13 years ago

Sebb (migrated from Bugzilla): (In reply to comment 2)

Created attachment 27664 [details] Including Plan that reproduces the NullPointer in non gui mode

Does not appear to be the correct test plan; it does not use an include controller

asfimport commented 13 years ago

Sebb (migrated from Bugzilla): (In reply to comment 3)

Created attachment 27665 [details] Included plan

If this is the sample included plan, it is excessively complicated. Please use smallest possible test plan, and ideally use Java Request instead of HTTP sampler (unless the test requires an HTTP sample).

asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Created attachment Use.Include.jmx: Includer plan

Use.Include.jmx ````xml false false TIME_BOUND 2000 = continue false 1 1 1 1316699696000 1316699696000 false Test.Fragment.jmx Test.Fragment.jmx false saveConfig true true true true true true true false true true false false true false false false false false 0 true ````
asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Hello Sebb, As you requested, much simpler plan. Regards Philippe

Created attachment Test.Fragment.jmx: Included in Use.Include.jmx

Test.Fragment.jmx ````xml false false TIME_BOUND 10000 = true Sleep_Time 100 = Sleep_Mask 0xFF = Label = ResponseCode = ResponseMessage = Status OK = SamplerData = ResultData = org.apache.jmeter.protocol.java.test.JavaTest continue false 1 1 1 1316697651000 1316697651000 false WorkBench Test Plan Wikipedia samples T /wiki/Wikipedia false saveConfig true true true true true true true false true true false false true false false false false false 0 true sleep=0; timebound = vars.get("TIME_BOUND"); timebound = Long.parseLong(timebound); if (SampleResult.getSampleLabel(false).startsWith("T ")) { if(SampleResult.getTime() >= timebound){ return false; } sleep = timebound - SampleResult.getTime(); sleep = sleep*Math.random()*2; //if we're going to sleep less than 0 then //we've reched the breaking point if(sleep <=0 ){ return false; } //we do this instead of using the timer, due to the Thread.sleep((long)sleep); } else{ return true; } true ````
asfimport commented 13 years ago

Sebb (migrated from Bugzilla): (In reply to comment 10)

Created attachment 27674 [details] Included in Use.Include.jmx

Hello Sebb, As you requested, much simpler plan.

Thanks, that's better.

Not sure why the Thread Group with the module controller is present, as the top-level script still fails without it in non-GUI mode. Likewise the Transaction Controller seems to be unnecessary.

All that is needed is a Test Fragment with a single Java sampler.

asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Test plan as you requested. Sebb, about your request, I just took another plan I found in another IncludeController https://github.com/apache/jmeter/issues/2558 and tried to reproduce issue with it by changing what initial bug submitter described, once it reproduced it, I used it as is. That's why plan was initially complex.

Regards Philippe

Created attachment Test.Fragment.jmx: Included in Use.Include.jmx

Test.Fragment.jmx ````xml false false TIME_BOUND 10000 = continue false 1 1 1 1316697651000 1316697651000 false Sleep_Time 100 = Sleep_Mask 0xFF = Label = ResponseCode = ResponseMessage = Status OK = SamplerData = ResultData = org.apache.jmeter.protocol.java.test.JavaTest ````
asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Created attachment Use.Include.jmx: Includer plan

Use.Include.jmx ````xml false false TIME_BOUND 2000 = continue false 1 1 1 1316699696000 1316699696000 false Test.Fragment.jmx Test.Fragment.jmx false saveConfig true true true true true true true false true true false false true false false false false false 0 true ````
asfimport commented 13 years ago

Sebb (migrated from Bugzilla): The fix looks OK, however it causes some tests to fail.

In particular, "ant batchtest" detects differences in BatchTestLocal.csv. These show that the test plan behaves very differently.

asfimport commented 13 years ago

@pmouawad (migrated from Bugzilla): Hello Sebb, Very strange indeed, as strange as the fact that although key is here, getTree does not find its value.

I think we should fix issue related to hashCode and equals in AbstractTestElement.

Regards Philippe

asfimport commented 13 years ago

Sebb (migrated from Bugzilla): (In reply to comment 15)

Hello Sebb, Very strange indeed, as strange as the fact that although key is here, getTree does not find its value.

I think that can happen if the key changes whilst in the hash.

I think we should fix issue related to hashCode and equals in AbstractTestElement.

That should help, but as has been seen from the patch failure, the behaviour of the JMeter code is quite tricky in this area.

asfimport commented 12 years ago

Sebb (migrated from Bugzilla): The problem is in the ListedHashTree#replace method.

This updates the order of elements using the code:

order.set(order.indexOf(currentKey), newKey);

The problem is that indexOf() uses equals() to scan the LinkedList to find the matching Object. The current implementation of equals for TestElelemts compares contents. So if there are two identical Include Controllers the wrong key may be found. [This problem does not affect the tree itself, because that is a hash tree, and test elements use the identity hashcode.]

I suspect this does not affect the GUI tests because the Test Elements will then have additional properties which relate to the GUI.

The bug can be fixed by using Object equality for equals; unit tests all still work apart from TestHTTPFileArgs.testRemoving() which assumes that HTTPFileArgs are equal if they have equal contents. That could be fixed separately.

I'm not entirely sure what it means for two test elements to be truly "equal". At present, they violate the rule that equal objects must have equal hash codes.

However, changing the AbstractTestElement#equals() method is a very big change and may have unexpected consequences (apart from just HTTPFileArgs).

As a workround for this bug, the IncludeController can be fixed to use Object equals. After further testing, the fix can hopefully be extended to all test elements.

asfimport commented 12 years ago

Sebb (migrated from Bugzilla): Added workround:

URL: http://svn.apache.org/viewvc?rev=1340884&view=rev Log: https://github.com/apache/jmeter/issues/2472 - IncludeController : NullPointerException loading script in non-GUI mode if Includers use same element name

Modified: jmeter/trunk/build.xml jmeter/trunk/src/components/org/apache/jmeter/control/IncludeController.java jmeter/trunk/xdocs/changes.xml

asfimport commented 12 years ago

@pmouawad (migrated from Bugzilla): Great you fixed it Sebb . I close issue.

asfimport commented 12 years ago

Sebb (migrated from Bugzilla): Reverted IncludeController change.

Now use == rather than equals() when finding the entry in the list.

URL: http://svn.apache.org/viewvc?rev=1341670&view=rev Log: https://github.com/apache/jmeter/issues/2472 - IncludeController : NullPointerException loading script in non-GUI mode if Includers use same element name Apply better fix that applies for all elements, not just IncludeController

Modified: jmeter/trunk/src/components/org/apache/jmeter/control/IncludeController.java jmeter/trunk/src/jorphan/org/apache/jorphan/collections/ListedHashTree.java