Friday, 16 October 2015

LoadRunner Correlation with web_reg_save_param_regexp

Do you have a correlation which you can’t solve because the values of the left and right boundary are dynamic? Correlation is an essential part of performance test scripting and there are plenty of different challenges with correlation. Imagine having a value of “GraphA123567EndGraphA” and the goal is to correlate 123567
From the example above, the left and right boundaries would be “LB=GraphA” “RB=EndGraphA”
What if the word GraphA is dynamic and can be anything from GraphA-GraphZ?
There is a solution at hand!
Using web_reg_save_param_regex will allow the user to grab a correlation value using dynamic left and right boundaries. This function uses the power of regular expressions, below are a few examples:
Example 1:
Source: “GraphA123567EndGraphA”
Solution: web_reg_save_param_regexp(“ParamName=CorrValue”, “RegExp=\“Graph[A-Za-z]\”, \“([0-9]+)\”, \“EndGraph[A-Za-z]\””, LAST);
Result: 123567
Example 2:
Correlate the values from a drop down list of a form
Source: dropdown >>> red, blue, green
Solution: web_reg_save_param_regexp(“ParamName=ColourList”, “RegExp=option=[0-9]+>([A-Za-z])
  • {ColourList1}=red
  • {ColourList2}=blue
  • {ColourList3}=green
Example 3:
Correlate up till the end of 642
Source:J\u002blsGd3zj1qdP\u002bvk0vDRaKyJFde5tCa6spDEy08SNab1hP8j5GTs4j6\u002f\u002bTqOwvxMHEQZLWd\u002btu8NlHJrVAarIQ==|634998513832503642″];
Solution: web_reg_save_param_regexp(“ParamName=SecurityString”,”RegExp=\”([A-Z0-9a-z\\\\+]+==\\|[0-9]+)\”\\];”,LAST);
Result:J\u002blsGd3zj1qdP\u002bvk0vDRaKyJFde5tCa6spDEy08SNab1hP8j5GTs4j6\u002f\u002bTqOwvxMHEQZLWd\u002btu8NlHJrVAarIQ==|634998513832503642
Example 4:
Correlate only “634998513832503642” Source:
<em>J\u002blsGd3zj1qdP\u002bvk0vDRaKyJFde5tCa6spDEy08SNab1hP8j5GTs4j6\u002f\u002bTqOwvxMHEQZLWd\u002btu8NlHJrVAarIQ==|634998513832503642"];</em>
Solution:
web_reg_save_param_regexp("ParamName=SecurityString",
    "RegExp=\"[A-Z0-9a-z\\\\+]+==\\|([0-9]+)\"\\];",
    LAST);
Result: 634998513832503642
So what is a Regular Expression? 
Also known as regex, a regular expression is a search string which enables matching of a string. Think of it as an advance searching function which can pick out values from a string of multiple characters.
Examples of regex:
  • \d matches a single digit
  • \w matches a single word (including alphanumeric characters and underscore)
  • [A-Z]+ matches any word which is upper case
  • [a-z]+ matches any word which is lower case
  • [0-9]+ matches any numeric value
There are other alternatives to web_reg_save_param_regexp. However these functions are limited and not as flexible.
LB/DIG RB/DIG – # will be a wildcard for a numeric value“session_id_##”
  • Adding LB/IC/DIG will ignore case
  • “LB/IC/DIG=session_id_##=” (e.g. Session_id_20)
LB/ALNUM or RB/ALNUM – ^ will be a wildcard for an alphanumeric value
  • ALNUMIC – ignore case
  • ALNUMLC – match only lower case
  • ALNUMUC – match only upper case
SaveOffSet
  • If there is a dynamic value for a boundary e.g. “session_id_2” (3,4,5)
  • SaveOffSet = 2 (to cover “2=”)
  • Web_reg_save_param(“SessionID”, “LB=session_id_”, “RB=\””, “SaveOffSet=2”, LAST);
LR implementation
  • PERL based
  • LR 11 does not support multiple capture groups however this is now supported in LR 11.52 (example below)
