<?xml version="1.0" encoding="UTF-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
   <title type="text">ngrinder</title>
      <subtitle type="html">ngrinder</subtitle>
      <updated>2013-05-22T16:15:38-07:00</updated>
   <id>http://www.cubrid.org/wiki_ngrinder/atom</id>
   <link rel="alternate" type="text/html" hreflang="en" href="http://www.cubrid.org/?mid=wiki_ngrinder"/>
   <link rel="self" type="application/atom+xml" href="http://www.cubrid.org/wiki_ngrinder/atom"/>
   <generator uri="http://www.xpressengine.com/" version="1.4.4.1">XpressEngine</generator>
   <entry>
      <title>Groovy Maven Structure</title>
      <id>http://www.cubrid.org/651955</id>
      <published>2013-05-06T18:49:19-07:00</published>
      <updated>2013-05-22T10:31:50-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/651955"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/651955#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;If you choose to use Groovy Script when you create a script, it works simular to Jython script except the JUnit styled test cases.    &lt;br /&gt;However if you want not only to use Groovy but also to execute JUnit runner in your IDE or easily configure dependencies, you can choose to make Groovy Maven Project first.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/955/651/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/955/651/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;351&quot; height=&quot;248&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you create Groovy Maven Project, you can have the following directories&amp;nbsp;containing&amp;nbsp;three files under the&amp;nbsp;specified&amp;nbsp;project folder.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/955/651/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/955/651/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;269&quot; height=&quot;87&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; width=&quot;595&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;250&quot;&gt;Location&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;343&quot;&gt;Description&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;250&quot;&gt;${name}/pom.xml&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;343&quot;&gt;Maven project file.          &lt;br /&gt;You can add the library dependencies in this file.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;250&quot;&gt;${name}/src/main/java/Test1.groovy&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;343&quot;&gt;Default groovy script file&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;250&quot;&gt;${name}/src/main/java/resources1.txt&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;343&quot;&gt;Default resource file&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;250&quot;&gt;${name}/lib&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;343&quot;&gt;Not automatically generated. but this folder can be used to distribute private libraries if available.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;You can import this project into you IDE using SVN checkout. You may need to check the below links.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;[Install Groovy IDE] &lt;/li&gt;    &lt;li&gt;[Import Groovy Maven Project in IDE] &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;In pom.xml, You can specify the additional library dependencies.&lt;/p&gt;  &lt;pre class=&quot;brush: xml;&quot;&gt;&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd&quot;&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
    &amp;lt;groupId&amp;gt;ngrinder&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;${name}&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.0.1&amp;lt;/version&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;jdk-version&amp;gt;1.6&amp;lt;/jdk-version&amp;gt;
        &amp;lt;source-encoding&amp;gt;UTF-8&amp;lt;/source-encoding&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;repositories&amp;gt;
        &amp;lt;repository&amp;gt;
            &amp;lt;id&amp;gt;nhnopensource.maver.repo&amp;lt;/id&amp;gt;
            &amp;lt;url&amp;gt;https://github.com/nhnopensource/nhnopensource.maven.repo/raw/master/releases&amp;lt;/url&amp;gt;
        &amp;lt;/repository&amp;gt;
    &amp;lt;/repositories&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;!-- Following dependency is mandatory --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.ngrinder&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;ngrinder-groovy&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;3.2&amp;lt;/version&amp;gt;
            &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;

        &amp;lt;!-- Add the dependencies --&amp;gt;
        &amp;lt;!--  &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;commons-io&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;commons-io&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.0.1&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
         --&amp;gt;
        &amp;lt;!-- Put your private library like this --&amp;gt;
        &amp;lt;!--  
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;your_lib&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;your_lib&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;your_lib_version&amp;lt;/version&amp;gt;
            &amp;lt;scope&amp;gt;system&amp;lt;/scope&amp;gt;
            &amp;lt;systemPath&amp;gt;${project.basedir}/lib/hello.jar&amp;lt;/systemPath&amp;gt;
        &amp;lt;/dependency&amp;gt;
        --&amp;gt;
    &amp;lt;/dependencies&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;source&amp;gt;${jdk-verion}&amp;lt;/source&amp;gt;
                    &amp;lt;target&amp;gt;${jdk-version}&amp;lt;/target&amp;gt;
                    &amp;lt;encoding&amp;gt;${source-encoding}&amp;lt;/encoding&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-eclipse-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;2.9&amp;lt;/version&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;additionalProjectnatures&amp;gt;
                        &amp;lt;projectnature&amp;gt;
                            org.eclipse.jdt.groovy.core.groovyNature
                        &amp;lt;/projectnature&amp;gt;
                        &amp;lt;projectnature&amp;gt;
                            org.eclipse.m2e.core.maven2Nature
                        &amp;lt;/projectnature&amp;gt;
                    &amp;lt;/additionalProjectnatures&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;&lt;/pre&gt;

&lt;p&gt;If you like to add the private libraries which do not exist in the public maven repository, you can put them in the lib folder directly and specify the systemPath option like the above sample. lib folder will be automatically detected and copied into agents as well when controller prepare the script distribution. 
  &lt;br /&gt;When a script is selected in the performance test configuration, controller automatically detects whether the script is under the folder ${name}/src/main/java and there is pom.xml in the base folder. Then controller will copy the files in the ${name}/src/main/resources and ${name}/src/main/java folder recursively into controller’s distribution folder before distributing them to agents. Below shows how each folders in svn are copied to the distribution folder.&lt;/p&gt;
&lt;blockquote class=&quot;q4&quot;&gt;
&lt;pre&gt;- from svn foler + pom.xml
                 + src/main/java/Test1.groovy
                                /package_names/the_other_groovyscripts
                 + src/main/resources/resources1.txt
                                     /subfolder_names/the_other_resources
                 + lib (private libraris)


- to dist folder + Test1.groovy 
                 + resources1.txt 
                 + package_names/the_other_groovy_scripts 
                 + subfolder_names/the_other_resources 
                 + lib (copied from maven dependencies and files in lib folder existing subversion)&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;In generic Jython script and Groovy script, the resources are loaded using command &quot;open(“./resources/resource1.txt”)&quot;. However this won’t work in Groovy Maven project. We had to change this path based resource discovery into the classpath based resource discovery to make Groovy JUnit test workable in IDE as well,&amp;nbsp;&lt;br /&gt;All resources in ${project_name}/src/main/resources/.. are copied into the same folder where the test script is copied but keeping the sub directory hierachy. You can load the resources using code below.&lt;/p&gt;

&lt;pre class=&quot;brush: groovy;&quot;&gt;import org.codehaus.groovy.reflection.ReflectionUtils;
....


class YourTest {
    String text;

    @BeforeThread
    public void beforeThread() {
       // In groovy, InputStream contains text field.
       text = loadResourceFromClassPath(&quot;/resource1.txt&quot;).text;
    }

    @Test
    public void doTest() {
       ....
    }

    // This is groovy way to load resource from classpath
    public loadResourceFromClassPath(String resourcePath) {
        return ReflectionUtils.getCallingClass(0).getResourceAsStream(resourcePath);
    }
}&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="groovy"/>
            <category term="script guide"/>
            
   </entry>
   <entry>
      <title>How to use library</title>
      <id>http://www.cubrid.org/502090</id>
      <published>2012-11-20T21:40:22-08:00</published>
      <updated>2013-05-08T02:13:39-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/502090"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/502090#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;h3&gt;Jython and Groovy&lt;/h3&gt;&lt;p&gt;Some guy may want to use java libraries or python py modules in the scripts. For this case, nGrinder supports upload of these files and a user can use external libraries without any system configuration. Just upload the jar or py files in the lib folder on the same location of the test script file. The files in the lib folder will be automatically passed to agents and be located in the agent classpath when the test is executed. &lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/090/502/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/090/502/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;709&quot; height=&quot;160&quot; style=&quot;background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Then You can just refer the uploaded jar or py like followings..&lt;/p&gt;    &lt;pre class=&quot;brush: py;&quot;&gt;from net.grinder.script import Test
from net.grinder.script.Grinder import grinder
from org.json.simple import JSONValue
from java.util import Random
from java.lang import String
# This library is located in the lib folder.
from mpcCaller import NpcCaller

random = Random()Z

caller = NpcCaller(&quot;xx.xx.xx.15&quot;, 7090);
module = &quot;tchat&quot;
procedure = &quot;chatBO/RelayCommand&quot;…&lt;/pre&gt;&lt;h3&gt;Groovy Maven Project&lt;/h3&gt;&lt;div&gt;If you&apos;re using Groovy Maven Project you can easily add the external libraries in the pom.xml. Please refer [Groovy Maven Structure]&lt;/div&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            
   </entry>
   <entry>
      <title>Jython Script Structure</title>
      <id>http://www.cubrid.org/651899</id>
      <published>2013-05-06T18:26:57-07:00</published>
      <updated>2013-05-08T02:13:11-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/651899"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/651899#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;nGrinder uses The Grinder Jython Script with no modification. Following is the jython template nGrinder uses.&lt;/p&gt;  &lt;pre class=&quot;brush: py;&quot;&gt;# -*- coding:utf-8 -*-

# A simple example using the HTTP plugin that shows the retrieval of a
# single page via HTTP. 
#
# This script is auto generated by ngrinder.
#
# @author ${userName}
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
from net.grinder.plugin.http import HTTPPluginControl


control = HTTPPluginControl.getConnectionDefaults()
# if you don&apos;t want that HTTPRequest follows the redirection, please modify the following option 0.
# control.followRedirects = 1
# if you want to increase the timeout, please modify the following option.
control.timeout = 6000

test1 = Test(1, &quot;mytest&quot;)
request1 = HTTPRequest()

# Make any method call on request1 increase TPS
test1.record(request1)

class TestRunner:
    # initlialize a thread 
    def __init__(self):
        grinder.statistics.delayReports=True
        pass

    # test method        
    def __call__(self):
        result = request1.GET(&quot;http://www.google.com”)
        
        # You get the message body using the getText() method.
        # if result.getText().find(&quot;HELLO WORLD&quot;) != -1 :
        #    grinder.statistics.forLastTest.success = 1
        # else :
        #     grinder.statistics.forLastTest.success = 0
            
        # if you want to print out log.. 
        # Don&apos;t use print keyword. 
        # instead use following.
        # grinder.logger.info(&quot;Hello World&quot;)
        

        if result.getStatusCode() == 200 :
            grinder.statistics.forLastTest.success = 1
        elif result.getStatusCode() in (301, 302) :
            grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was %d.&quot; %  result.getStatusCode()) 
            grinder.statistics.forLastTest.success = 1
        else :
            grinder.statistics.forLastTest.success = 0&lt;/pre&gt;

&lt;p&gt;The each process in the Grinder jython scriptengine reads the whole script and each thread executes the TestRunner’s __call__ method. 
  &lt;br /&gt;This execution can be illustrated by the following figure.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/899/651/image_6.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/899/651/image_thumb_2.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;742&quot; height=&quot;387&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When JythonScript engine creates processes, each process run the global scope script first. In above template, the following is the gloabl scope script which is executed once per process. 
  &lt;br /&gt;&lt;/p&gt;

&lt;pre class=&quot;brush: py;&quot;&gt;control = HTTPPluginControl.getConnectionDefaults()
# if you don&apos;t want that HTTPRequest follows the redirection, please modify the following option 0.
# control.followRedirects = 1
# if you want to increase the timeout, please modify the following option.
control.timeout = 6000

test1 = Test(1, &quot;mytest”)
request1 = HTTPRequest()

# Make any method call on request1 increase TPS
test1.record(request1)&lt;/pre&gt;

&lt;p&gt;In the above part, the test statistics are prepared and request1 object is instrumented to record any methods call on request1 object. 
  &lt;br /&gt;Then the multiple threads are created and each thread creates a TestRunner object by running the __init__ method.&amp;nbsp; &lt;br /&gt;__init__ method is subject to be invoked once per thread. Therefore, this method is the perfect place to login if your target system needs the login.&lt;/p&gt;

&lt;pre class=&quot;brush: py;&quot;&gt;class TestRunner:
    # initlialize a thread 
    def __init__(self):
        grinder.statistics.delayReports=True
        pass&lt;/pre&gt;

&lt;br /&gt;After creating TestRunner object, each thread continuously invokes __call__() method on the created TestRunner object until the test is finished. 

&lt;pre class=&quot;brush: py;&quot;&gt;    # test method        
    def __call__(self):
        result = request1.GET(&lt;a href=&quot;http://www.google.com&quot;&gt;http://www.google.com&lt;/a&gt;)
        
        # You get the message body using the getText() method.
        # if result.getText().find(&quot;HELLO WORLD&quot;) != -1 :
        #    grinder.statistics.forLastTest.success = 1
        # else :
        #     grinder.statistics.forLastTest.success = 0
            
        # if you want to print out log.. 
        # Don&apos;t use print keyword. 
        # instead use following.
        # grinder.logger.info(&quot;Hello World&quot;)
        

        if result.getStatusCode() == 200 :
            grinder.statistics.forLastTest.success = 1
        elif result.getStatusCode() in (301, 302) :
            grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was %d.&quot; %  result.getStatusCode()) 
            grinder.statistics.forLastTest.success = 1
        else :
            grinder.statistics.forLastTest.success = 0&lt;/pre&gt;

&lt;p&gt;When the agent gets the stop message from controller or specified run count is reached, each thread is terminated. Before thread terminations, thread invokes __del__(self) method to clean up the test. If you don’t provide this method in the test script, it’s just ignored. 
  &lt;br /&gt;When starting a test in the controller, not only script but also following folders which exists at the same folder as the script is located are transfered to the agents.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/899/651/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/899/651/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;952&quot; height=&quot;162&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All transfered library files like .class, .py, .jar located in the lib folder are automatically are set a library path.&amp;nbsp; Therefore you can extend the test script to use 3rd party library. In addition, you can locate any resources in the resources folder. The resources can be opened by calling 
  &lt;br /&gt;&lt;/p&gt;

&lt;pre class=&quot;brush: py;&quot;&gt;open(&quot;./resources/resource_file_name.txt&quot;)&lt;/pre&gt;

&lt;p&gt;Please check out [How to use library] and [How to use resources] for detailed instruction.&lt;/p&gt;

&lt;p&gt;However, from nGrinder 3.2, we start to support Groovy as a scripting language. We believe this is much powerful way. Check out [Groovy Script Structure] as well for the detailed instruction.&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="groovy"/>
            
   </entry>
   <entry>
      <title>Groovy Script</title>
      <id>http://www.cubrid.org/650855</id>
      <published>2013-05-05T20:26:38-07:00</published>
      <updated>2013-05-08T02:08:13-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/650855"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/650855#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;nGrinder 3.2 supports Groovy as scripting language. It’s not a just replacement of jython but also new test script development model. When you decide to write scripts with groovy in maven structure, you can reuse the exiting full development experiences from JUnit and Eclipse development enviornments.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;[Groovy Script Structure]&lt;/li&gt;    &lt;li&gt;[Groovy Maven Structure]&lt;/li&gt;    &lt;li&gt;[Install Groovy IDE]&lt;/li&gt; &lt;!--EndFragment--&gt;    &lt;li&gt;[Import Groovy Maven Project in IDE]&lt;/li&gt;
&lt;/ul&gt;Groovy is not only&amp;nbsp;convenient&amp;nbsp;to write but also efficient to execute. Our benchmark result shows that the Groovy script which does same job as Jython script can have 2 times more virtual user count(especially thread count) per agent.&lt;ul&gt; &lt;/ul&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="groovy"/>
            <category term="script guide"/>
            
   </entry>
   <entry>
      <title>Using nGrinder to perform load test for a socket.io app</title>
      <id>http://www.cubrid.org/608603</id>
      <published>2013-03-10T21:31:59-07:00</published>
      <updated>2013-05-07T22:52:53-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/608603"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/608603#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;nGrinder can not only be used to test the normal web application, but also can be used for JDBC, web service and realtime apps like socket.io provides.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://socket.io&quot;&gt;Socket.io&lt;/a&gt; aims to make realtime apps possible in every browser and mobile device. With the extensibility of nGrinder, we can test a socket.io based app with the help of extended library. We can use this &lt;a href=&quot;https://github.com/Gottox/socket.io-java-client&quot;&gt;socket.io-java-client&lt;/a&gt; library to do it.&lt;/p&gt;  &lt;p&gt;But this library use an async way to send request and receive response. So we need some modification based on the SocketIO class to do it in a synchronized way.&lt;/p&gt;  &lt;p&gt;If you are not familiar with the&amp;nbsp; &lt;a href=&quot;https://github.com/Gottox/socket.io-java-client&quot;&gt;socket.io-java-client&lt;/a&gt; , please go to get the code and check the example in it. &lt;/p&gt;  &lt;p&gt;The main idea is, using the SocketIO object to create a connection to the app server, and provide a function to send request to server, and get the response and return. And in this example, I use Java Lock and Condition to archive this.&lt;/p&gt;  &lt;p&gt;And below is the source of BlockingSocketIO class:&lt;/p&gt;  &lt;pre class=&quot;brush: java; auto-links: false;&quot;&gt;package my;

import io.socket.IOAcknowledge;
import io.socket.IOCallback;
import io.socket.SocketIO;
import io.socket.SocketIOException;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import org.json.JSONObject;

/**
 * Class description.
 *
 * @author Mavlarn
 * @since
 */
public class BlockingSocketIO implements IOCallback {
    
    private SocketIO socketIO;
    private ReentrantLock transportLock;
    private Condition responseCondition;
    private String respMsg;
    
    public BlockingSocketIO (String url) {
        try {
            transportLock = new ReentrantLock();
            responseCondition = transportLock.newCondition();
            socketIO = new SocketIO(url, this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public String sendAndRcv (final String message) {
        try {
            transportLock.lock();
            socketIO.send(message);
            respMsg = null;
            responseCondition.await();
            return respMsg;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            transportLock.unlock();
        }
        return respMsg;
    }
    
    public String sendAndRcv(final JSONObject json) {
        try {
            transportLock.lock();
            socketIO.send(json);
            respMsg = null;
            responseCondition.await();
            return respMsg;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            transportLock.unlock();
        }
        return respMsg;
    }

    public String emitAndRcv(String event, final Object args) {
        try {
            transportLock.lock();
            socketIO.emit(event, args);
            respMsg = null;
            responseCondition.await();
            return respMsg;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            transportLock.unlock();
        }
        return respMsg;
    }

    @Override
    public void onMessage(JSONObject json, IOAcknowledge ack) {
        setResponse(json.toString());
    }

    @Override
    public void onMessage(String data, IOAcknowledge ack) {
        setResponse(data);
    }

    private void setResponse(String data) {
        try {
            transportLock.lock();
            respMsg = data;
            responseCondition.signal();
            System.out.println(&quot;Server said:&quot; + data);
        } finally {
            transportLock.unlock();
        }
    }

    @Override
    public void onError(SocketIOException socketIOException) {
        System.out.println(&quot;an Error occured&quot;);
        socketIOException.printStackTrace();
    }

    @Override
    public void onDisconnect() {
        System.out.println(&quot;Connection terminated.&quot;);
    }

    @Override
    public void onConnect() {
        System.out.println(&quot;Connection established&quot;);
    }

    @Override
    public void on(String event, IOAcknowledge ack, Object... args) {
        System.out.println(&quot;Server triggered event &apos;&quot; + event + &quot;&apos;&quot;);
        setResponse(args[[0].toString());
    }

}&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;In this class, I use &lt;a href=&quot;https://github.com/Gottox/socket.io-java-client&quot;&gt;socket.io-java-client&lt;/a&gt; library to send message to socket.io server, and get response with the help of Lock and Condition.&lt;/p&gt;

&lt;p&gt;And we need to package this class in jar and upload it into lib folder in nGrinder. You should also upload socketio.jar and its dependency libs WebSocket.jar and json-org.jar.&lt;/p&gt;

&lt;p&gt;And next, we need&amp;nbsp; the python script for test in nGrinder.&amp;nbsp; It will be as below:&lt;/p&gt;

&lt;pre class=&quot;brush: py; auto-links: false;&quot;&gt;from net.grinder.script.Grinder import grinder
from net.grinder.script import Test

from org.json import JSONObject
from my import BlockingSocketIO

test1 = Test(1, &quot;Test1&quot;)

class TestRunner:

    def testSocketIO(self):
        json = JSONObject()
        user = &quot;Thread-%s&quot; % grinder.threadNumber
        json.putOpt(&quot;user&quot;, user)
        msg = &quot;test message&amp;lt;%s&amp;gt;.&quot; % user
        json.putOpt(&quot;message&quot;, msg)
        grinder.logger.info(&quot;msg:&quot; + json.toString())
        respMsg = self.socketIO.emitAndRcv(&quot;user message&quot;, json)
        return respMsg
    
    def __init__(self):
        grinder.statistics.delayReports=True
        #init socket io
        #create socket io object in thread init function. Then every thread will use its own socket.io connection.
        self.socketIO = BlockingSocketIO(&quot;http://127.0.0.1:3000&quot;)
        
        #send socket.io server to init user
        json = JSONObject()
        user = &quot;Thread-%s&quot; % grinder.threadNumber
        json.putOpt(&quot;username&quot;, user)
        self.socketIO.emitAndRcv(&quot;user&quot;, json)

    # test method        
    def __call__(self):
        resp = self.testSocketIO()

        if &quot;test message&quot; in resp :
            grinder.statistics.forLastTest.success = 1
        else :
            grinder.statistics.forLastTest.success = 0

test1.record(TestRunner.testSocketIO)&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;In this script, in the init function of test runner, we created a socket.op connection object, then all the tests of this thread will use the same connection. It is very important for the long pooling app based on socket.io. And in thie init function, a message with “user” event in sent to server to init the user in server side. And in every test function, we will send a message with “user message” event.&lt;/p&gt;

&lt;p&gt;Before we can test this script, we need a server side app. We need node.js installed with the module “socket.io”.&lt;/p&gt;

&lt;p&gt;And write a script as below, which is named server.js:&lt;/p&gt;

&lt;pre class=&quot;brush: js; auto-links: false;&quot;&gt;var http = require(&apos;http&apos;), io = require(&apos;socket.io&apos;);

var app = http.createServer();
app.listen(3000);

console.log(&apos;Server running at http://127.0.0.1:3000/&apos;);

// Socket.IO server
var io = io.listen(app);

io.sockets.on(&apos;connection&apos;, function (socket) {
  console.log(&quot;new connection from&quot; + socket); get and log connection
  socket.on(&apos;user message&apos;, function (msg) {  //accept a request with “user message” event
    socket.emit(&apos;user message processed&apos;, {user: msg.user, message: msg.message});
  });

  socket.on(&apos;user&apos;, function (userMsg) { //accept a request with “user” event, like user login.
    socket.user = userMsg.username;
    socket.emit(&apos;user processed&apos;, {user: userMsg.user, message: &quot;New user come in.&quot;});
  });

  socket.on(&apos;disconnect&apos;, function () {
    if (!socket.user) return;
    socket.emit(&apos;announcement&apos;, {user: socket.user, action: &apos;disconected&apos;});
  });
});&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;And run this simulated server with :&lt;/p&gt;

&lt;pre class=&quot;brush: ps; auto-links: false;&quot;&gt;node server.js&lt;/pre&gt;

&lt;p&gt;You should see a log said the server is running at http://127.0.0.1:3000/.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Then, validate this script to make sure it can work properly. The validation result should be as below:&lt;/p&gt;

&lt;pre class=&quot;brush: plain; auto-links: false;&quot;&gt;2013-03-11 13:13:08,844 INFO  elapsed time is 17 ms
2013-03-11 13:13:08,844 INFO  Final statistics for this process:
2013-03-11 13:13:08,854 INFO  
             Tests        Errors       Mean Test    Test Time    TPS          
                                       Time (ms)    Standard                  
                                                    Deviation                 
                                                    (ms)                      

Test 1       1            0            3.00         0.00         58.82         &quot;Test1&quot;

Totals       1            0            3.00         0.00         58.82        

  Tests resulting in error only contribute to the Errors column.          
  Statistics for individual tests can be found in the data file, including
  (possibly incomplete) statistics for erroneous tests. Composite tests   
  are marked with () and not included in the totals.                      


……
2013-03-11 13:13:08,750 INFO  validation-0: starting threads
Mar 11, 2013 1:13:08 PM io.socket.IOConnection sendPlain
INFO: &amp;gt; 5:::{&quot;args&quot;:[{&quot;username&quot;:&quot;Thread-0&quot;}],&quot;name&quot;:&quot;user&quot;}
Mar 11, 2013 1:13:08 PM io.socket.IOConnection transportMessage
INFO: &amp;lt; 1::
Connection established
Mar 11, 2013 1:13:08 PM io.socket.IOConnection transportMessage
INFO: &amp;lt; 5:::{&quot;name&quot;:&quot;user processed&quot;,&quot;args&quot;:[{&quot;message&quot;:&quot;New user come in.&quot;}]}
Server triggered event &apos;user processed&apos;
Server said:{&quot;message&quot;:&quot;New user come in.&quot;}
Mar 11, 2013 1:13:08 PM io.socket.IOConnection sendPlain
INFO: &amp;gt; 5:::{&quot;args&quot;:[{&quot;message&quot;:&quot;test message&amp;lt;Thread-0&amp;gt;.&quot;,&quot;user&quot;:&quot;Thread-0&quot;}],&quot;name&quot;:&quot;user message&quot;}
Mar 11, 2013 1:13:08 PM io.socket.IOConnection transportMessage
INFO: &amp;lt; 5:::{&quot;name&quot;:&quot;user message processed&quot;,&quot;args&quot;:[{&quot;user&quot;:&quot;Thread-0&quot;,&quot;message&quot;:&quot;test message&amp;lt;Thread-0&amp;gt;.&quot;}&amp;amp;a93;}
Server triggered event &apos;user message processed&apos;
Server said:{&quot;message&quot;:&quot;test message&amp;lt;Thread-0&amp;gt;.&quot;,&quot;user&quot;:&quot;Thread-0&quot;}
2013-03-11 13:13:08,855 INFO  validation-0: finished&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;From the result message, we can see that the test is successful, and the server processed 2 request, one is “user”, another is “user message”. For the user name, I use the “Thread-[thread number]”we should see the different name if we test with multiple vuser.&lt;/p&gt;

&lt;p&gt;The server side log should be similar as this:&lt;/p&gt;

&lt;pre class=&quot;brush: ps; auto-links: false;&quot;&gt;debug - client authorized
info - handshake authorized gr0AYzAn7sAKTE_XsORt
debug - setting request GET /socket.io/1/websocket/gr0AYzAn7sAKTE_XsORt
debug - set heartbeat interval for client gr0AYzAn7sAKTE_XsORt
debug - client authorized for 
debug - websocket writing 1::
new connection from[object Object]
debug - websocket writing 5:::{&quot;name&quot;:&quot;user processed&quot;,&quot;args&quot;:[{&quot;message&quot;:&quot;New user come in.&quot;}]}
debug - websocket writing 5:::{&quot;name&quot;:&quot;user message processed&quot;,&quot;args&quot;:[{&quot;user&quot;:&quot;Thread-0&quot;,&quot;message&quot;:&quot;test message&amp;lt;Thread-0&amp;gt;.&quot;}]}
info - transport end (socket end)
debug - set close timeout for client gr0AYzAn7sAKTE_XsORt
debug - cleared close timeout for client gr0AYzAn7sAKTE_XsORt
debug - cleared heartbeat interval for client gr0AYzAn7sAKTE_XsORt
debug - discarding transport&lt;/pre&gt;

&lt;p&gt;The server log said, it got a client connection, and succeed to handshake, and processed 2 request. And at last, the client is disconnected.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Then we can create a test with this script to test with nGrinder.&lt;/p&gt;

&lt;p&gt;Below is the final report:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://www.cubrid.org/./files/attach/images/379199/603/608/report.png&quot; alt=&quot;NewImage&quot; title=&quot;NewImage&quot; class=&quot;iePngFix&quot; width=&quot;800&quot; height=&quot;579&quot; style=&quot;&quot; /&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;At last, don’t forget to check the server log:&lt;/p&gt;

&lt;pre class=&quot;brush: plain; auto-links: false;&quot;&gt;   ......
   info  - transport end (socket end)
   debug - set close timeout for client JFrRHYoO3__jN4pdsOSi
   debug - cleared close timeout for client JFrRHYoO3__jN4pdsOSi
   debug - cleared heartbeat interval for client JFrRHYoO3__jN4pdsOSi
   debug - discarding transport
   info  - transport end (socket end)
   debug - set close timeout for client pDHSiLJhTXaqVR5osOSk
   debug - cleared close timeout for client pDHSiLJhTXaqVR5osOSk
   debug - cleared heartbeat interval for client pDHSiLJhTXaqVR5osOSk
   debug - discarding transport
   info  - transport end (socket end)
   debug - set close timeout for client 7u_rypQFSZ2vcTGKsOSj
   debug - cleared close timeout for client 7u_rypQFSZ2vcTGKsOSj
   debug - cleared heartbeat interval for client 7u_rypQFSZ2vcTGKsOSj
   debug - discarding transport
   info  - transport end (socket end)
   debug - set close timeout for client fmxnHFQ_U-wsCmdMsOSg
   debug - cleared close timeout for client fmxnHFQ_U-wsCmdMsOSg
   debug - cleared heartbeat interval for client fmxnHFQ_U-wsCmdMsOSg
   debug - discarding transport&lt;/pre&gt;

&lt;p&gt;In the server log, there should be some log to say that the connection is discarded. In this test, the vuser is 10, so in the log, there should be 10 times of “discarding transport”. It means that, one vuser is simulated as one actual user with one connection. I you don’t want to use one connection for one thread, you can move the code :&lt;/p&gt;

&lt;pre class=&quot;brush: java; auto-links: false;&quot;&gt;socketIO = BlockingSocketIO(&quot;http://127.0.0.1:3000&quot;)&lt;/pre&gt;
to above of TestRunner, then all thread in this process will use the same connection.

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;By the way, the node server is running on my note book. From the TPS and mean time, we can see that the performance of socket.io server is really impressive. Please check the attachment for the java libs used by this test.&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;&lt;embed type=&quot;application/thunder_download_plugin&quot; width=&quot;0&quot; height=&quot;0&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="socket.io"/>
            <category term="load test"/>
            
   </entry>
   <entry>
      <title>How to run the multiple tests with different weight</title>
      <id>http://www.cubrid.org/546775</id>
      <published>2013-01-07T20:44:51-08:00</published>
      <updated>2013-05-07T22:31:32-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/546775"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/546775#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;The real user is not simple. There might have multiple usage scenarios for the target system. If you want to simulate this on The Grinder script, you may need to run multiple tests with different weight.&lt;/p&gt;  &lt;p&gt;With following The Grinder script technique, it’s possible to simulate this case. You can upload the each scenarios in the &lt;b&gt;lib &lt;/b&gt;folder(refer [How to use library]) and create the test script which control each test scenario like following.&lt;/p&gt;

&lt;h4&gt;  Jython&lt;/h4&gt;&lt;pre class=&quot;brush: py;&quot;&gt;# Run test scripts in parallel
# Run TestScript1 in 50% of threads, TestScript2 in 30% of threads,
# and TestScript3 in 20% of threads.

from net.grinder.script.Grinder import grinder

 
# You can locate Scenario1,2,3.py files in the lib folder.
scripts = 〔&quot;Scenario1&quot;, &quot;Scenario2&quot;, &quot;Scenario2&quot;〕


# Ensure modules are initialised in the process thread.
for script in scripts: exec(&quot;import %s&quot; % script)

def createTestRunner(script):
    exec(&quot;x = %s.TestRunner()&quot; % script)
    return x

class TestRunner:
    def __init__(self):
        tid = grinder.threadNumber
        s = tid % 10
        if s in range(1,5):
            self.testRunner = createTestRunner(scripts〔0〕)
        elif s in range(6,8):
            self.testRunner = createTestRunner(scripts〔1〕)
        else:
            self.testRunner = createTestRunner(scripts〔2〕)

    # This method is called for every run.
    def __call__(self):
        self.testRunner()&lt;/pre&gt;&lt;h4&gt;
Groovy
&lt;/h4&gt;&lt;pre class=&quot;brush: groovy;&quot;&gt;	@Test
	public void test(){
		switch (grinder.threadNumber % 10) {
			case 1..5:
				doTest1()
				break
			case 6..8:
				doTest2()
				break
			default :
				doTest3()
				break
		}
	}

	public void doTest1() {
		...
	}

	public void doTest2() {
		...
	}

	public void doTest3() {
		...
	}&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>User defined statistic in nGrinder</title>
      <id>http://www.cubrid.org/592353</id>
      <published>2013-02-21T22:57:06-08:00</published>
      <updated>2013-05-07T22:24:48-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/592353"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/592353#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Maybe you know that &quot;The Grinder&quot; supports user defined statistic. If you define and put some value in the script, then this filed can be saved in data log or summary data. You can check the example script for this from:&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;http://grinder.sourceforge.net/g3/script-gallery.html#jmssender.py&quot; target=&quot;_blank&quot;&gt;http://grinder.sourceforge.net/g3/script-gallery.html#jmsreceiver.py&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But in ngrinder, in previous 3.1.2 version, you can not see that data in test report. But from version 3.1.2, you can see that data in report chart.&lt;/p&gt;  &lt;p&gt;The sample script is below:&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;font-size: 14px; font-weight: bold; line-height: 26px; text-transform: uppercase;&quot;&gt;Jython&lt;/span&gt;&lt;/p&gt;  &lt;pre class=&quot;brush: py; auto-links: false;&quot;&gt;# -*- coding:utf-8 -*-

# A simple example using the HTTP plugin that shows the retrieval of a
# single page via HTTP. 
#
# This script is auto generated by ngrinder.
#
# @author admin
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
from net.grinder.plugin.http import HTTPPluginControl
from java.util import Random

control = HTTPPluginControl.getConnectionDefaults()
# if you don&apos;t want that HTTPRequest follows the redirection, please modify the following option 0.
# control.followRedirects = 1
# if you want to increase the timeout, please modify the following option.
control.timeout = 6000

test1 = Test(1, &quot;Test1&quot;)
request1 = HTTPRequest()

#grinder.statistics.registerDataLogExpression(&quot;Delivery time&quot;, &quot;userLong0&quot;)
grinder.statistics.registerSummaryExpression(&quot;User_defined&quot;, &quot;(/ userLong0(+ (count timedTests)))&quot;)
                        
# Make any method call on request1 increase TPS
test1.record(request1)
random = Random()

class TestRunner:
	# initlialize a thread 
	def __init__(self):
		grinder.statistics.delayReports=True
		pass

	# test method		
	def __call__(self):
		result = request1.GET(&quot;http://www.naver.com&quot;)
		
		# do something
		deliveryTime = random.nextInt(1000)
		grinder.sleep(deliveryTime)
		grinder.logger.info(&quot;deliveryTime: %d&quot; % deliveryTime)
		grinder.statistics.forLastTest.setLong(&quot;userLong0&quot;, deliveryTime)
		
		if result.getStatusCode() == 200 :
			grinder.statistics.forLastTest.success = 1
		elif result.getStatusCode() in (301, 302) :
			grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was %d.&quot; %  result.getStatusCode()) 
			grinder.statistics.forLastTest.success = 1
		else :
			grinder.statistics.forLastTest.success = 0&lt;/pre&gt;&lt;h4&gt;
Groovy
&lt;/h4&gt;&lt;pre class=&quot;brush: groovy; auto-links: false;&quot;&gt;@RunWith(GrinderRunner)
class Test1 {

	public static GTest test;
	public static HTTPRequest request;

	@BeforeProcess
	public static void beforeClass() {
		test = new GTest(1, &quot;aa000000&quot;);
		// Register a custom statistics
		grinder.statistics.registerSummaryExpression(&quot;User_defined&quot;, &quot;(/ userLong0(+ (count timedTests)))&quot;)
		request = new HTTPRequest();
		test.record(request);
		grinder.logger.info(&quot;before process.&quot;);
	}
	
	Random random = new Random();
	
	@BeforeThread
	public void beforeThread() {
		grinder.statistics.delayReports=true;
		grinder.logger.info(&quot;before thread.&quot;);
	}


	@Test
	public void test(){
		HTTPResponse result = request.GET(&quot;http://www.google.com&quot;);
		def deliveryTime = random.nextInt(1000)
		grinder.sleep(deliveryTime)
		grinder.logger.info(&quot;deliveryTime: ${deliveryTime}&quot;)
		// Update statistics
		grinder.statistics.forLastTest.setLong(&quot;userLong0&quot;, deliveryTime)
		
		if (result.statusCode == 301 || result.statusCode == 302) {
			grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was {}.&quot;, result.statusCode);
		} else {
			assertThat(result.statusCode, is(200));
		}
	}
&lt;/pre&gt;
&lt;p&gt;Currently, only one chart can be displayed for the user defined statistic, and the name of this statistic should be “User_defined”.&amp;nbsp;For more detailed description of usage, you can refer the document of grinder: &lt;a href=&quot;http://grinder.sourceforge.net/g3/script-javadoc/net/grinder/script/Statistics.html#registerSummaryExpression(java.lang.String, java.lang.String)&quot; target=&quot;_blank&quot;&gt;registerSummaryExpression&lt;/a&gt;. After running a test with this script, you can see the chart for user defined statistics in the detailed report.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/353/592/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/353/592/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;653&quot; height=&quot;662&quot; style=&quot;border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            <category term="user-defined"/>
            <category term="statistic"/>
            
   </entry>
   <entry>
      <title>How to handle the big response</title>
      <id>http://www.cubrid.org/594309</id>
      <published>2013-02-24T18:11:23-08:00</published>
      <updated>2013-05-07T22:20:01-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/594309"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/594309#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;div&gt;Some performance testing script may return a significant amount of response. This situation occurs when you try to download the file and test video in the script especially. Because nGrinder is configured to use at maximum 1GB memory per one process, the each thread can use 100MB if 10 threads per a process are invoked. Considering the variety of other overhead, the maximum response nGrinder can handle might be about 50 mega per request. if the each response is over this amount, nGrinder agent might cause OOM error.&lt;/div&gt;  &lt;div&gt;&amp;nbsp;&lt;/div&gt;  &lt;div&gt;The easiest way to solve this problem is to reduce the number of threads and to increase the number of processes. Instead of this solution, you can make script not to read whole response to save memory if the whole response read is not necessary. Please refer to the following code.&lt;/div&gt;

&lt;h4&gt;Jython&lt;span style=&quot;font-size: 13px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/h4&gt;  &lt;pre class=&quot;brush: py;&quot;&gt;from jarray import zeros
 
 
request1 = HTTPRequest()
# set this not to read whole response when the GET/POST is called.
request1.setReadResponseBody(False)
# Make any method call on request1 increase TPS
test1.record(request1)
 
 
class TestRunner:
    # initlialize a thread 
    def __init__(self):
        grinder.statistics.delayReports=True
        pass
 
    # test method        
    def __call__(self):
        result = request1.GET(&quot;http://www.naver.com&quot;)
        # create a buffer.. 
        buf = zeros(1024, &apos;b&apos;)
        # read only 1024 byte from input stream 
        stream = result.getInputStream();
        stream.read(buf)
        stream.close()
 
......&lt;/pre&gt;&lt;h4&gt;

Groovy
 &lt;/h4&gt;&lt;pre class=&quot;brush: groovy;&quot;&gt;@RunWith(GrinderRunner)
class Test1 {

	public static GTest test;
	public static HTTPRequest request;

	@BeforeProcess
	public static void beforeClass() {
		test = new GTest(1, &quot;aa000000&quot;);
		request = new HTTPRequest();
		// Make not to read whole response.
		request.setReadResponseBody(false);
		test.record(request);
		grinder.logger.info(&quot;before process.&quot;);
	}
	
	// Prepare buffer
	byte[] buffer = new byte&amp;#91;1000&amp;#93;;

	@BeforeThread
	public void beforeThread() {
		grinder.statistics.delayReports=true;
		grinder.logger.info(&quot;before thread.&quot;);
	}


	@Test
	public void test(){
		HTTPResponse result = request.GET(&quot;http://www.google.com&quot;);

		// Read only 1000 byte and close the stream
		def stream = result.getInputStream();
		stream.read(buffer);
		stream.close();

		if (result.statusCode == 301 || result.statusCode == 302) {
			grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was {}.&quot;, result.statusCode);
		} else {
			assertThat(result.statusCode, is(200));
		}
	}
}&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>How to use resources</title>
      <id>http://www.cubrid.org/546659</id>
      <published>2013-01-07T19:37:43-08:00</published>
      <updated>2013-05-07T22:16:19-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/546659"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/546659#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;h3&gt;Jython and generic Groovy&lt;/h3&gt;&lt;p&gt;Some users want to use txt or xml files to externalize the resources from scripts. For example, if you have a bunch of user ids and need to test some system with those ids, keeping all ids in the script is not realistic. Instead, you can use resources files which nGrinder supports. Only following file type are distributable&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;json, csv, txt, properties&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;

&lt;p&gt;To use resources files, you can create resources folder at the same location with the script.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/659/546/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/659/546/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;624&quot; height=&quot;141&quot; style=&quot;background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The resources folder containing multiple resource files will be passed to the agents during the test execution. In the script you can refer the these resources&amp;nbsp; like following code.&lt;/p&gt;

&lt;h4&gt;Jython&lt;/h4&gt;      &lt;pre class=&quot;brush: py;&quot;&gt;from net.grinder.script import Test
from net.grinder.script.Grinder import grinder
from net.grinder.plugin.http import HTTPRequest                                                             

test1 = Test(1, &quot;Test1&quot;)
test_host = &quot;http://www.sample.com&quot;
request1 = test1.wrap(HTTPRequest(url=test_host))

test_query_file = &quot;./resources/rows_10.txt&quot;


class TestRunner:
    def __init__(self):
        self.urlCount = 0
        self.urlList = []
        
        try:
            fpQuery = open(test_query_file, &quot;r&quot;) 
            ....&lt;/pre&gt;&lt;h3&gt;
&lt;/h3&gt;&lt;h4&gt;Generic Groovy&lt;/h4&gt;&lt;div&gt;Generic groovy without maven project structure does exactly same resource action as Jython. You can get the resource using new File(&quot;./resources/resource_name&quot;). Please notice that&amp;nbsp;File object in Groovy contains text field for easy file manipulation.&lt;/div&gt; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;pre class=&quot;brush: groovy;&quot;&gt;String text
	@BeforeThread
	public void beforeThread() {
		grinder.statistics.delayReports=true;
		grinder.logger.info(&quot;before thread.&quot;);
		text = new File(&quot;./resources/resource1.txt&quot;).text;
	}
	
	
	@Test
	public void test(){
		println(text)
		HTTPResponse result = request.GET(&quot;http://www.google.com&quot;);
		if (result.statusCode == 301 || result.statusCode == 302) {
			grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was {}.&quot;, result.statusCode);
		} else {
			assertThat(result.statusCode, is(200));
		}
	}
&lt;/pre&gt;
&lt;h3&gt;Groovy Maven Project&lt;/h3&gt;&lt;div&gt;However &amp;nbsp;the above method does not work if you&apos;re using Groovy Maven Project.&amp;nbsp;&lt;/div&gt;

&lt;div&gt;It&apos;s because the resource discovery is changed to classpath based in Groovy Maven Project.&amp;nbsp;&lt;/div&gt;

&lt;div&gt;Please refer [Groovy Maven Structure] to know how to open resources.&lt;/div&gt;

&lt;pre class=&quot;brush: groovy;&quot;&gt;import org.codehaus.groovy.reflection.ReflectionUtils;
....
 
 
class YourTest {
    String text;
 
    @BeforeThread
    public void beforeThread() {
       // In groovy, InputStream contains text field.
       text = loadResourceFromClassPath(&quot;/resource1.txt&quot;).text;
    }
 
    @Test
    public void doTest() {
       ....
    }
 
    // This is groovy way to load resource from classpath
    public loadResourceFromClassPath(String resourcePath) {
        return ReflectionUtils.getCallingClass(0).getResourceAsStream(resourcePath);
    }
}
&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>How to parse XML</title>
      <id>http://www.cubrid.org/576354</id>
      <published>2013-02-05T17:18:33-08:00</published>
      <updated>2013-05-07T22:12:13-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/576354"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/576354#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Sometimes it’s necessary to analyze data returned from server and&amp;nbsp; put the value to another request. Actually, we don’t recommend to use “Parsing”&amp;nbsp;because&amp;nbsp;it’s very expensive processing and eventually&amp;nbsp;decrease&amp;nbsp;the whole agent performance. It’s always better to use&amp;nbsp;regular&amp;nbsp;expression to extract some data from the returned data. However if you really need to parse XML, you can do it easily.&lt;/p&gt;

&lt;h4&gt;Jython&lt;/h4&gt;&lt;p&gt;You can use ElementTree parser which nGrinder 3.1.1 and above has.&lt;/p&gt;  &lt;pre class=&quot;brush: py;&quot;&gt;from xml.etree import ElementTree
xmlstring = &quot;&quot;&quot;
&amp;lt;hello&amp;gt;
    &amp;lt;world&amp;gt;
        WOW
    &amp;lt;/world&amp;gt;
    &amp;lt;my&amp;gt;
        &amp;lt;ngrinder&amp;gt;
            GOOD!!
        &amp;lt;/ngrinder&amp;gt;
    &amp;lt;/my&amp;gt;
&amp;lt;/hello&amp;gt;&quot;&quot;&quot;
mydom = ElementTree.fromstring(xmlstring)
# XPATH
grinder.logger.info(mydom.findall(&amp;#91;0&amp;#93;.text)&lt;/pre&gt;

&lt;p&gt;The result will be “GOOD&quot;!!”. Please refer &lt;a href=&quot;http://docs.python.org/2/library/xml.etree.elementtree.html&quot;&gt;http://docs.python.org/2/library/xml.etree.elementtree.html&lt;/a&gt; for the detailed API usage.&lt;/p&gt;

&lt;p&gt;&lt;span style=&quot;font-size: 14px; font-weight: bold; line-height: 26px; text-transform: uppercase;&quot;&gt;Groovy&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;brush: groovy;&quot;&gt;def message = &quot;&quot;&quot; 
    &amp;lt;hello&amp;gt;
    &amp;lt;world&amp;gt;
        WOW
    &amp;lt;/world&amp;gt;
    &amp;lt;world a=&quot;wow_attr&quot;&amp;gt;
        WOW2
    &amp;lt;/world&amp;gt;
    &amp;lt;my&amp;gt;
        &amp;lt;ngrinder&amp;gt;
            GOOD!!
        &amp;lt;/ngrinder&amp;gt;
    &amp;lt;/my&amp;gt;
&amp;lt;/hello&amp;gt;&quot;&quot;&quot;
def hello = new XmlParser().parseText(message);
grinder.logger.info(hello.world&amp;#91;1&amp;#93;.text())
grinder.logger.info(hello.world&amp;#91;1&amp;#93;.&apos;@a&apos;)&lt;/pre&gt;

This will print &quot;WOW2&quot; and &quot;wow_attr&quot;. Please refer the detailed &lt;a href=&quot;http://groovy.codehaus.org/Reading+XML+using+Groovy&apos;s+XmlParser&quot; target=&quot;_self&quot;&gt;API usage&lt;/a&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>How to parse JSON</title>
      <id>http://www.cubrid.org/573944</id>
      <published>2013-02-03T17:55:22-08:00</published>
      <updated>2013-05-07T21:23:16-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/573944"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/573944#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;nGrinder 3.1.1 contains json.jar, one of most famous Json parser(provided from &lt;a href=&quot;http://www.json.org&quot;&gt;www.json.org&lt;/a&gt;). You can easily parse json string with this library.    &lt;br /&gt;You can use this like the following.&lt;/p&gt;  &lt;h4&gt;JYTHON&lt;/h4&gt;  &lt;pre class=&quot;brush: python;&quot;&gt;from org.json import JSONObject 

message = &quot;&quot;&quot; 
{ 
  &quot;glossary&quot;: { 
     &quot;title&quot;: &quot;example glossary&quot;, 
        &quot;GlossDiv&quot;: { 
           &quot;title&quot;: &quot;S&quot;, 
           &quot;GlossList&quot;: { 
              &quot;GlossEntry&quot;: { 
                 &quot;ID&quot;: &quot;SGML&quot;, 
                 &quot;SortAs&quot;: &quot;SGML&quot;, 
                 &quot;GlossTerm&quot;: &quot;Standard Generalized Markup Language&quot;, 
                 &quot;Acronym&quot;: &quot;SGML&quot;, 
                 &quot;Abbrev&quot;: &quot;ISO 8879:1986&quot;, 
                 &quot;GlossDef&quot;: { 
                    &quot;para&quot;: &quot;A meta-markup language, used to create markup languages such as DocBook.&quot;
                 }, 
                 &quot;GlossSee&quot;: &quot;markup&quot; 
            } 
         } 
      } 
  } 
} 
&quot;&quot;&quot; 

json = JSONObject(message) 
grinder.logger.info(json.get(&quot;glossary&quot;).getString(&quot;title&quot;)) &lt;/pre&gt;&lt;h4&gt;

GROOVY&lt;/h4&gt;&lt;div&gt;For groovy you can use JsonSlurper instead.&lt;/div&gt;
 &lt;pre class=&quot;brush: groovy;&quot;&gt;import groovy.json.JsonSlurper


....
def message = &quot;&quot;&quot; 
{ 
  &quot;glossary&quot;: { 
     &quot;title&quot;: &quot;example glossary&quot;, 
        &quot;GlossDiv&quot;: { 
           &quot;title&quot;: &quot;S&quot;, 
           &quot;GlossList&quot;: { 
              &quot;GlossEntry&quot;: { 
                 &quot;ID&quot;: &quot;SGML&quot;, 
                 &quot;SortAs&quot;: &quot;SGML&quot;, 
                 &quot;GlossTerm&quot;: &quot;Standard Generalized Markup Language&quot;, 
                 &quot;Acronym&quot;: &quot;SGML&quot;, 
                 &quot;Abbrev&quot;: &quot;ISO 8879:1986&quot;, 
                 &quot;GlossDef&quot;: { 
                    &quot;para&quot;: &quot;A meta-markup language, used to create markup languages such as DocBook.&quot;
                 }, 
                 &quot;GlossSee&quot;: &quot;markup&quot; 
            } 
         } 
      } 
  } 
}&quot;&quot;&quot;
def jsonMsg = new JsonSlurper().parseText(message)
grinder.logger.info(jsonMsg.glossary.title)&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>How to adjust logger level</title>
      <id>http://www.cubrid.org/546596</id>
      <published>2013-01-07T18:14:22-08:00</published>
      <updated>2013-05-07T21:04:11-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/546596"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/546596#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Whenever a script calls the HTTP GET/POST method, each HTTP call is recorded at the log files in the agent&apos;s side. A log files are created per process and threads belonging to a process use a single log file.&amp;nbsp;Logs can be huge(Giga byte size) depending on how many times the tests are executed and how many errors are occurred. However, nGrinder users need to check these logs to resolve their script problem which occurs in the agents. nGrinder solves this by limiting the maximum size of log file and passing only one process log to the controller.&amp;nbsp;If the log file goes up to 1MB, nGrinder overwrites the existing log to reduce the logger overhead.&lt;/p&gt;  &lt;p&gt;However, It might result the problem when a user tries to find out the error causes by checking agent logs. However, what if a user ran a test more than 1,000,000 times and 5 errors were occurred? Logs for 5 errors might have been overwritten by log rotation so the user can not find the clue for their problem,&lt;/p&gt;  &lt;p&gt;For this case, you need to adjust log level to ERROR to focus on real error.&lt;/p&gt;

&lt;h4&gt; 
Jython
&lt;/h4&gt;&lt;pre class=&quot;brush: py;&quot;&gt;# -*- coding:utf-8 -*-
 
# A simple example using the HTTP plugin that shows the retrieval of a
# single page via HTTP. 
#
# @author admin
from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
from org.slf4j import LoggerFactory
from ch.qos.logback.classic import Level
from ch.qos.logback.classic import Logger 
 
test1 = Test(1, &quot;Test1&quot;)
request1 = test1.wrap(HTTPRequest())
 
class TestRunner:
    def __init__(self) :
        logger = LoggerFactory.getLogger(&quot;worker&quot;);
        logger.setLevel(Level.ERROR);
        
    def __call__(self):
        grinder.statistics.delayReports=True
        result = request1.GET(&quot;http://sample.com&quot;)
 
       
        if result.getStatusCode() == 200 :
            grinder.statistics.forLastTest.success = 1
        else :
            grinder.logger.error(result.getStatusCode())
            grinder.statistics.forLastTest.success = 0
 &lt;/pre&gt;&lt;h4&gt;

Groovy
&lt;/h4&gt;&lt;pre class=&quot;brush: groovy;&quot;&gt;import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.plugin.http.HTTPRequest
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess

import org.apache.commons.io.IOUtils;
import org.codehaus.groovy.reflection.ReflectionUtils;
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.slf4j.LoggerFactory;

import ch.qos.logback.classic.Level;

import HTTPClient.HTTPResponse

/**
 * A simple example using the HTTP plugin that shows the retrieval of a
 * single page via HTTP.
 *
 * This script is auto generated by ngrinder.
 *
 * @author ${userName}
 */
@RunWith(GrinderRunner)
class Test1 {

	public static GTest test;
	public static HTTPRequest request;

	@BeforeProcess
	public static void beforeClass() {
		test = new GTest(1, &quot;test&quot;);
		request = new HTTPRequest();
		test.record(request);
		grinder.logger.info(&quot;before process.&quot;);
	}

	
	@BeforeThread
	public void beforeThread() {
                // Adjust logger to error level
		LoggerFactory.getLogger(&quot;worker&quot;).setLevel(Level.ERROR)
		grinder.statistics.delayReports=true;
		grinder.logger.info(&quot;before thread.&quot;);
	}
	
	
	@Test
	public void test(){
		HTTPResponse result = request.GET(&quot;http://www.google.com&quot;);
		if (result.statusCode == 301 || result.statusCode == 302) {
			grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was {}.&quot;, result.statusCode);
		} else {
			assertThat(result.statusCode, is(200));
		}
	}
 &lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>How to ramp up by threads</title>
      <id>http://www.cubrid.org/546753</id>
      <published>2013-01-07T20:30:05-08:00</published>
      <updated>2013-05-07T20:47:32-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/546753"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/546753#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;nGrinder supports the process rampup as a default feature. If a user want to increase the loads step by steps, User can set a number of process and how to increase them at the ramp-up panel in the test configuration page.&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/753/546/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/753/546/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;638&quot; height=&quot;428&quot; style=&quot;background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;It’s the &lt;strong&gt;process&lt;/strong&gt; ramp-up. If you like to 10 steps in ramp-up, you should set the process count at least 10. If you want more, you should set the process count more.    &lt;br /&gt;However, the processes take a lot of resources to be invoked. 100 processes in a agent is not realistic. It will cause the agent machine out of memory error.&lt;/p&gt;  &lt;p&gt;Let’s assume that you want to know from which TPS level the system starts to be satuated.&lt;/p&gt;  &lt;p&gt;&lt;img src=&quot;http://devcafe.nhncorp.com/files/attach/images/240795/284/113/001/94cd28a0b1bb04d9d67931ce83f7410b.PNG&quot; alt=&quot;tps_increase.PNG&quot; title=&quot;tps_increase.PNG&quot; class=&quot;iePngFix&quot; style=&quot;&quot; /&gt;    &lt;br /&gt;You can use the thread level ramp up for this case. All you need is to add following code in your script.&lt;/p&gt;

&lt;h3&gt;Jython&lt;/h3&gt;  &lt;pre class=&quot;brush: py;&quot;&gt;# -*- coding:utf-8 -*-

# A simple example using the HTTP plugin that shows the retrieval of a
# single page via HTTP. 
#
# This script is auto generated by ngrinder.
#

from net.grinder.script.Grinder import grinder
from net.grinder.script import Test
from net.grinder.plugin.http import HTTPRequest
from net.grinder.plugin.http import HTTPPluginControl
from HTTPClient import NVPair

control = HTTPPluginControl.getConnectionDefaults()
control.setTimeout(30000)

test1 = Test(1, &quot;Test1&quot;)
request1 = HTTPRequest();
test1.record(request1)

class TestRunner:
  def initialSleep( self ):
      sleepTime = grinder.threadNumber * 1000  # 1 seconds per thread
      grinder.sleep(sleepTime, 0)

  def __call__( self ):
      if grinder.runNumber == 0: self.initialSleep()

      grinder.statistics.delayReports=True
      result = request1.GET(&quot;http://www.google.com&quot;)
      
      if result.getText().find(&quot;Google&quot;) != -1 :
          grinder.statistics.forLastTest.success = 1
      else :
          grinder.statistics.forLastTest.success = 0 &lt;/pre&gt;&lt;h3&gt;

Groovy
 &lt;/h3&gt;&lt;pre class=&quot;brush: groovy;&quot;&gt;/**
 * A simple example using the HTTP plugin that shows the retrieval of a
 * single page via HTTP.
 *
 * This script is auto generated by ngrinder.
 *
 * @author ${userName}
 */
@RunWith(GrinderRunner)
class Test1 {

	public static GTest test;
	public static HTTPRequest request;

	@BeforeProcess
	public static void beforeClass() {
		test = new GTest(1, &quot;aa000000&quot;);
		request = new HTTPRequest();
		test.record(request);
		grinder.logger.info(&quot;before process.&quot;);
	}


	@BeforeThread
	public void beforeThread() {
		grinder.statistics.delayReports=true;
		grinder.logger.info(&quot;before thread.&quot;);
		
	}
	
	public void initialSleep() {
		grinder.sleep(grinder.threadNumber * 1000, 0)
	}

	@Test
	public void test(){
		if (grinder.runNumber == 0) {
		   initialSleep()
                }
		HTTPResponse result = request.GET(&quot;http://www.google.com&quot;);
		if (result.statusCode == 301 || result.statusCode == 302) {
			grinder.logger.warn(&quot;Warning. The response may not be correct. The response code was {}.&quot;, result.statusCode);
		} else {
			assertThat(result.statusCode, is(200));
		}
	}
&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            <category term="script-guide"/>
            
   </entry>
   <entry>
      <title>Import Groovy Maven Project in IDE</title>
      <id>http://www.cubrid.org/652570</id>
      <published>2013-05-07T06:30:25-07:00</published>
      <updated>2013-05-07T20:39:05-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/652570"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/652570#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Groovy Maven Project is structured for users to easily import the project into IDE. If you already have an IDE which supports Groovy and Maven, you can easily import it. However if you don’t have it yet, please follow the instruction in [Install Groovy IDE] first.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;If you have installed the Eclipse based Groovy IDE and created Groovy Maven Project in nGrinder subversion, you can import the Groovy Maven Project using the subversion client in Eclipse.&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href=&quot;/files/attach/images/379199/570/652/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;744&quot; height=&quot;216&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Notice that there is the subversion URL field in the script management menu. The above figure shows the our test instance. In this instance, the created Groovy Maven project can be accessed through http://ngrinder-staging.nhncorp.com:8080/svn/admin/project URL.    &lt;br /&gt;OK. Let’s import the project.&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Open your Eclipse and Choose File ==&amp;gt; Others ==&amp;gt; Maven ==&amp;gt; Check out Maven Projects from SCM      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;477&quot; height=&quot;265&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;       &lt;br /&gt;&lt;/li&gt;    &lt;li&gt;Select svn in the SVN URL and type the SVN URL provided in nGrinder. Then click Finish.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_6.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_2.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;527&quot; height=&quot;342&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Then the project will be imported.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_8.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_3.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;240&quot; height=&quot;147&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Enable Groovy on this project.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_10.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_4.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;576&quot; height=&quot;169&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Remove groovy libraries from classpath by selecting &quot;Groovy ==&amp;gt; Remove Groovy libraries from classpath&quot;.      &lt;br /&gt;Because there is a conflict between libraries provided by Maven and Eclipse.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_18.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_8.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;654&quot; height=&quot;66&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Select the Groovy test case and Select Run As ==&amp;gt; JUnit Test.&lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_12.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_5.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;576&quot; height=&quot;193&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Then you might see the following error. It’s because the specialized nGrinder JUnit Runner(named GrinderRunner) needs a special JVM argument for instrumentation&lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_14.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_6.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;379&quot; height=&quot;316&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Check the error message and add the JVM argument following the instruction. Select Run As ==&amp;gt; Run Configurations ==&amp;gt; Select Test1 ==&amp;gt; Select Arguments panel.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_16.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_7.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;795&quot; height=&quot;407&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;       &lt;br /&gt;Please be aware that the argument is varied depending on users. So provide the exact argument which is shown in the JUnit error message. This setting should be provided for every JUnit test running set.&amp;nbsp;If you like to make it as a default vm option for every test run. You can set it up in the global configuration. Please check [Install Groovy IDE] for details. &lt;/li&gt;    &lt;li&gt;Then run as JUnit test again.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_20.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_9.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;440&quot; height=&quot;339&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;In my case, the access to please_modify_this.com causes the error. Ater changing this to http://www.google.com . It shows the green bar now.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_22.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_10.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;536&quot; height=&quot;145&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;You can add the break point in the test case. Then select Debug As ==&amp;gt; JUnit Test.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_24.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_11.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;445&quot; height=&quot;118&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Then you can debug the test case using the generic Eclipse debugging feature.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_28.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_13.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;684&quot; height=&quot;285&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;When you think the test case is almost completed, you may need to see what happens in the repeated run. For this you can provide the @Repeat annotation on the test case class. Then run as JUnit test again.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_32.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_15.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;437&quot; height=&quot;129&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Then you can see that test case is executed multiple times you specified. Please note that it’s 100 repetition by single thread.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/570/652/image_34.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/570/652/image_thumb_16.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;297&quot; height=&quot;193&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;If you think the test case is ready, commit it into subversion selecting Team ==&amp;gt; Commit. Finally run this test in nGrinder.&lt;/li&gt; &lt;/ol&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="groovy"/>
            <category term="script guide"/>
            
   </entry>
   <entry>
      <title>User Guide</title>
      <id>http://www.cubrid.org/444932</id>
      <published>2012-10-08T20:41:15-07:00</published>
      <updated>2013-05-07T19:02:00-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/444932"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/444932#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;This page provide the collection of user guides when you access nGrinder with user permission.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[Quick Start]&lt;/li&gt;
&lt;li&gt;[Test Configuration]&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[Virtual User]&lt;/li&gt;
&lt;li&gt;[Process and Thread]&lt;/li&gt;
&lt;li&gt;[How to add custom monitor data]&lt;/li&gt;
&lt;/ul&gt;

&lt;li&gt;Scripting&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[Scripting Guide]&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;[Script Security]&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;[Script Management]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[User Permission]&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;[User Account Share]&lt;/li&gt;
&lt;li&gt;[User Agent]&lt;/li&gt;
&lt;/ul&gt;

&lt;li&gt;[Recorder]&lt;/li&gt;
&lt;li&gt;[Frequently Asked Question]&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;If you&apos;re Korean speaker(한국인), please check &amp;nbsp; you can check the following resources.&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;[User Guide in Korean]&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            
   </entry>
   <entry>
      <title>Install Groovy IDE</title>
      <id>http://www.cubrid.org/651127</id>
      <published>2013-05-06T00:47:00-07:00</published>
      <updated>2013-05-07T08:13:57-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/651127"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/651127#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;blockquote class=&quot;q4&quot;&gt;&lt;p&gt;When you create Groovy Maven project, you can use IDE to write and debug test cases. Groovy maven project use only maven’s pom.xml to structure src folders and specify dependencies. Therefore if your IDE supports Groovy and Maven project, you can use it. For who don’t have IDE yet. This explains how to install Eclipse based Groovy Maven IDE.&lt;/p&gt;

&lt;/blockquote&gt;&lt;ol&gt;
&lt;li&gt;Download and unzip the lastest “Eclipse IDE for Java Developers” which fits to your OS.&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;&lt;a href=&quot;http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/junosr2&quot;&gt;http://www.eclipse.org/downloads/packages/eclipse-ide-java-developers/junosr2&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;The above version already includes Maven Eclipse plugin but Groovy and Subversion. You need to install them. Firstly, run the downloaded eclipse by double-clicking eclipse.exe.&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;Install Groovy&lt;/li&gt;    &lt;ol&gt;     &lt;li&gt;Go to “Help” ==&amp;gt; “Eclipse Market Place”&lt;/li&gt;      &lt;li&gt;Type groovy in the search field. Then click the install button in Groovy Eclipse for Juno.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_10.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_4.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;525&quot; height=&quot;131&quot; style=&quot;margin: 0px; border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Then install all.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_12.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_5.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;527&quot; height=&quot;66&quot; style=&quot;border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Then click “Next”s and “Finish”s and restart Eclipse until the installation is completed.&lt;/li&gt; &lt;!--EndFragment--&gt;&lt;/ol&gt;    &lt;li&gt;Install Subversive&lt;/li&gt;    &lt;ol&gt;     &lt;li&gt;Go to “Help” ==&amp;gt; “Eclipse Market Place”&lt;/li&gt;      &lt;li&gt;Type subversive in the search field. Then click install below.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_6.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_2.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;525&quot; height=&quot;131&quot; style=&quot;margin: 0px; border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Select Subveresive SVN JDK Ignore Extensions and Team Provider. Then select “Next” buttons until the installation is started.        &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_8.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_3.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;624&quot; height=&quot;139&quot; style=&quot;margin: 0px; border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Restart Eclipse and and select SVN Kit 1.7.8. Subversion repo provided by nGrinder is compatible with above SVN Kit 1.7.8.       &lt;br /&gt;Then click “Next”s and “Finish”s and restart Eclipse until the installation is completed.        &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;543&quot; height=&quot;88&quot; style=&quot;border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Now it’s time to connect Maven and Subversion by installing m2e subversive connector. Click File menu ==&amp;gt; New ==&amp;gt; Checkout Maven Projects from SCM.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_14.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_6.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;470&quot; height=&quot;220&quot; style=&quot;margin: 0px; border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Then click m2e Marketplace in the next dialog.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_16.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_7.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;530&quot; height=&quot;374&quot; style=&quot;margin: 0px; border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;&lt;/li&gt;      &lt;li&gt;Check the m2e subversive and click Finish button.       &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/127/651/image_18.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/image_thumb_8.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;533&quot; height=&quot;83&quot; style=&quot;margin: 0px; border: 0px currentColor; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt;        &lt;br /&gt;Then click “Next”s and “Finish”s and restart Eclipse until the installation is completed.&lt;/li&gt;
&lt;li&gt;Groovy JUnit Running requires the special JVM argument for every test run. It can be very annoying. If you plan to use this Eclipse instance only for nGrinder Test Case, it might be a good choice to provide the default JVM options for every JVM execution in this Eclipse.&amp;nbsp;&lt;br /&gt;Go To Window ==&amp;gt; Preference ==&amp;gt; Java ==&amp;gt; Installed JRE. Then click Edit on the default JRE.&lt;br /&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/127/651/pic3.PNG&quot; alt=&quot;pic3.PNG&quot; title=&quot;pic3.PNG&quot; class=&quot;iePngFix&quot; width=&quot;567&quot; height=&quot;399&quot; style=&quot;&quot; /&gt;
&lt;br /&gt;Finally you can provide Default VM arguments here. Detailed option you should provide depends on the user configuration. Please check [Import Groovy Maven Project in IDE] to know the option.&lt;/li&gt;   &lt;/ol&gt; &lt;/ol&gt;  &lt;p&gt;Now your IDE is ready to run and debug your nGrinder groovy test cases. &amp;nbsp;[Import Groovy Maven Project in IDE]&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="groovy"/>
            <category term="user-guide"/>
            
   </entry>
   <entry>
      <title>Scripting Guide</title>
      <id>http://www.cubrid.org/499865</id>
      <published>2012-11-18T18:05:40-08:00</published>
      <updated>2013-05-06T18:47:08-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/499865"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/499865#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;blockquote class=&quot;q4&quot;&gt;&lt;p&gt;nGrinder 3.2 or later support not only Jython but also Groovy as scripting language. If you want to know about Groovy scripting, please refer [Groovy Script]&lt;/p&gt;

&lt;/blockquote&gt;&lt;blockquote class=&quot;q4&quot;&gt;&lt;ul&gt;
&lt;li&gt;You can see various &lt;a href=&quot;http://grinder.sourceforge.net/g3/script-gallery.html&quot; target=&quot;_self&quot;&gt;The Grinder script samples&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You can check &lt;a href=&quot;http://grinder.sourceforge.net/g3/script-javadoc/index.html&quot; target=&quot;_self&quot;&gt;The Grinder APIs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;More practical ways for the advanced nGrinder user are...&amp;nbsp;&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;Do you want to know what script types nGrinder supports?&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[Jython Script Structure]&lt;/li&gt;
&lt;li&gt;[Groovy Script Structure]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you want to ramp-up more precisely?&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to ramp up by threads]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need a custom dns entry? Need to change the /etc/hosts file in the agents? No. You can configure target host fields for this. You don&apos;t need root permission.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to change DNS]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need to use your own jar or py? Read followings.&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to use library]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need to load your own xml or txt file? Read followings.&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to use resources]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need to simulate the multiple user scenario in the different run weight?&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to run the multiple tests with different weight]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need to adjust the logger level to only see the errors? Read followings.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to adjust logger level]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need to test DB performance? Doesn&apos;t nGrinder seems to support this? No.. You can still test it with nGrinder&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[Using nGrinder to perform db load test]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need to parse data retrieved from server?&amp;nbsp;&lt;br /&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to parse JSON]&lt;/li&gt;
&lt;li&gt;[How to parse XML]&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;ul&gt;
&lt;li&gt;Do you need to define your own statistic?&amp;nbsp;&lt;br /&gt;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[User defined statistic in ngrinder]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you cope with the big response like movie or file download?&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;[How to handle the big response]&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Do you need you test a socket.io app?&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;li style=&quot;margin-top: 7px; margin-right: 0px; margin-bottom: 7px; margin-left: 0px; &quot;&gt;&lt;a href=&quot;/wiki_ngrinder/entry/using-ngrinder-to-perform-load-test-for-a-socket-io-app&quot; target=&quot;_self&quot;&gt;How to test a socket.io app&lt;/a&gt;&lt;/li&gt;
&lt;li style=&quot;margin-top: 7px; margin-right: 0px; margin-bottom: 7px; margin-left: 0px; &quot;&gt;&lt;a href=&quot;/wiki_ngrinder/entry/using-ngrinder-to-perform-load-test-for-socket-io-app-python-version&quot; target=&quot;_self&quot;&gt;How to test a socket.io app&amp;nbsp;- Python version&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div&gt;&lt;br /&gt;&lt;/div&gt;

&lt;br /&gt;&lt;ul&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div&gt;&lt;br /&gt;&lt;/div&gt;

&lt;div&gt;&lt;br /&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;ul&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="script guide"/>
            
   </entry>
   <entry>
      <title>Groovy Script Structure</title>
      <id>http://www.cubrid.org/651508</id>
      <published>2013-05-06T06:29:47-07:00</published>
      <updated>2013-05-06T06:29:47-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/651508"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/651508#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Not like [Jython Script Structure], Groovy Script Structure is based on JUnit. It’s because we want to reuse existing JUnit experiences as much as possible. Several IDEs already well integrate JUnit and let a user to run the test case directly. If you created Goorvy Maven Project option in script creation dialog box in nGrinder, You can enjoy the this excellant approach in your current IDE. &lt;/p&gt;  &lt;p&gt;For now, I’d like to explain see the generic Groovy script stucture whatever you choose Groovy Script or Groovy Maven Project.    &lt;br /&gt;Following is a base template for groovy script.&lt;/p&gt;  &lt;pre class=&quot;brush: groovy;&quot;&gt;import static net.grinder.script.Grinder.grinder
import static org.junit.Assert.*
import static org.hamcrest.Matchers.*
import net.grinder.plugin.http.HTTPRequest
import net.grinder.script.GTest
import net.grinder.script.Grinder
import net.grinder.scriptengine.groovy.junit.GrinderRunner
import net.grinder.scriptengine.groovy.junit.annotation.BeforeThread
import net.grinder.scriptengine.groovy.junit.annotation.BeforeProcess

import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

import HTTPClient.HTTPResponse

/**
 * A simple example using the HTTP plugin that shows the retrieval of a
 * single page via HTTP.
 *
 * This script is auto generated by ngrinder.
 *
 * @author ${userName}
 */
@RunWith(GrinderRunner)
class Test1 {

    public static GTest test;
    public static HTTPRequest request;

    // This method is executed once per a process. 
    @BeforeProcess
    public static void beforeClass() {
        test = new GTest(1, &amp;quot;${name}&amp;quot;);
        request = new HTTPRequest();
        test.record(request);
        grinder.logger.info(&amp;quot;before process.&amp;quot;);
    }

    // This method is executed once per a thread. 
    @BeforeThread
    public void beforeThread() {
        grinder.statistics.delayReports=true;
        grinder.logger.info(&amp;quot;before thread.&amp;quot;);
    }

    // This method is continously executed until you stop the test 
    @Test
    public void test(){
        HTTPResponse result = request.GET(&amp;quot;${url}&amp;quot;);
        if (result.statusCode == 301 || result.statusCode == 302) {
            grinder.logger.warn(&amp;quot;Warning. The response may not be correct. The response code was {}.&amp;quot;, result.statusCode);
        } else {
            assertThat(result.statusCode, is(200));
        }
    }
}&lt;/pre&gt;

&lt;p&gt;The Groovy test case in nGrinder should be annotated with @RunWith(GroovyRunner). This will invoke GroovyRunner to control the JUnit running behavior and mount the grinder context on JUnit. 
  &lt;br /&gt;@Test annotated methods are subject to be executed repeatedly.&amp;#160; As you can see above, you can assert the test result using JUnit assertion way. If the assertion is failed, the last test bounded this thread will be evaluated as a error.&lt;/p&gt;

&lt;p&gt;Instead of @BeforeClass @Before @AfterClass @After whch are used the generic JUnit tests, Groovy test case in nGrinder uses its own annotation to control script behaviors.&lt;/p&gt;

&lt;table cellspacing=&quot;0&quot; cellpadding=&quot;2&quot; width=&quot;750&quot; border=&quot;0&quot;&gt;&lt;tbody&gt;
    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;&amp;#160;&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Description&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;Applied to&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Usage&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@BeforeProcess&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define behaviors which should be executed before the process is invoked&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;static method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Load resource files which are shared by threads 
        &lt;br /&gt;Define GTest and instrument the test target using record method.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@AfterProcess&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define behaviors which should be executed after the process is terminated&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;static method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Close resource files.&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@BeforeThread&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define behaviors which should be executed before the each thread is executed.&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;member method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Login the target system. 
        &lt;br /&gt;Set up the thread bounded values. (For example, Cookie Handler)&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@AfterThread&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define behaviors which should be exeucted after the each thread is exeucted&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;member method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Logout the target system&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@Before&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define behaviors which should be executed before every @Test annotated method are executed. &lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;member method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Common logic which is shared by the multiple @Test annotated methods. 
        &lt;br /&gt;Variable set up&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@After&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define behaviors which should be executed after every @Test annotated methods are executed. &lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;member method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Not used much..&lt;/td&gt;
    &lt;/tr&gt;

    &lt;tr&gt;
      &lt;td valign=&quot;top&quot; width=&quot;150&quot;&gt;@Test&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;177&quot;&gt;Define the test behavior. Excuted muliple times&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;123&quot;&gt;member method&lt;/td&gt;

      &lt;td valign=&quot;top&quot; width=&quot;298&quot;&gt;Test body&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;The exeution flow can be illustrated by following.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.cubrid.org/files/attach/images/379199/508/651/image_8.png&quot;&gt;&lt;img title=&quot;image&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; border=&quot;0&quot; alt=&quot;image&quot; src=&quot;http://www.cubrid.org/files/attach/images/379199/508/651/image_thumb_3.png&quot; width=&quot;746&quot; height=&quot;366&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the test case sample, Please look this part carefully.&lt;/p&gt;

&lt;pre class=&quot;brush: groovy;&quot;&gt;    public static GTest test;
    public static HTTPRequest request;&lt;br /&gt;
    // This method is executed once per a process. 
    @BeforeProcess
    public static void beforeProcess() {
        // Instead of Test in Jython, GTest is used here
        // It&apos;s because the identifier &amp;quot;Test&amp;quot; is alredy used by the @Test 
        // GTest is the replacement to avoid the naming confliction.
        test = new GTest(1, &amp;quot;${name}&amp;quot;);
        request = new HTTPRequest();
        test.record(request);
        grinder.logger.info(&amp;quot;before process.&amp;quot;);
    }&lt;/pre&gt;

&lt;p&gt;In @BeforeProcess annotated method, it defines GTest instance and record the HTTPRequest instance and save them in the static member variable. 
  &lt;br /&gt;It’s the first step of test statistic preparation. Any method calls on request variable will increase the TPS. If you want to record multiple HTTPRequest instances using multiple GTest named diiferently, You can just add another member variables and invoke record method on different HTTPRequest instance.&amp;#160; Furthermore, you can define another the test methods in a single test case class as well. Just add @Test annotation on those like the following.&amp;#160; &lt;br /&gt;&lt;/p&gt;

&lt;pre class=&quot;brush: groovy;&quot;&gt;    @Test
    public void testGoogle(){
        HTTPResponse result = request.GET(&amp;quot;http://www.google.com&amp;quot;);
        if (result.statusCode == 301 || result.statusCode == 302) {
            grinder.logger.warn(&amp;quot;Warning. The response may not be correct. The response code was {}.&amp;quot;, result.statusCode);
        } else {
            assertThat(result.statusCode, is(200));
        }
    }

    @Test
    public void testYahoo(){
        HTTPResponse result = request.GET(&amp;quot;http://www.yahoo.com&amp;quot;);
        if (result.statusCode == 301 || result.statusCode == 302) {
            grinder.logger.warn(&amp;quot;Warning. The response may not be correct. The response code was {}.&amp;quot;, result.statusCode);
        } else {
            assertThat(result.statusCode, is(200));
        }
    }&lt;/pre&gt;

&lt;p&gt;However, you should aware nGrinder GroovyRunner creates only one test case object per a thread not like generic JUnit test case which creates a separate test case object for each @Test annotated method. So if each @Test annotated methods share member variables, they can affect each other. It’s intentional. In nGrinder test case, it’s very likely each @Test method relies on the previous @Test annotated method execution result. Therefore, if you save the previous test result in the member varible and refer it to decide to continue to next test method, you can easily implement the test dependency. &lt;/p&gt;

&lt;pre class=&quot;brush: groovy;&quot;&gt;    private boolean googleResult;
    
    @Test
    public void testGoogle(){
        googleResult = false;
        HTTPResponse result = request.GET(&amp;quot;http://www.google.com&amp;quot;);
        if (result.statusCode == 301 || result.statusCode == 302) {
            grinder.logger.warn(&amp;quot;Warning. The response may not be correct. The response code was {}.&amp;quot;, result.statusCode);
        } else {
            assertThat(result.statusCode, is(200));
        }
        googleResult = true;
    }

    @Test
    public void testYahoo(){
        if (!googleResult) {
            grinder.logger.warn(&amp;quot;Just return. Because prev google test is failed.&amp;quot;);
            return;
        }
        HTTPResponse result = request.GET(&amp;quot;http://www.yahoo.com&amp;quot;);
        if (result.statusCode == 301 || result.statusCode == 302) {
            grinder.logger.warn(&amp;quot;Warning. The response may not be correct. The response code was {}.&amp;quot;, result.statusCode);
        } else {
            assertThat(result.statusCode, is(200));
        }
    }&lt;/pre&gt;

&lt;p&gt;How can you use library and resources?&amp;#160; If you don’t use [Groovy Maven Structure] yet, you can refer [Jython Script Structure] to how to include them in your script. It’s exactly same as Jython way.
  &lt;br /&gt;However if you use Maven structure plus Groovy, you can enjoy the easier library dependency setting and run the JUnit test in your IDE. Interested in this?

  &lt;br /&gt;Then continue to see the [Groovy Maven Structure] to know how to enable this for you.&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="script guide"/>
            <category term="groovy"/>
            
   </entry>
   <entry>
      <title>Recorder Limitation</title>
      <id>http://www.cubrid.org/634226</id>
      <published>2013-04-12T07:42:51-07:00</published>
      <updated>2013-04-23T18:45:25-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/634226"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/634226#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;h2&gt;Features per OS&lt;/h2&gt;&lt;p&gt;Due to the embedded browser component limitation, nGrinder Recorder has a different feature support depending on OS.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;table width=&quot;666&quot; bordercolor=&quot;#000000&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; style=&quot;width: 694px; color: rgb(19, 18, 18); font-family: Calibri, &apos;Times New Roman&apos;, Arial, Tahoma; font-size: 15px; line-height: 20px; background-color: rgb(244, 247, 250);&quot;&gt;&lt;tbody&gt;&lt;tr style=&quot;background-color: black; color: white; background-position: initial initial; background-repeat: initial initial;&quot;&gt;&lt;td width=&quot;158&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;Features&lt;/td&gt;&lt;td width=&quot;141&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;Windows&lt;/td&gt;&lt;td width=&quot;165&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;MAC&lt;/td&gt;&lt;td width=&quot;200&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;Linux&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;158&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;Proxy&lt;/td&gt;&lt;td width=&quot;141&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;/td&gt;&lt;td width=&quot;165&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;/td&gt;&lt;td width=&quot;200&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;158&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;Embedded Browser&lt;/td&gt;&lt;td width=&quot;141&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;/td&gt;&lt;td width=&quot;165&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;△&lt;/td&gt;&lt;td width=&quot;200&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;△ (Crashed&amp;nbsp;Frequently)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td width=&quot;158&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;HTTPS support&lt;/td&gt;&lt;td width=&quot;141&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;/td&gt;&lt;td width=&quot;165&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;X&lt;/td&gt;&lt;td width=&quot;200&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space:pre&quot;&gt;	&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td width=&quot;158&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;Flash support&lt;/td&gt;&lt;td width=&quot;141&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;O&lt;/td&gt;&lt;td width=&quot;165&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;X&lt;/td&gt;&lt;td width=&quot;200&quot; valign=&quot;top&quot; style=&quot;padding: 3px;&quot;&gt;X&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;/p&gt;

&lt;p&gt;We&apos;re highly recommending you to use Windows when recording user interaction. If you like to use MAC or Linux, use the separate browser with proxy settings. Refer [Recorder-Recording Guide For Non Window User].&lt;/p&gt;

&lt;h2&gt;Missing Recorded Element&lt;/h2&gt;&lt;p&gt;nGrinder Recorder does not guarantee to generate the perfectly executable scripts. It&apos;s a just helper application with which a user can start to write suitable scripts. Even though nGrinder Recorder contains embedded browsers&amp;nbsp; nsides, it doesn&apos;t take much information from these to generate scripts. As you can see the &lt;a href=&quot;/wiki_ngrinder/entry/recorder-architecture&quot; target=&quot;_blank&quot;&gt;nGrinder Recorder Architecture&lt;/a&gt;, the actual recording is performed by intercepting HTTP/HTTPS messages not by intercepting the browser events. After recording HTTP/HTTPS messages by a proxy, nGrinder Recorder tries to generate the script which simulates user behavior. It might be not perfect due to information loss. For example, The web pages in browsers can create cookies in javascript. nGrinder Recorder can understand cookies generated only by server but browser. Therefore this cookie processing code won&apos;t show up in the finally generated script. The users should add the client side cookie generation code by themselves.&lt;/p&gt;  &lt;pre class=&quot;brush: py;&quot;&gt;# User need to write his own cookie handling code to complement the missing part.
threadContext = HTTPPluginControl.getThreadHTTPClientContext()
expiryDate = Date()
expiryDate.year += 10
cookie = Cookie(&quot;key&quot;, &quot;value&quot;,&quot;localhost&quot;, &quot;/&quot;, expiryDate, 0)
CookieModule.addCookie(cookie, threadContext)&lt;/pre&gt;

&lt;p&gt;Only information nGrinder Recorder takes from the embedded browser is click events to separate messages into the pages. Following is the code generated by nGrinder Recorder.&lt;/p&gt;

&lt;pre class=&quot;brush: py;&quot;&gt;class TestRunner:
    &quot;&quot;&quot;A TestRunner instance is created for each worker thread.&quot;&quot;&quot;
    def __init__(self) :
        grinder.statistics.delayReports=True
        pass
    
    def __call__(self) :
        try : 
            # Following two pages are created because a user click the mouse.
            self.page1()
            self.page2()
            grinder.statistics.forLastTest.success = 1
        except Exception, e:
            err(e.message)
            grinder.statistics.forLastTest.success = 0

    def page1(self) :
        ##########################################################################################
        # http://img.naver.net/static/newsstand/up/2012/1119/nsd102245777.gif
        ##########################################################################################
        grinder.sleep(54)
        result = request_img_naver_net.GET(
                &quot;/static/newsstand/up/2012/1119/nsd102245777.gif&quot;,
                None,    
                headers0
            ) 
        self.checkResponse(result, 200,  &quot;http://img.naver.net/static/newsstand/up/2012/1119/nsd102245777.gif&quot;)

        ##########################################################################################
        # http://img.naver.net/thumb.opencast/opencast01/n/a/naver_story/20130411/17442431363707.jpg
        ##########################################################################################
        self.token_type = &apos;f10060&apos;  
        result = request_img_naver_net.GET(
                &quot;/thumb.opencast/opencast01/n/a/naver_story/20130411/17442431363707.jpg?type=%s&quot;
                    % (self.token_type),
                None,    
                headers0
            ) 
        self.checkResponse(result, 200,  &quot;http://img.naver.net/thumb.opencast/opencast01/n/a/naver_story/20130411/17442431363707.jpg&quot;)&lt;/pre&gt;

&lt;h2&gt;Not recordable HTTPS messages&lt;/h2&gt;&lt;p&gt;When users try to records HTTPS traffics, The browsers may shows the following message box. &lt;/p&gt;

&lt;p align=&quot;center&quot;&gt;&lt;a href=&quot;/files/attach/images/379199/226/634/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/226/634/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;386&quot; height=&quot;306&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This alert is shown because the proxy should use a self-signed private certificate between the browser and proxy HTTPS communication to capture HTTPS messages. The certificate issued by the webserver is used only between the proxy and target web server communication. The proxy decodes the messages from the target server and decode them with this valiid certificate and record the messages. Then the proxy encode the message with the grinder self-signed certificate and send it back to the browsers. From the perspective of browsers, they don’t aware of the proxy behavior. They just show warning mesage because they think the messages are&amp;nbsp; encoded by something wrong certificiate. Currently only IE engine among our embedded browser engines allows users to accepts the invalid certificate while browsing HTTPS sites. Therefore the embedded browsers only works with the proxy well in Windows and IE env. In OS X, users should configure separate browsers to connect the proxy instead of using embedded browser. The general web browser has a way to accept the self-signed certificate. See [Recorder-How to import self signed certificates].&lt;/p&gt;

&lt;p&gt;The messages used in the mobile devices can also be captured by setting the mobile device’s network configuration. However the most of all mobile browsers may reject the messages encoded with such a private certificates. There might be no way to show this HTTPS pages in the mobile devices. If someone knows how to configure it, please let us know.&lt;/p&gt;

&lt;p&gt;Only way to browse these is to let the proxy use the valid certificate when it returns back the HTTPS messages to the browsers. See Configuration section in [Recorder-Installation].&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="recorder"/>
            
   </entry>
   <entry>
      <title>Recorder Installation</title>
      <id>http://www.cubrid.org/633812</id>
      <published>2013-04-12T00:34:55-07:00</published>
      <updated>2013-04-23T18:43:04-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/633812"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/633812#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;h3&gt;Prerequsite&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;nGrinder Recorder is cross os application becauses it is implemented in Java. At least you requires followings to run nGrinder Recorder.      &lt;ul&gt;       &lt;li&gt;Java Runtime (over 1.6) &lt;/li&gt;        &lt;li&gt;GUI enabled env (not supporting headless OS) &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;However, Some major features of nGrinder Recorder can work in Windows due to some bugs in internal components.      &lt;br /&gt;We’ll continue to work to make the disabled feature runnable in the other OS.&amp;nbsp;&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Check out [Recorder-Limitation] first.&lt;span style=&quot;line-height: 25px;&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;  &lt;h3&gt;Installation&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;Currently nGrinder Recorder is provided in the form of java webstart.&amp;nbsp; You can install it just by clicking the following URL in the browser.      &lt;ul&gt;       &lt;li&gt;TBD&amp;nbsp;&lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt;    &lt;li&gt;Then nGrinder Recorder will ask you to install the Therefore the following warning message will show up.&amp;nbsp; &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/812/633/image_6.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/812/633/image_thumb_2.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;341&quot; height=&quot;231&quot; style=&quot;border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Check “Always trust content from the publisher” and click Run. nGrinder Recorder requires full permission in your PC because the &lt;a href=&quot;http://www.teamdev.com/downloads/jxbrowser/docs/JxBrowser-PGuide.html#jws&quot; target=&quot;_blank&quot;&gt;underlying JXBrowser requires it&lt;/a&gt;. &lt;/li&gt;    &lt;li&gt;Then..&amp;nbsp; If your PC’s firewall monitor port openning, the port openning warning message may come up. You should allow nGrinder Recorder to open the port appropriately.      &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/812/633/image_8.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/812/633/image_thumb_3.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;340&quot; height=&quot;244&quot; style=&quot;border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;If you can see the following window, You’re ready to use nGrinder Recorder.&amp;nbsp; &lt;br /&gt;&lt;a href=&quot;/files/attach/images/379199/812/633/image_10.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/812/633/image_thumb_4.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;573&quot; height=&quot;380&quot; style=&quot;border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;&quot; /&gt;&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Copy the downloaded jnlp file into the desktop to run nGrinder without network access. &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Configuration&lt;/h3&gt;  &lt;ul&gt;   &lt;li&gt;Just like nGrinder Controller and Agent, nGrinder Recorder uses the configuration in the ${user.home}/.ngrinder_recorder folder.&amp;nbsp; You can open recorder.conf file to configure followings.      &lt;ul&gt;
&lt;/ul&gt;
&lt;table width=&quot;666&quot; bordercolor=&quot;#000000&quot; style=&quot;border-collapse: collapse;&quot; border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot;&gt;&lt;tbody&gt;         &lt;tr style=&quot;color: white; background-color: black;&quot;&gt;           &lt;td width=&quot;250&quot; valign=&quot;top&quot;&gt;key&lt;/td&gt;            &lt;td width=&quot;440&quot; valign=&quot;top&quot;&gt;value&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td width=&quot;250&quot; valign=&quot;top&quot;&gt;recorder.additional.headers&lt;/td&gt;            &lt;td width=&quot;440&quot; valign=&quot;top&quot;&gt;The recorder only records the limited set of headers. If you want to record more, you can specify this value with header names separated by comma. Check the detailed info &lt;a href=&quot;http://grinder.sourceforge.net/g3/tcpproxy.html#additional-headers&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td width=&quot;250&quot; valign=&quot;top&quot;&gt;keystore.password &lt;/td&gt;            &lt;td width=&quot;440&quot; valign=&quot;top&quot;&gt;A user can provide the same certificate which is used already for the webserver HTTPS communication.&amp;nbsp; A user should locates the keystore in the ${user.home}/.ngrinder_recorder/keystore file. Then specify the password of this keystore here.&lt;/td&gt;         &lt;/tr&gt;          &lt;tr&gt;           &lt;td width=&quot;250&quot; valign=&quot;top&quot;&gt;keystore.type &lt;/td&gt;            &lt;td width=&quot;440&quot; valign=&quot;top&quot;&gt;A user can specify the keystore type. The default value is jks.&lt;/td&gt;         &lt;/tr&gt;       &lt;/tbody&gt;             &lt;/table&gt;   &lt;/li&gt; &lt;/ul&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="recorder"/>
            
   </entry>
   <entry>
      <title>Recorder</title>
      <id>http://www.cubrid.org/631994</id>
      <published>2013-04-09T22:46:01-07:00</published>
      <updated>2013-04-23T18:35:41-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/631994"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/631994#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Grinder Recorder will be releasde at the end of April.&lt;/p&gt;    &lt;blockquote class=&quot;q4&quot;&gt;   &lt;p&gt;&lt;b&gt;nGrinder Recorder&lt;/b&gt; is a &lt;b&gt;helper application&lt;/b&gt; to create the basic nGrinder script. It records HTTP/HTTPS traffics sent from the embedded browser and creates the &lt;a href=&quot;http://grinder.sourceforge.net/&quot; target=&quot;_blank&quot;&gt;The Grinder&lt;/a&gt; compatible script. It’s based on &lt;a href=&quot;http://grinder.sourceforge.net/g3/tcpproxy.html&quot; target=&quot;_blank&quot;&gt;TCPProxy&lt;/a&gt; which The Grinder project provides. We found out that TCPProxy is very powerful but it’s little bit difficult to understand and run because it’s command line based.&amp;nbsp; In addition, the generated script is more complex than we expected. Therefore, we built new The Grinder script recording tool named &quot;nGrinder Recorder&quot; with the built-in web browser and java webstart technology. You can just start the script recording just by just few clicks.      &lt;br /&gt;We, nGrinder Development Team,&lt;strong&gt; don’t put much energy on this product&lt;/strong&gt;. We believe the manual script writing is the best way to achieve efficient peformance testing not by this kind of recoding. So there might be some crash due to lack of its functionality testing.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p style=&quot;text-align: center&quot;&gt;&lt;a href=&quot;/files/attach/images/379199/994/631/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/994/631/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;735&quot; height=&quot;418&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;[Recorder-Architecture] &lt;/li&gt;    &lt;li&gt;[Recorder-Limitation] &lt;/li&gt;
&lt;li&gt;[Recorder-ScreenShot]&lt;/li&gt;    &lt;li&gt;[Recorder-Installation] &lt;/li&gt;    &lt;li&gt;[Recorder-Quick-Start] &lt;/li&gt;    &lt;li&gt;[Recorder-Recording-Guide] &lt;/li&gt;    &lt;li&gt;[Recorder-Recording-Guide-For-Non-Window-User] &lt;/li&gt;    &lt;li&gt;[Recorder-Generated Test Script Structure] &lt;/li&gt; &lt;/ul&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="recorder"/>
            
   </entry>
   <entry>
      <title>Recorder-Recording Guide For Non Window user</title>
      <id>http://www.cubrid.org/637565</id>
      <published>2013-04-16T18:46:52-07:00</published>
      <updated>2013-04-17T21:49:02-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/637565"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/637565#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Due to serious bugs existing internal component, nGrinder Recorder only provides its full funtionalities in Windows. For Linux and Mac users may not enjoy its simple use case but need some configuration to make nGrinder Recorder do its job.&lt;/p&gt;  &lt;p&gt;In Mac and Linux, Embedded browsers are invoked with to the initiated proxy connection. However, it&apos;s not so well tested and we found there are some&amp;nbsp;frequent crash especially in OS X. Furthermore, HTTPS is not supported in OS X. Therefore, we highly recommend you to set up separated browsers connecting to the proxy.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;636&quot; height=&quot;480&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;As you can see below, the proxy is initiated using 10288 port.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;636&quot; height=&quot;119&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you like to record HTTP/HTTPS with Firefox,&amp;nbsp; Open Firefox and go to Preferences and Select Advanced ==&amp;gt; Settings in the popup window.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_10.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_4.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;128&quot; height=&quot;151&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&amp;nbsp; &lt;a href=&quot;/files/attach/images/379199/565/637/image_8.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_3.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;503&quot; height=&quot;152&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Set the proxy in HTTPS and HTTPS according the proxy info provided by nGrinder Recorder.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_12.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_5.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;638&quot; height=&quot;378&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Then, navigate where you want in Firefox. Don’t forget that you should click Start Record button in nGrinder Recorder.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_14.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_6.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;637&quot; height=&quot;318&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Then click Stop Recording in nGrinder Recorder. Then you can see the recorded script.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_16.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_7.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;636&quot; height=&quot;477&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Please don’t forget to disable proxy settings when you finish the recording job. Otherwise you can not browse the Internet afterwards.&lt;/p&gt;  &lt;p&gt;When you navigates to HTTPS sites, you will see the following page. It’s because the proxy send messages encrypted by the self-signed certificate.    &lt;br /&gt;To ignore this, you should click “I Understand the Risks” and add the exception.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/565/637/image_18.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/565/637/image_thumb_8.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;640&quot; height=&quot;478&quot; style=&quot;border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="recorder"/>
            
   </entry>
   <entry>
      <title>How to build nGrinder Recorder using maven</title>
      <id>http://www.cubrid.org/637684</id>
      <published>2013-04-16T21:19:41-07:00</published>
      <updated>2013-04-16T21:46:07-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/637684"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/637684#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;blockquote class=&quot;q4&quot;&gt;This article is only for nGrinder Recorder commiters. The source code of nGrinder Recorder exists in the private repo in github. Due to the licensing problem of 3rd party library, we can not publicize the source yet. &lt;/blockquote&gt;  &lt;ol&gt;   &lt;li&gt;create ngrinder recorder folder and move in      &lt;pre class=&quot;brush: bash;&quot;&gt;mkdir ngrinder-recorder
cd ngrinder-recorder&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;clone the repo. 
    &lt;pre class=&quot;brush: bash;&quot;&gt;git clone https://github.com/nhnopensource/ngrinder-recorder.git&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;Move to cloned repo and install custom libraris into local maven repo. 
    &lt;br /&gt;

    &lt;pre class=&quot;brush: bash;&quot;&gt;cd ngrinder-recorder
install_maven_lib.bat&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;clone the build script repo at the same folder where ngrinder-recorder is cloned. This repo is located in NHN internal repo due to the certificate. If you have no permission yet. Please ask JunHo Yoon a permission. 
    &lt;pre class=&quot;brush: bash;&quot;&gt;cd ..&lt;br /&gt;git clone http://devcode.nhncorp.com/git/recorderpack.git ngrinder_recorder_package&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;Move to ngrinder_recorder_package directory 
    &lt;pre class=&quot;brush: bash;&quot;&gt;cd ngrinder_recorder_package&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;create keystore 
    &lt;pre class=&quot;brush: bash;&quot;&gt;create_keystore.bat&lt;/pre&gt;
  &lt;/li&gt;

  &lt;li&gt;package nGrinder Recorder with code signing. 
    &lt;pre class=&quot;brush: bash;&quot;&gt;deploy.bat&lt;/pre&gt;
  &lt;/li&gt;
&lt;/ol&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="dev"/>
            
   </entry>
   <entry>
      <title>Dev Document</title>
      <id>http://www.cubrid.org/380295</id>
      <published>2012-06-21T20:59:50-07:00</published>
      <updated>2013-04-16T21:18:33-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/380295"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/380295#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;This page contains nGrinder 3.0 related developer documents.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;[How to build nGrinder from the scratch using Maven]&lt;/li&gt;
&lt;li&gt;[How to build nGrinder Recorder using Maven]&lt;/li&gt;
&lt;li&gt;[Java Implementation for Google Analytics Measurement Protocol]&lt;/li&gt;
&lt;li&gt;[How to setup nGrinder Project in Eclipse]&lt;/li&gt;
&lt;li&gt;[Coding Convention] &lt;/li&gt;
&lt;li&gt;[Feature Completion Rate]&lt;/li&gt;
&lt;li&gt;[How to refer nGrinder Home]&lt;/li&gt;
&lt;li&gt;[Setup Mylyn task reposiroty for JIRA]&lt;/li&gt;
&lt;li&gt;[Spring in nGrinder]&lt;/li&gt;    &lt;li&gt;[How to create dynamic queries in SpringData]&lt;/li&gt;
&lt;li&gt;[How to develop Plugin]&lt;/li&gt;
&lt;li&gt;[v3.1 development features]&lt;/li&gt;
&lt;li&gt;[nGrinder test execution performance test]&lt;/li&gt;
&lt;li&gt;[&lt;a href=&quot;/wiki_ngrinder/entry/ngrinder-git-branching-policy&quot; target=&quot;_self&quot;&gt;Git Branching Policy]&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;[Contributors]&lt;/li&gt; &lt;/ul&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            
   </entry>
   <entry>
      <title>Recorder-Generated Test Script Structure</title>
      <id>http://www.cubrid.org/603902</id>
      <published>2013-03-05T18:03:25-08:00</published>
      <updated>2013-04-16T18:59:22-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/603902"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/603902#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;The structure of a recorded test-script looks like this:&lt;/p&gt;

&lt;pre class=&quot;brush: python;&quot;&gt;(
...
import statements
...
)

(
...
header definitions
...
)

(
...
url definitions
...
)

(
...
request and test definitions
...
)
class TestRunner:
     (
     ...
     method definitions - a method is defined for each recorded page
     ...
     )

     def __call__(self):
     (
     ...
     calls to defined methods, which actually runs the requests
     ...
     )

     ( utility function (I&apos;ll go over this later) )

     (
     ...
     calls to utility function to wrap/instrument tests (I&apos;ll go over this later)
     ...
     )

&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Import statements&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;you will import classes that make the tests work.By default,the following are indispensable.&lt;/p&gt;

&lt;pre class=&quot;brush: java;&quot;&gt;from net.grinder.script import Test
from net.grinder.script.Grinder import grinder
from net.grinder.plugin.http import HTTPPluginControl, HTTPRequest
from HTTPClient import NVPair, Cookie, CookieModule, CookiePolicyHandler&lt;/pre&gt;
&lt;p&gt;The first two import statements import the Test and grinder objects, which give you access to grinder framework and its environment. Next two import statements import utility classes which perform HTTP Requests. The NVPair class lets you organize parameters and values for POST requests nto name-value pairs.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Header definitions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;These headers are used to create the request objects .The generated code looks like this:&lt;/p&gt;

&lt;pre class=&quot;brush: java;&quot;&gt;connectionDefaults = HTTPPluginControl.getConnectionDefaults()
httpUtilities = HTTPPluginControl.getHTTPUtilities()

log = grinder.logger.info
err = grinder.logger.error

# Set up a cookie handler to log all cookies that are sent and received.
class MyCookiePolicyHandler(CookiePolicyHandler):
	def acceptCookie(self, cookie, request, response):
		# log(&quot;accept cookie: %s&quot; % cookie)
		return 1

	def sendCookie(self, cookie, request):
		# log(&quot;send cookie: %s&quot; % cookie)
		return 1
 
def createRequest(url, headers=None):
	&quot;&quot;&quot;Create an instrumented HTTPRequest.&quot;&quot;&quot;
	request = HTTPRequest(url=url)
	if headers: request.headers=headers
	return request

CookieModule.setCookiePolicyHandler(MyCookiePolicyHandler())
 
# These definitions at the top level of the file are evaluated once,
# when the worker process is started.
connectionDefaults.defaultHeaders = &amp;#91;
	NVPair(&apos;Accept-Encoding&apos;, &apos;gzip, deflate&apos;),
	NVPair(&apos;Referer&apos;, &apos;https://accounts.google.com/ServiceLogin?service=mail&amp;amp;passive=true&amp;amp;continue=http://mail.google.com/mail/?ui%3Dmobile%26zyp%3Dl&amp;amp;scc=1&amp;lt;mpl=ecobh&amp;amp;nui=5&amp;amp;btmpl=mobile&apos;),
	NVPair(&apos;Accept-Language&apos;, &apos;ko,Korean;q=0.7,en-US;q=0.3&apos;),
	NVPair(&apos;User-Agent&apos;, &apos;Mozilla/5.0 (iPhone; U; CPU iPhone OS 1_2_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5&apos;)
&amp;#93;


headers0 = &amp;#91;
	NVPair(&apos;Accept&apos;, &apos;*/*&apos;)
&amp;#93;
&lt;/pre&gt;
&lt;p&gt;The first statement creates an HTTPPluginConnection object, which lets you control the behavior of the connection. The next statement creates an instance of an HTTPUtilities object which provides access to various utility methods.&lt;/p&gt;
&lt;p&gt;In the next few lines, the script actually defines the headers. First, it sets up the default headers that are used by each request.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Request and test definitions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;This is the actual requests that we are going to use for our tests:&lt;/p&gt;

&lt;pre class=&quot;brush: python;&quot;&gt;request_https_ssl_google_analytics_com = createRequest(&quot;https://ssl.google-analytics.com&quot;);
request_https_accounts_youtube_com = createRequest(&quot;https://accounts.youtube.com&quot;);
request_https_mail_google_com = createRequest(&quot;https://mail.google.com&quot;);

&lt;/pre&gt;
&lt;p&gt;First,we create an instance of an HTTPRequest object using the previously defined URL’s and Headers.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Page definitions&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;After the request objects have been defined, we come to the actual TestRunner class.&lt;/p&gt;

&lt;pre class=&quot;brush: python;&quot;&gt;# A method for each recorded page.
	def page1(self) :
		##########################################################################################
		# https://accounts.youtube.com/accounts/CheckConnection
		##########################################################################################
		grinder.sleep(196)
		self.token_pmpo = &apos;https://accounts.google.com&apos;  
		self.token_v = &apos;180753535&apos;  
		self.token_timestamp = &apos;1366165396372&apos;  
		result = request_https_accounts_youtube_com.GET(
				&quot;/accounts/CheckConnection?pmpo=%s&amp;amp;v=%s×tamp=%s&quot;
					% (self.token_pmpo, self.token_v, self.token_timestamp),
				None,	
				&amp;#91;
					NVPair(&apos;Accept&apos;, &apos;application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, application/msword, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*&apos;)
				&amp;#93;
			) 
		self.checkResponse(result, 200,  &quot;https://accounts.youtube.com/accounts/CheckConnection&quot;)

		##########################################################################################
		# https://ssl.google-analytics.com/__utm.gif
		##########################################################################################
		self.token_utmwv = &apos;5.4.1&apos;  
		self.token_utms = &apos;1&apos;  
		self.token_utmn = &apos;1757647728&apos;  
		self.token_utmhn = &apos;accounts.google.com&apos;  
		self.token_utmcs = &apos;utf-8&apos;  
		self.token_utmsr = &apos;1920x1080&apos;  
		self.token_utmvp = &apos;839x617&apos;  
		self.token_utmsc = &apos;24-bit&apos;  
		self.token_utmul = &apos;en-us&apos;  
		self.token_utmje = &apos;1&apos;  
		self.token_utmfl = &apos;11.6 r602&apos;  
		self.token_utmdt = &apos;Gmail: Google 이메일&apos;  
		self.token_utmhid = &apos;1841284240&apos;  
		self.token_utmr = &apos;-&apos;  
		self.token_utmp = &apos;/mail/homepage&apos;  
		self.token_utmht = &apos;1366165396400&apos;  
		self.token_utmac = &apos;UA-992684-1&apos;  
		self.token_utmcc = &apos;__utma=72592003.2014635375.1366162754.1366162754.1366165396.2;+__utmz=72592003.1366162754.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);&apos;  
		self.token_utmu = &apos;qjCAAC~&apos;  
		result = request_https_ssl_google_analytics_com.GET(
				&quot;/__utm.gif?utmwv=%s&amp;amp;utms=%s&amp;amp;utmn=%s&amp;amp;utmhn=%s&amp;amp;utmcs=%s&amp;amp;utmsr=%s&amp;amp;utmvp=%s&amp;amp;utmsc=%s&amp;amp;utmul=%s&amp;amp;utmje=%s&amp;amp;utmfl=%s&amp;amp;utmdt=%s&amp;amp;utmhid=%s&amp;amp;utmr=%s&amp;amp;utmp=%s&amp;amp;utmht=%s&amp;amp;utmac=%s&amp;amp;utmcc=%s&amp;amp;utmu=%s&quot;
					% (self.token_utmwv, self.token_utms, self.token_utmn, self.token_utmhn, self.token_utmcs, self.token_utmsr, self.token_utmvp, self.token_utmsc, self.token_utmul, self.token_utmje, self.token_utmfl, self.token_utmdt, self.token_utmhid, self.token_utmr, self.token_utmp, self.token_utmht, self.token_utmac, self.token_utmcc, self.token_utmu),
				None,	
				headers0
			) 
		self.checkResponse(result, 200,  &quot;https://ssl.google-analytics.com/__utm.gif&quot;)

		##########################################################################################
		# https://mail.google.com/mail/images/c.gif
		##########################################################################################
		grinder.sleep(94)
		self.token_t = &apos;1366165396404&apos;  
		result = request_https_mail_google_com.GET(
				&quot;/mail/images/c.gif?t=%s&quot;
					% (self.token_t),
				None,	
				headers0
			) 
		self.checkResponse(result, 200,  &quot;https://mail.google.com/mail/images/c.gif&quot;)
&lt;/pre&gt;
&lt;p&gt;In the script, you have a method for each recorded page, which are called page1, page2.&lt;/p&gt;
&lt;p&gt;Within each page, there are one or more GET and/or POST requests made via the request objects, which simulate the transactions made by a single page.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;__call__ method&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;In Jython any object implementing __call__ is callable, which basically means that this function is called when you call the class instance as a function. In the context of the this script, it just means that this is where all the testing starts off. In the __call__ method you can see that there are calls to all the recorded page methods,and this essentially runs the recorded test.&lt;/p&gt;
&lt;pre class=&quot;brush: python;&quot;&gt;
	def __call__(self) :
		try :
			self.page1()
			grinder.statistics.forLastTest.success = 1
		except Exception, e:
			err(e.message)
			grinder.statistics.forLastTest.success = 0

&lt;/pre&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="script-structure"/>
            
   </entry>
   <entry>
      <title>Recorder Recording Guide</title>
      <id>http://www.cubrid.org/636624</id>
      <published>2013-04-16T00:00:43-07:00</published>
      <updated>2013-04-16T18:49:51-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/636624"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/636624#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;h2&gt;Filtering&lt;/h2&gt;  &lt;p&gt;If you ran the example following Quick Start, you may have been suprised by overwhelmly long generated scripts. It is because there are actually many HTTP/HTTPS messages even in a single browsing which you didn’t notice before. Do we have to include all these in the script? Sometimes it is useless to include all these in the performance test.    &lt;br /&gt;High load services usually use CDN(Content Delivery Network)s for static resources like images or javascripts. CDNs are located in multiple datacenters and the most speedy datacenter is automatically selected depending from where the calls are made. CDNs usually have the very efficient content delivery mechanism enough to handle high loads. Furthermore, they charges the fee depending on the how many contents are delivered.&amp;#160; So it’s really necessary to simulate the call to here? You can not even control the content delivery logics if there are some performance issues. &lt;/p&gt;  &lt;p&gt;Usually developers might want to run the performance test on the web servers under their controls. nGrinder Recorder includes several filtering features.&lt;/p&gt;  &lt;h3&gt;Host name filter&lt;/h3&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;732&quot; height=&quot;204&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;nGrinder Recorder recognizes the host names to which the proxy is connecting and how many calls are made. On the right panel there is a table which lists up the connected hosts and connection counts. When you don’t start Recording yet, this panel shows connected hosts but call count.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_6.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_2.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;730&quot; height=&quot;221&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you start Recording, it shows the recorded call count in “R” column.&amp;#160; You can examine the host names and uncheck all hosts which you don’t interested in.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_12.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_5.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;731&quot; height=&quot;348&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;The easist way to achieve this is to click “Unselect All” button downside and check the interested host.&lt;/p&gt;  &lt;h3&gt;Resource type filter&lt;/h3&gt;  &lt;p&gt;There is one more way to filter out unnecessary static resources. At the downside of the right panel, there is a filter based on file types. “Recorded Type” panel lists the general static resource content type.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_14.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_6.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;199&quot; height=&quot;131&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&amp;#160;&lt;a href=&quot;/files/attach/images/379199/624/636/image_18.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_8.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;198&quot; height=&quot;129&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you uncheck Record Type like above, nGrinder Recorder doesn’t record the HTTP messages which URL paths end with well known resource type names (like .png, .css, .js) or response content type has the well known static resource content type string (like text/javascript). If you uncheck some of these while you are recoding, the previously recorded messages are not deleted. However eventually it will be not included in the final script. If you check them again and generate a script, the script will contains the previously recorded messages. &lt;/p&gt;  &lt;h3&gt;Reset Recording&lt;/h3&gt;  &lt;p&gt;You can completly remove all recording by selecting “Clear all recoding” submenu which is popped up by clicking “Reset” button.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_38.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_16.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;294&quot; height=&quot;161&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; margin: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;There are several sub menus in Reset button. Each has the different action like below.&lt;/p&gt;  &lt;table style=&quot;border-collapse: collapse&quot; bordercolor=&quot;#000000&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; width=&quot;752&quot; border=&quot;1&quot;&gt;&lt;tbody&gt;     &lt;tr style=&quot;color: white; background-color: black&quot;&gt;       &lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;Submenu name&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;533&quot;&gt;Action&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;Clear all recording&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;533&quot;&gt;Clear all recorded messages. However do not change the filter.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;Clear all filters&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;533&quot;&gt;Clear all filters. However do not chnage the recorded messages.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;Clear connection count&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;533&quot;&gt;Make the all connection count 0 in the filter panel.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;Reset browser cache&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;533&quot;&gt;Delete all cached content from the embedded browser so that the browser can actually make a call to the given web pages.&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;217&quot;&gt;Reset cookies&lt;/td&gt;        &lt;td valign=&quot;top&quot; width=&quot;533&quot;&gt;Delete all saved cookes from the embedded browser so that the browser is not interfared by the previosly issued cookies.&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;h2&gt;Script Generation&lt;/h2&gt;  &lt;p&gt;When a user clicks “Stop Recordng” button, the recorded HTTP/HTTPS messages are transformed to The Grinder script. The script generated by nGrinder Recorder is little bit different from TCPProxy provides. We made the script template little bit compact than what TCPProxy generates.&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_22.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_10.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;753&quot; height=&quot;254&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Be aware that “Stop Recording” doesn’t mean “Reset Recording”. If you click Start Recording again, it continues to record the messages appending to existing recording. It’s because there are many reasons to pause the recording (A user might fall down by too much overwork) &lt;/p&gt;  &lt;h3&gt;Add sleep time&lt;/h3&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_24.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_11.png&quot; alt=&quot;image&quot; title=&quot;image&quot; align=&quot;left&quot; class=&quot;iePngFix&quot; width=&quot;204&quot; height=&quot;61&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: left; padding-top: 0px; padding-left: 0px; margin: 0px 10px 0px 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;There are one option for script generation. If you check “Add sleep time” in Script Generation Options option groups, the actual wating time during recoding are included in the unit of milliseconds at the final script like following.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/624/636/image_26.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_12.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;747&quot; height=&quot;391&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;If you went to the toilet after starting recoding, Recorded sleep time might be very long. Please check the how long the script sleep between calls before running a script in nGrinder Controller. &lt;/p&gt;  &lt;p&gt;You can also find very detailed generated script structure explaination here.&lt;/p&gt;  &lt;h2&gt;Mobile Web Page Recording&lt;/h2&gt;  &lt;p&gt;nGrinder Recorder supports the user agent string change in Windows. which means you navigate the mobile site which detects the browser and send the appropriate contents. You can select the which user agent will be used during navigation.&amp;#160; Then even if you navigate the &lt;a href=&quot;http://www.amazon.com&quot;&gt;www.amazon.com&lt;/a&gt;, Then the mobile page is sent from the server like below&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;a href=&quot;/files/attach/images/379199/624/636/image_2.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;255&quot; height=&quot;261&quot; style=&quot;border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px&quot; /&gt;&lt;/a&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_3.png&quot; alt=&quot;image_thumb.png&quot; title=&quot;image_thumb.png&quot; class=&quot;iePngFix&quot; width=&quot;408&quot; height=&quot;259&quot; style=&quot;&quot; /&gt;&lt;/p&gt;  &lt;p&gt;If you don’t want to use this fake browser technique but the real mobile browser from your devices, you can record the messages by configuring your mobile devices proxy settings.&lt;/p&gt;  &lt;table style=&quot;border-collapse: collapse&quot; bordercolor=&quot;#000000&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; width=&quot;752&quot; border=&quot;1&quot;&gt;&lt;colgroup&gt;&lt;col width=&quot;300&quot; /&gt;&lt;col width=&quot;300&quot; /&gt;&lt;/colgroup&gt;&lt;tbody&gt;     &lt;tr style=&quot;color: white; background-color: black&quot;&gt;       &lt;th&gt;IOS&lt;/th&gt;        &lt;th&gt;Android&lt;/th&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;         &lt;ul&gt;           &lt;li&gt;Go to the Settings Application &lt;/li&gt;            &lt;li&gt;Go to General &amp;lt; Network &amp;lt; Wi-Fi &lt;/li&gt;            &lt;li&gt;Select Wi-Fi connection you want to use with HTTP Proxy and connect. &lt;/li&gt;            &lt;li&gt;Edit Wi-Fi connection, scroll down and find &amp;quot;Proxy HTTP&amp;quot; and press on &amp;quot;Manual&amp;quot;&amp;quot;, here we need to fill all proxy connection settings. &lt;/li&gt;            &lt;li&gt;Set server as 10.66.9.95 &lt;/li&gt;            &lt;li&gt;Set port as 10288 &lt;/li&gt;            &lt;li&gt;Disable authentication &lt;/li&gt;         &lt;/ul&gt;       &lt;/td&gt;        &lt;td&gt;         &lt;ul&gt;           &lt;li&gt;Open the Applications tab and tap Settings. &lt;/li&gt;            &lt;li&gt;Tap Wireless &amp;amp; networks. &lt;/li&gt;            &lt;li&gt;Make sure the wireless network is enabled, and connected to the network for which you want to set the proxy server. &lt;/li&gt;            &lt;li&gt;Tap Wi-Fi settings. &lt;/li&gt;            &lt;li&gt;In the list of available networks, tap and hold the network to which you are connected, until a menu shows. &lt;/li&gt;            &lt;li&gt;Tap Modify Network. &lt;/li&gt;            &lt;li&gt;Tap Proxy Settings, and then Manual. &lt;/li&gt;            &lt;li&gt;Set server as 10.66.9.95 &lt;/li&gt;            &lt;li&gt;Set port as 10288 &lt;/li&gt;            &lt;li&gt;Tab Save &lt;/li&gt;         &lt;/ul&gt;       &lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;p&gt;If you set up above, you can record the messages from your devices, just as you did in the embedded browser.&lt;/p&gt;  &lt;h2&gt;HTTPS Handling&lt;/h2&gt;  &lt;p&gt;nGrinder Recorder supports HTTPS as well but very limited way. As described in &lt;a href=&quot;/wiki_ngrinder/entry/recorder-limitation&quot;&gt;Recorder Limitation&lt;/a&gt;, the private self-signed ceritificate is used to intercept the HTTPS messages. So you may see following alerts whenever you access HTTPS sites. &lt;/p&gt;  &lt;p&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/624/636/image_thumb_1_1.png&quot; alt=&quot;image_thumb_1.png&quot; title=&quot;image_thumb_1.png&quot; class=&quot;iePngFix&quot; width=&quot;746&quot; height=&quot;423&quot; style=&quot;&quot; /&gt;     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;To avoid this alert, you have to import the self signed certificate in the trusted certificates. Check out [Recorder-How to import self-signed certificates]&lt;/p&gt;  &lt;p&gt;nGrinder Recorder is to provide another way to work around this issue. Actually this method is introduced by TCPProxy and nGrinder uses it with little modification. If you are going to test your HTTPS server, you might have already the valid certificate. You can provide this instead of embedded certificate for the proxy to use. You can refer how to provide your own certificate in Recorder Installation guide.&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="recorder"/>
            
   </entry>
   <entry>
      <title>nGrinder DevZone</title>
      <id>http://www.cubrid.org/379651</id>
      <published>2012-06-20T18:23:28-07:00</published>
      <updated>2013-04-16T18:47:24-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/379651"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/379651#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/651/379/ngrinder_logo.png&quot; alt=&quot;ngrinder_logo.png&quot; title=&quot;ngrinder_logo.png&quot; class=&quot;iePngFix&quot; width=&quot;730&quot; height=&quot;158&quot; style=&quot;&quot; /&gt;     &lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;font color=&quot;#000000&quot;&gt;&lt;strong&gt;nGrinder&lt;/strong&gt;&lt;/font&gt; (pronounced as en-g-ra-in-der) is a stress tests platform that enables you to create test scripts, execute tests, monitor target servers and generate results simultaneously. The open-source nGrinder offers easy ways to conduct stress tests by eliminating inconveniences and providing integrated environments. It uses the renowned performance test tool, &lt;a href=&quot;http://grinder.sourceforge.net&quot; target=&quot;_blank&quot;&gt;&lt;strong&gt;The Grinder&lt;/strong&gt;&lt;/a&gt;, as its internal engine.&lt;/p&gt;  &lt;p&gt;This is the tool developed by the service provider who really runs frequent load testing not by tool vendor. A breakthrough feature of nGrinder 3.X is support for concurrent tests which means that multiple users can run different tests at the same time! And it&apos;s cloud friendly and has attractive interface !&lt;/p&gt;

&lt;p&gt;nGrinder is being developed by NHN Korea and NHN China together.&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; width=&quot;702&quot;&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td valign=&quot;top&quot; width=&quot;336&quot; class=&quot;&quot;&gt;         &lt;ul&gt;           &lt;li&gt;&lt;a href=&quot;http://www.nhnopensource.org/ngrinder/&quot; target=&quot;_self&quot;&gt;Official Home Page&lt;/a&gt; &lt;/li&gt;            &lt;li&gt;[Architecture] &lt;/li&gt;            &lt;li&gt;[Screen Shot] &lt;/li&gt;            &lt;li&gt;[Guide]&lt;/li&gt;            &lt;ul&gt;             &lt;li&gt;[Installation Guide] &lt;/li&gt;              &lt;li&gt;[Admin Guide] &lt;/li&gt;              &lt;li&gt;[User Guide] &lt;/li&gt;
&lt;li&gt;[Scripting Guide]&lt;/li&gt;
&lt;li&gt;[Recorder Guide]&lt;/li&gt;           &lt;/ul&gt;            &lt;li&gt;[Presentations]&lt;/li&gt;
&lt;li&gt;[Professional Service]&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;&lt;td valign=&quot;top&quot; width=&quot;364&quot; class=&quot;&quot;&gt;&lt;ul&gt;
&lt;li&gt;[nGrinder Release Notes|Release Notes]&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://sourceforge.net/projects/ngrinder/files&quot; target=&quot;_blank&quot;&gt;Downloads&lt;/a&gt; &lt;/li&gt;            &lt;li&gt;[Road Map] &lt;/li&gt;            &lt;li&gt;[Dev Document] &lt;/li&gt;            &lt;li&gt;&lt;a href=&quot;http://ngrinder-dev.642.n7.nabble.com/&quot; target=&quot;_self&quot;&gt;Mailing List&lt;/a&gt;&lt;/li&gt;            &lt;li&gt;&lt;a href=&quot;http://jira.cubrid.org/browse/NGRINDER&quot; target=&quot;_blank&quot;&gt;Issue Tracker&lt;/a&gt;&lt;/li&gt;            &lt;li&gt;[Frequently Asked Question] &lt;/li&gt;
&lt;li&gt;[How to Use Windows LiveWriter in nGrinder wiki|Wiki Guide]&lt;/li&gt;
&lt;li&gt;[Who uses nGrinder]&lt;/li&gt;
&lt;li&gt;[Help nGrinder]&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="architecture"/>
            
   </entry>
   <entry>
      <title>Recorder Guide</title>
      <id>http://www.cubrid.org/637550</id>
      <published>2013-04-16T18:45:05-07:00</published>
      <updated>2013-04-16T18:45:05-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/637550"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/637550#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;Please follow [Recorder].&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="recorder"/>
            
   </entry>
   <entry>
      <title>Guide</title>
      <id>http://www.cubrid.org/437757</id>
      <published>2012-09-27T07:22:21-07:00</published>
      <updated>2013-04-16T18:43:59-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/437757"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/437757#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;&lt;/p&gt;This page provides the collection of nGrinder guides.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;
&lt;li&gt;[Installation Guide] /&amp;nbsp;[Upgrade Guide]&lt;/li&gt;
&lt;li&gt;[Quick Start]&lt;/li&gt;
&lt;li&gt;[User Guide]&lt;/li&gt;
&lt;li&gt;[Admin Guide]&lt;/li&gt;
&lt;li&gt;[Recorder Guide]&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="user-guide"/>
            
   </entry>
   <entry>
      <title>How to add custom monitor data</title>
      <id>http://www.cubrid.org/625619</id>
      <published>2013-04-01T22:31:18-07:00</published>
      <updated>2013-04-16T18:35:09-07:00</updated>
      <link rel="alternate" type="text/html" href="http://www.cubrid.org/625619"/>
      <link rel="replies" type="text/html" href="http://www.cubrid.org/625619#comment"/>
      <author>
         <name>junoyoon</name>
               </author>
            <content type="html">&lt;div class=&quot;xe_content&quot;&gt;&lt;p&gt;From nGrinder 3.1.3, we provided support for the custom monitor data for target monitoring. It can be used if you want to check some monitor data of target server in the test report. All you need to do, is to use any tools you like to generate the monitor data with some internal time. (The best practice is to set the internal time as same as the sampling interval of nGrinder test.) And the data should be saved in:&lt;/p&gt;  &lt;p&gt;${ngrinder_agent}/monitor/custom.data&lt;/p&gt;  &lt;p&gt;And the content of this file should be the several values of monitoring, seporated with “,”. And it only contains the current value with only one line. As below:&lt;/p&gt;  &lt;p&gt;315630613,1123285602,1106612131&lt;/p&gt;  &lt;p&gt;And then, you need to make sure the file is being updated during the test running. nGrinder monitor will get its content and send to nGrinder controller. After the test finished, you can see the target monitoring chart page in test report:&lt;/p&gt;  &lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/619/625/image_4.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/619/625/image_thumb_1.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;674&quot; height=&quot;576&quot; style=&quot;border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px&quot; /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Be noticed that the chart name is “CUSTOM MONITOR DATA 1”, “CUSTOM MONITOR DATA 2” .., till “CUSTOM MONITOR DATA 5”. And there will be at most 5 custom data. You can save the meaning of this fileds as the test comment.&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;So, the next, we need to use some tool to get the monitor data and save into that file with some interval.&lt;/p&gt;  &lt;p&gt;To do that, the first thing on Linux you may think about is “cron”. We can create a script and run it with “cron”. But with “cron”, the minimal interval is minute. But for nGrinder monitoring, at the most of time the interval is one second.&lt;/p&gt;  &lt;p&gt;So in this guide, I will use java to get the java VM running information with JMX. If the target server is a java application like tomcat, we can use the way in this guide to get the VM running information of tomcat, and display the data in chart in the final report.&lt;/p&gt;  &lt;p&gt;As I said above, I will use JMX to get the VM data. But in the normal we will not enable the JMX server of tomcat. So we will use attach API to attach to the target process, and&amp;nbsp; enable the “management-agent”, and then we can connect with JMX to the target process.&lt;/p&gt;  &lt;p&gt;You can find the VMMonitor.java from &lt;a href=&quot;https://gist.github.com/Mavlarn/5289680&quot; target=&quot;_blank&quot;&gt;gist&lt;/a&gt;. Be aware about the code that, in java VM, for different java version and different GC setting, the GC names will be different. So in this code, I get the GC names of current Java VM, and using these names to get target process GC information with JMX. So the Java environment you use to run this code should be same as that you run the target tomcat. And the VM option like “-server” or GC setting should also be same. Otherwise, you can not get the GC names of target tomcat process.&lt;/p&gt;  &lt;p&gt;And below, we will use this code to get the GC information of target process and save into custom.data file. The new code is as below:&lt;/p&gt;  &lt;pre class=&quot;brush: java; auto-links: false;&quot;&gt;import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

/**
 * Class description.
 * 
 * @author Mavlarn
 */
public class GCMonitor {

    public static Set&amp;lt;String&amp;gt; youngGCNames = new HashSet&amp;lt;String&amp;gt;();
    public static Set&amp;lt;String&amp;gt; oldGCNames = new HashSet&amp;lt;String&amp;gt;();

    static {
        // Oracle (Sun) HotSpot
        youngGCNames.add(&quot;Copy&quot;); // -XX:+UseSerialGC
        youngGCNames.add(&quot;ParNew&quot;); // -XX:+UseParNewGC
        youngGCNames.add(&quot;PS Scavenge&quot;); // -XX:+UseParallelGC

        // Oracle (BEA) JRockit
        youngGCNames.add(&quot;Garbage collection optimized for short pausetimes Young Collector&quot;); // -XgcPrio:pausetime
        youngGCNames.add(&quot;Garbage collection optimized for throughput Young Collector&quot;); // -XgcPrio:throughput
        youngGCNames.add(&quot;Garbage collection optimized for deterministic pausetimes Young Collector&quot;); // -XgcPrio:deterministic

        // Oracle (Sun) HotSpot
        oldGCNames.add(&quot;MarkSweepCompact&quot;); // -XX:+UseSerialGC
        oldGCNames.add(&quot;PS MarkSweep&quot;); // -XX:+UseParallelGC and
                                        // (-XX:+UseParallelOldGC or -XX:+UseParallelOldGCCompacting)
        oldGCNames.add(&quot;ConcurrentMarkSweep&quot;); // -XX:+UseConcMarkSweepGC

        // Oracle (BEA) JRockit
        oldGCNames.add(&quot;Garbage collection optimized for short pausetimes Old Collector&quot;); // -XgcPrio:pausetime
        oldGCNames.add(&quot;Garbage collection optimized for throughput Old Collector&quot;); // -XgcPrio:throughput
        oldGCNames.add(&quot;Garbage collection optimized for deterministic pausetimes Old Collector&quot;); // -XgcPrio:deterministic
    }

    static final String CONNECTOR_ADDRESS = &quot;com.sun.management.jmxremote.localConnectorAddress&quot;;

    public static void main(String&amp;#91;&amp;#93; args) throws InterruptedException {
        if (args == null || args.length == 0) {
            System.err.println(&quot;Please specify the target PID to attach.&quot;);
            return;
        }

        // attach to the target application
        VirtualMachine vm;
        try {
            vm = VirtualMachine.attach(args&amp;#91;0&amp;#93;&amp;#93;);
        } catch (AttachNotSupportedException e) {
            System.err.println(&quot;Target application doesn&apos;t support attach API.&quot;);
            e.printStackTrace();
            return;
        } catch (IOException e) {
            System.err.println(&quot;Error during attaching to target application.&quot;);
            e.printStackTrace();
            return;
        }

        try {
            // get the connector address
            String connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
            MBeanServerConnection serverConn;
            // no connector address, so we start the JMX agent
            if (connectorAddress == null) {
                String agent = vm.getSystemProperties().getProperty(&quot;java.home&quot;) + File.separator + &quot;lib&quot;
                        + File.separator + &quot;management-agent.jar&quot;;
                vm.loadAgent(agent);
                // agent is started, get the connector address
                connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
            }

            // establish connection to connector server
            JMXServiceURL url = new JMXServiceURL(connectorAddress);
            JMXConnector connector = JMXConnectorFactory.connect(url);
            serverConn = connector.getMBeanServerConnection();
            ObjectName objName = new ObjectName(ManagementFactory.RUNTIME_MXBEAN_NAME);

            // Get standard attribute &quot;VmVendor&quot;
            String vendor = (String) serverConn.getAttribute(objName, &quot;VmVendor&quot;);
            System.out.println(&quot;vendor:&quot; + vendor);

            String&amp;#91;&amp;#93; gcNames = getGCNames();
            while(true) {
                long minorGCCount = 0;
                long minorGCTime = 0;
                long fullGCCount = 0;
                long fullGCTime = 0;
                
                for (String currName : gcNames) {
                    objName = new ObjectName(&quot;java.lang:type=GarbageCollector,name=&quot; + currName);
                    Long collectionCount = (Long) serverConn.getAttribute(objName, &quot;CollectionCount&quot;);
                    Long collectionTime = (Long) serverConn.getAttribute(objName, &quot;CollectionTime&quot;);
                    if (youngGCNames.contains(currName)) {
                        minorGCCount = collectionCount;
                        minorGCTime = collectionTime;
                    } else if (oldGCNames.contains(currName)) {
                        fullGCCount = collectionCount;
                        fullGCTime = collectionTime;
                    }
                    StringBuilder sb = new StringBuilder(&quot;&amp;#91;&quot;);
                    sb.append(getGCType(currName)).append(&quot;	: &quot;);
                    sb.append(&quot;Count=&quot; + collectionCount);
                    sb.append(&quot; 	GCTime=&quot; + collectionTime);
                    sb.append(&quot;&amp;#93;&quot;);
                    System.out.println(sb.toString());
                }
                StringBuilder valueStr = new StringBuilder();
                //custom data format is:
                //minorGCCount,minorGCTime,fullGCCount,fullGCTime
                valueStr.append(minorGCCount);
                valueStr.append(&quot;,&quot;);
                valueStr.append(minorGCTime);
                valueStr.append(&quot;,&quot;);
                valueStr.append(fullGCCount);
                valueStr.append(&quot;,&quot;);
                valueStr.append(fullGCTime);
                writeToFile(valueStr.toString());
                Thread.sleep(1000); //sleep one second.
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static String getGCType(String name) {
        if (youngGCNames.contains(name)) {
            return &quot;Minor GC&quot;;
        } else if (oldGCNames.contains(name)) {
            return &quot;Full GC&quot;;
        } else {
            return name;
        }
    }

    public static String&amp;#91;&amp;#93; getGCNames() {
        List&amp;lt;GarbageCollectorMXBean&amp;gt; gcmbeans = ManagementFactory.getGarbageCollectorMXBeans();
        String&amp;#91;&amp;#93; rtnName = new String&amp;#91;gcmbeans.size()&amp;#93;;
        int index = 0;
        for (GarbageCollectorMXBean gc : gcmbeans) {
            rtnName&amp;#91;index&amp;#93; = gc.getName();
            index++;
        }
        return rtnName;
    }
    
    public static void writeToFile(String gcData) {
        String currDir = System.getProperty(&quot;user.dir&quot;);
        BufferedWriter writer = null;
        
        try {
            File customFile = new File(currDir + File.separator + &quot;custom.data&quot;);
            if (!customFile.exists()) {
                customFile.createNewFile();
            }
            writer = new BufferedWriter(new FileWriter(customFile));
            writer.write(gcData);
            writer.flush();
        } catch (IOException e) {
            System.err.println(&quot;Error to read custom monitor data:&quot; + e.getMessage());
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}&lt;/pre&gt;

&lt;p&gt;Some comments about the code are:&lt;/p&gt;

&lt;p&gt;a) We need to pass the target process ID as arguments to run.&lt;/p&gt;

&lt;p&gt;b) This code should be run under same java environment and VM option with the target process. Otherwise, the attaching will properly fail. And if the target tomcat process is running with “-server” option, also be aware to set “-server” option to run this java code.&lt;/p&gt;

&lt;p&gt;Becasue under different java version and setting, the GC names will be different, I founded some names and their types(monior GC or full). They are not complete and maybe not very correct. If you use IBM JVM, you should modify the code by yourself.&lt;/p&gt;

&lt;p&gt;c) The custom values format is “minorGCCount,minorGCTime,fullGCCount,fullGCTime”.&lt;/p&gt;

&lt;p&gt;d) This java code should be run in “${ngrinder_agent}/monitor/” directory. Becasue in the code, it will create custom.data file in current directory.&lt;/p&gt;

&lt;p&gt;e) To compile the code, it needs “tools.jar” of JDK.&amp;nbsp; You need to compile it like this:&lt;/p&gt;

&lt;pre class=&quot;brush: bash; auto-links: false;&quot;&gt;javac -cp /home/ngrinder/jdk1.6.0_38/lib/tools.jar GCMonitor.java

#get target tomcat process ID, it is 24003
java -cp /home/ngrinder/jdk1.6.0_38/lib/tools.jar: GCMonitor  24003&lt;/pre&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Then you should see the output in console as below:&lt;/p&gt;

&lt;pre class=&quot;brush: bash; auto-links: false;&quot;&gt;current dir:/home/ngrinder/.ngrinder_agent/monitor
&amp;#91;Minor GC       : Count=3564    GCTime=27850&amp;#93;
&amp;#91;Full GC        : Count=166     GCTime=65525&amp;#93;
&amp;#91;Minor GC       : Count=3564    GCTime=27850&amp;#93;
&amp;#91;Full GC        : Count=166     GCTime=65525&amp;#93;&lt;/pre&gt;

&lt;p&gt;And in custom.data file, the content is:&lt;/p&gt;

&lt;pre class=&quot;brush: bash; auto-links: false;&quot;&gt;3564,27850,166,65525&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Then, create a new test on nGrinder and set the target host properly. You can see the chart in test report:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/files/attach/images/379199/619/625/image_6.png&quot;&gt;&lt;img src=&quot;http://www.cubrid.org/files/attach/images/379199/619/625/image_thumb_2.png&quot; alt=&quot;image&quot; title=&quot;image&quot; class=&quot;iePngFix&quot; width=&quot;558&quot; height=&quot;568&quot; style=&quot;border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px&quot; /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;(Becasue the GC count is not changed very much, so we can not see much difference from the chart.)&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;p&gt;In this way, you can add any kind of custom monitor data and check it from test report.&lt;/p&gt;&lt;/div&gt;</content>
                  <category term="ngrinder"/>
            <category term="monitor"/>
            
   </entry>
</feed> 