Example Multiple Capture Groups
Source: rows”:[[“NW,RO,RA”,”DLY”,”10/07/2011″,”10/17/2011″,”10/01/2011″,”RA”,”Y”,”FR”,”AMEA”,”AC”,”1945″,”50″,”50″,”AC 100IOSH-08″,”UserDefined”,”10/07/2011″,”Reassigned”…”
Solution: web_reg_save_param_regexp(“ParamName=ParamValue”,”RegExp=rows”:\[\[“[^”\r\n]*”,”([A-Z]{3})”,”[^”\r\n]*”,”[^”\r\n]*”,”[^\/]+\/[\d]+?\/2011″,”[A-Za-z]*”,”[^”\r\n]*”,”[^”\r\n]*”,”([^”\r\n]*)”,”[^”\r\n]*”,”([^”\r\n]*)”,LAST);
Result:
  • {ParamValue1} = DLY
  • {ParamValue2} = AMEA
  • {ParamValue3} = 1945

Sunday, 11 October 2015

Test Plan vs Test Strategy

Test Plan
Test Strategy
  • A test plan for software project can be defined as a document that defines the scope, objective, approach and emphasis on a software testing effort
  • Test strategy is a set of guidelines that explains test design and determines how testing needs to be done
  • Components of Test plan include- Test plan id, features to be tested, test techniques, testing tasks, features pass or fail criteria, test deliverables, responsibilities, and schedule, etc.
  • Components of Test strategy includes- objectives and scope, documentation formats, test processes, team reporting structure, client communication strategy, etc.
  • Test plan is carried out by a testing manager or lead that describes how to test, when to test, who will test and what to test
  • A test strategy is carried out by the project manager. It says what type of technique to follow and which module to test
  • Test plan narrates about the specification
  • Test strategy narrates about the general approaches
  • Test plan can change
  • Test strategy cannot be changed
  • Test planning is done to determine possible issues and dependencies in order to identify the risks.
  • It is a long-term plan of action.You can abstract information that is not project specific and put it into test approach
  • A test plan exists individually
  • In smaller project, test strategy is often found as a section of a test plan
  • It is defined at project level
  • It is set at organization level and can be used by multiple projects

Monday, 5 October 2015

Changing Pacing time while a test is running

You might have noticed that once you have started your load test, it is possible to increase the number of transactions per hour by adding virtual users, but not by changing the pacing time.
The VuGen Pacing runtime setting is only read at the start of the test so, to change it, it is necessary to stop the test, then make the change and restart.
Fortunately (if you need to), you can write code to control the pacing of your virtual users instead of using the runtime settings. If you write code to pick up a pacing setting from a file, and check the file on each iteration, then you can cause your script to delay for the right amount of time to meet your desired transaction rate.

Obviously, if you are controlling the pacing yourself, you should have the Pacing runtime setting set to “start new iteration as soon as the previous iteration ends”. And if you are using think time for the pacing delay, you should have the Think Time runtime setting set to “replay think time” (or use think time that can’t be ignored).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Action()
{
  merc_timer_handle_t timer; 
  double duration;
  double pacing_time;
 
  // Read desired pacing timer from a text file.
  // The text file should contain the number of seconds to be used for pacing. 
  pacing_time = (double)jds_read_pacing_time("C:\\TEMP\\vugen_pacing.txt");
 
  // Start the timer.
  timer = lr_start_timer(); 
 
  // Call Action function that you want to control pacing for.
  // Note that if you do it this way (rather than putting the pacing code at the start and end of the 
  // Action), then you need to first go to the Run Logic area of the runtime settings, and right-click the 
  // Search Action and select "remove item" from the context menu.
  Search();
 
  // Stop the timer
  duration = lr_end_timer(timer); 
 
  // Wait for the necessary number of seconds to elapse before starting the next iteration.
  if (duration < pacing_time) {
    lr_think_time(pacing_time - duration);
  } else {
    lr_error_message("Pacing time exceeded. Target: %G seconds. Actual: %g seconds", pacing_time, duration);
  }
 
  return 0;
}
 
// Read pacing time from a file. Returns time in seconds (whole seconds only).
// Note that file can be on a shared network drive.
int jds_read_pacing_time(char* file_name) {
  long fs; // file stream
  int number_from_file;
 
  // Open the file for reading
  fs = fopen(file_name, "r+");
  if (fs == NULL) {
    lr_error_message("Error opening file: %s", file_name);
    return -1;
  }
 
  // Read number from file.
  if (fscanf(fs, "%d", &number_from_file) != 1) {
    lr_error_message("Error reading number from file: %s", file_name);
    return -1;
  }
 
  fclose(fs);
 
  return number_from_file;
}

Thursday, 1 October 2015

String Token Function & Reading Parameter Array

 Action()
{


char a,b,c;
char *value="040;350;07/05/2012";
char *temp;


lr_save_string(value,"TokenValue_1");
temp=(char *)strtok(lr_eval_string("{TokenValue_1}"),";");

lr_save_string(temp,"TokenValue1");
a=lr_output_message("%s",lr_eval_string("{TokenValue1}"));
lr_output_message("the string  a = %s",lr_eval_string("{TokenValue1}"));


temp=(char *) strtok(NULL,";");


lr_save_string(temp,"TokenValue2");

b=lr_output_message("%s",lr_eval_string("{TokenValue2}"));
lr_output_message("the string  b = %s",lr_eval_string("{TokenValue2}"));


temp=(char *) strtok(NULL,";");


lr_save_string(temp,"TokenValue3");
c=lr_output_message("%s",lr_eval_string("{TokenValue3}"));

lr_output_message("the string  c = %s",lr_eval_string("{TokenValue3}"));


    return 0;
} Action()
{


char a,b,c;
char *value="040;350;07/05/2012";
char *temp;


lr_save_string(value,"TokenValue_1");
temp=(char *)strtok(lr_eval_string("{TokenValue_1}"),";");

lr_save_string(temp,"TokenValue1");
a=lr_output_message("%s",lr_eval_string("{TokenValue1}"));
lr_output_message("the string  a = %s",lr_eval_string("{TokenValue1}"));


temp=(char *) strtok(NULL,";");


lr_save_string(temp,"TokenValue2");

b=lr_output_message("%s",lr_eval_string("{TokenValue2}"));
lr_output_message("the string  b = %s",lr_eval_string("{TokenValue2}"));


temp=(char *) strtok(NULL,";");


lr_save_string(temp,"TokenValue3");
c=lr_output_message("%s",lr_eval_string("{TokenValue3}"));

lr_output_message("the string  c = %s",lr_eval_string("{TokenValue3}"));


    return 0;
}


==================================

Action()
{
int i;
char value [100]; 

web_reg_save_param("Table", "LB=",RB=","Ord=ALL",LAST); 

LB should be a href and RB be >

web_url("MERCURY", "URL=http://www.mercury.com", LAST );
for (i=1; i<= atoi(lr_eval_string("{Table_count}")); i++){
sprintf(value,"{Table_%d}",i);
lr_output_message("Value %d = %s ",i,lr_eval_string(value));
}
return 0;

  1. }

????????????????///////////////////////???????????????????
Example 2:
xtern char * strtok(char * string, const char * delimiters ); // Explicit declaration
    char String_org[] = “http://localhost/app/myapp:8080”; // original string 
    char delimiter[] = “/:”;
    char * token;
    token = (char *)strtok(String_org, delimiter); // capture 1st sub string based on defined delimiter
    if (!token) {
        lr_output_message (“No tokens found in string!”);
        return( -1 );
    }
    while (token != NULL ) { // While valid tokens are returned
        lr_output_message (“%s”, token );
        token = (char *)strtok(NULL, delimiter); // Get the next token
    } 
- See more at: http://www.techsquids.com/pt/strtok-loadrunner/#sthash.QgUWWKck.dpuf

Monday, 28 September 2015

In-Script simulation of a load-balancer with LoadRunner

When testing enterprise grade web-based solutions there is often a company-wide LoadBalancer present that is a black-box from the testers point of view. Bypassing the LoadBalancer during testing is usually very important to be able to determine one servers limits or capacity.
There are however situations where the LB’s need to be simulated in a controlled way, and having the load share known and controlled during testing. To achieve this there is a simple trick that can be used in LoadRunner scripts.
The easiest way is to create a new action and then place this action in the correct place in the Run-Logic tree. Depending on the script it can be inserted as the last VUSER_INIT action or the 1st action in the VUSER_RUN section.
We now add a new parameter named VUserID to the parameter list, selecting the VUSER ID parameter type.
The code in the new action simply changes the target DOMAIN based on the VUserID parameter. Using the VuserID is good since we know it’s an integer number and always unique for the test.
Below is an example code where even and odd VuserID’s are used to determine the domain name:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Manual Load-Balancing
// This code enables execution of traffic to two separate web-servers, distributed 50/50
// by sending Even and Odd VUserID's to separate Web-Servers</code>
// Get the VUserID (Does not matter what the ID is
VUserID = atoi( lr_eval_string("{VUserID}") );
//if (VUserID & 0x0001==0) // use AND operator to filter out LSB bit
if(VUserID%2 == 0)
{
  lr_save_string( "http://www.server1.com", "BaseURL" ); // Even VUserID's
} else
{
  lr_save_string( "http://www.server2.com", "BaseURL" ); // Odd VUserID's
}
And here’s an example on how to actually use the BaseURL parameter:
1
2
3
4
5
6
7
8
9
10
11
lr_start_transaction("Homepage");
web_url("Home",
    "URL={BaseURL}/",   // BaseURL is determined by code above!
    "TargetFrame=",
    "Resource=0",
    "RecContentType=text/html",
    "Mode=HTML",
    LAST);
lr_end_transaction("Homepage", LR_AUTO);