Monday 3 June 2013

Siebel Protocol recording and correlation in load runner

Siebel 7.x Record and Replay for LoadRunner 8.x

Preparation before record – Internet Explorer Settings

To avoid problems, verify and change the following Internet Explorer’s settings before you try to record:
1.      Enable all ActiveX controls and plug-ins. This option is available in Internet Explorer ® Tools ® Internet Options ® Security ® Custom Level).
2.      Enable the “Use HTTP 1.1 through proxy connection” option. This option is available in Internet Explorer ® Tools ® Internet Options ® Advanced, under the “HTTP 1.1 settings” radio button.

Recording Siebel script with Auto-Correlation option

Correlation is the mechanism by which VuGen saves dynamic values to parameters during record and replay, for use at a later point in the script. For general information about correlation, you can refer to Problem ID 11806 - What is correlation and how is it done

For Siebel script, you can instruct VuGen to automatically apply correlation during recording using one of the following methods:
·         VuGen Native Siebel Correlation
The native, built-in rules, work on a low level, allowing you to debug your script and understand the correlations in depth.
·         Siebel Correlation Library
The Siebel correlation library automatically correlates most of the dynamic values, creating a concise script that you can replay easily. Note that this is only available for Siebel 7.7 and the library is distributed by Siebel.

How to record with VuGen Native Siebel Correlation

VuGen’s native built-in rules for the Siebel server detect the Siebel server variables and strings, automatically saving them for use at a later point within the script. It is available in VuGen recording option by default; you do not need to have any additional components installed.

Steps to record with Native Siebel correlation:

1.      From the ‘New Multiple Protocol Script’ window, add ‘Siebel-Web’ and click OK.

2.      Set the following Recording Options:
a.       Internet Protocol: Recording:
·         Select ‘ HTML based script’
·         Click on ‘HTML Advanced’ and select the following
i.        Script Type: a script containing explicit URLs only
ii.      Non HTML-generated elements: Do not record
  1. Internet Protocol: Advanced:
i.        Clear the ‘Reset context for each action’ option.
ii.      Select ‘Support Charset’ then select ‘UTF-8’
  1. Internet Protocol: Correlation:
i.        Make sure that you have ‘Enable Correlation during recording’
ii.      Make sure that ‘Siebel’ is selected. You can expand the list to see the details about each rule if you wish.
  1. Leave other options as default.

3.      Record in the following way:
·         Record the login in the vuser_init section
·         Record the Business Process in Action1
·         Record the logout in the vuser_end section

How to record with Siebel Correlation Library

Siebel has released a correlation library file, ssdtcorr.dll, as part of the Siebel Application Server version 7.7. This library is available only through Siebel and can be found on siebsrvr\bin directory for Windows

Note: The Siebel Correlation API is supported on Windows 2000 and Windows XP only. This implies that if you correlate the script with this method, you cannot replay this script on UNIX platform. If you need to run the script on UNIX platform, use the VuGen Native Siebel Correlation method.

The library file, ssdtcorr.dll, must be available to all machines where a Load Generator, Controller, or Tuning Console resides.

Steps to record with Siebel correlation library:

1.      Copy ssdtcorr.dll into the <LoadRunner>\bin directory of Controller / Tuning Console, and ALL Load Generator machines

2.      From the ‘New Multiple Protocol Script’ window, add ‘Siebel-Web’ and click OK.

3.      Set the following Recording Options:
a.       Internet Protocol: Recording:
·         Select ‘HTML based script’
·         Click on ‘HTML Advanced’ and select the following
    1. Script Type: a script containing explicit URLs only
    2. Non HTML-generated elements: Do not record
  1. Internet Protocol: Advanced:
i.        Clear the ‘Reset context for each action’ option.
ii.      Select ‘Support Charset’ then select ‘UTF-8’
  1. Internet Protocol: Correlation:
i.        Delete the default ‘Siebel’ correlation rule
ii.      Click on ‘Import’, the ‘Import correlation Settings from a file’ window opens.
iii.    Navigate to <LoadRunner>\dat\webrulesdefaultsetting directory, select ‘WebSiebel77Correlation.cor’ and click ‘Open’
iv.    On the ‘Confirm Rule Replacement’ window, select ‘Overwrite’
Note:  To revert back to the default correlation, delete all of the Siebel rules and click ‘Use Defaults’.
  1. Leave other options as default.

4.      Record in the following way:
·         Record the login in the vuser_init section
·         Record the Business Process in Action1
·         Record the logout in the vuser_end section


Replaying Siebel script – Run-Time Settings

Make sure that “Simulate a new user on each iteration” is not selected in the Browser Emulation options.

Common Replay Errors

Error: “We detected an Error which may have occurred for one or more of the following reasons: We are unable to process your request. This is most likely because you used the browser BACK or REFRESH button to get to this point.”


Diagnosis: A HTTP request has been sent twice to the server. This could be an individual web_url request or part of the resources being downloaded from another request. When sending the second request to the server, the Siebel 7.x server detects multiple requests and thus, issues the above error.

Example:
The following is a sample HTML-based script. Even though “start.swe3” is a frame within step “start.swe2,” you can see that an additional request is generated for “start.swe3” because of the “wait.html” step. On replay, the server may reject the second request,  “start.swe3,” since it is the same for the HTTP call generated by “start.swe2.” This may be due to the SWECount or SWEC.

      web_submit_data("start.swe2",
            "Action=http://64.242.155.45/callcenter/start.swe",
            "Method=POST",
            "RecContentType=text/html",
            "Referer=http://64.242.155.45/callcenter/start.swe?SWECmd=Start",
            "Mode=HTML",
            ITEMDATA,
            "Name=SWEUserName", "Value=sadmin", ENDITEM,
            "Name=SWEPassword", "Value=sadmin", ENDITEM,
            "Name=SWENeedContext", "Value=false", ENDITEM,
            "Name=SWEFo", "Value=SWEEntryForm", ENDITEM,
            "Name=SWETS", "Value=1024549479671", ENDITEM,
            "Name=SWECmd", "Value=ExecuteLogin", ENDITEM,
            "Name=SWEBID", "Value=-1", ENDITEM,
            "Name=SWEC", "Value=0", ENDITEM,
            LAST);

      web_url("wait.html",
            "URL=http://64.242.155.45/callcenter/wait.html",
            "TargetFrame=", "Resource=0","RecContentType=text/html","Referer=",
            "Snapshot=t6.inf","Mode=HTML",
            LAST);

      web_url("start.swe3",
"URL=http://64.242.155.45/callcenter/start.swe?SWEFrame=top._swe&_sn={Siebel_sn_body3}&SWECmd=GetCachedFrame&SWEC=1",
            "TargetFrame=", "Resource=0",
            "RecContentType=text/html",
            "Referer=http://64.242.155.45/callcenter/start.swe",
            "Mode=HTML",
LAST);
Solutions:

  1. Change the Mode in "start.swe2" to “Mode=HTTP”

The idea behind changing the mode from HTML to HTTP is to avoid parsing the HTML page that is returned by the server, so that resources are not downloaded. This helps to avoid multiple downloads of same request.

If the script still fails on the first iteration, go to step 2.  If the script fails on the second iterations onward, go to step 3.


  1. Disable the Run-Time Viewer

If the script still fails on the first iteration after the change from step 1, try to close the Run-Time Viewer. This option is in VuGen’s Tools ® General Options ® Display tab; clear the “Show Browser during Replay” option.  For more information about this, refer to Problem ID 17234 - Errors in Web replay because of conflict with the runtime browser.

If problem persists, refer to step 4


  1. Correlate SWECount or SWEC

If you are able to run the first iteration, but the script fails on the second iteration or onwards, you will need to correlate SWECount (7.0.3) or SWEC (7.0.4) from the previous step “start.sweXXX.”  For information about correlation, refer to Problem ID 11806 - What is correlation and how is it done.

If problem persists, refer to step 4.


  1. Run the script with the extended log

If none of the above helps, replay the script with the extended log and identify the HTTP request that is being downloaded multiple times. Search for a similar HTTP Request being sent earlier in the execution log. Once you locate the same, set “Mode=HTTP” so that the resources for that request are not downloaded, and try replaying the script again.

DATABASE(SQL) MONITORING IN LOAD RUNNER

Profiling

Profilers access the state of the application and can be notified of interesting events like object allocations and method invocations. Front-end that provides a GUI can be used, like commercial profilers OptimizeIt or JProbe, or the agent can simply dump the profiling information into a file like HPROF Profilers are very good at identifying hot spots that need to be optimized. Profilers help analyze CPU utilization, Memory usage, Thread behavior.
CPU Profiling
Its precise and accurate profiling of CPU consumption allows rapid identification and fixing of performance bottlenecks and inefficient algorithms.  Tools normally provide two CPU profilers to fit different profiling needs.

a)    Sample-based profiler: is a profiler that interrupts all running threads every p period. Once all threads are interrupted, it records what each thread is currently doing and whether each thread is currently using CPU. It then resumes all running threads. p is called a sampling period. This is the profiler of choice when profiling a large GUI application or a server running in production or in a test lab under load.  Sampling has little overhead but is very coarse-grained.

b)    Instrumentation-based profiler: is a profiler that intercepts method invocations. Each time a method is called the profiler records the fact that a method was called and gives the control back to the application. The profiler also intercepts when a method returns from executing and records the amount of time/CPU that was spent in the method. Very good precision: each time a method is invoked, it is recorded. Large overhead: the tested application runs several times slower with an instrumentation profiler.
In addition different profiler software provide varying feature to facilitate the use and analysis of the information gathered.
Monitoring of Object Allocations and Memory Leak Debugging
Spotting memory leaks has never been easy.  Available tools provide a comprehensive object reference graph that not only lists all references kept on each instance, but also automatically highlights references that need to be cleared so that an instance can be garbage collected.  Such advanced debugging capabilities help to dramatically shorten the time spent tracking memory leaks in any program.
Tools have a range of features specifically designed for the precise monitoring of object allocations.  Developers have the capability to monitor object allocations in real-time to detect performance issues such as excessive allocations.  Temporary objects can be closely analyzed with its functionality of garbage collection and temporal mark setting. 
Analyze Threads
Detect and predict thread deadlock, stalls, and data races before they cause business applications to crash. Thread issues have traditionally been difficult to apprehend because of the complexity of multi-threaded programs. Available tools lets developers easily understand thread issues -- such as thread contentions, thread starvation, excessive locking, and deadlocks. The tool gives developers a real-time, high-level view of the changing status of all threads in an application as it runs. Thread issues are spotted immediately, and can be tracked back to the responsible lines of code with a simple mouse click.
Tuning and Optimization
The biggest performance improvement in an application is typically achieved by eliminating badly performing designs and architectures.
After targeting design and architecture, the biggest bang for the buck in terms of improving performance is choosing a better performing software’s like better VM, and then choosing a better compiler.
Having tuned the design and architecture, and having selected improved VMs and compilers, the major bottlenecks remaining are probably due to the application implementation.


Load Runner Interview Questions ans Answers

Load Testing Questions and Answers

1. What is load testing?

Answer: Load testing checks if the application can handle lots of users and tasks at once, like during busy times. It helps to see if the app can handle heavy usage without slowing down or crashing.

2. What is performance testing?

Answer: Performance testing checks how well a computer, network, or software works. It measures things like how fast it responds or how many tasks it can do at once.

3. Did you use LoadRunner? Which version are you using?

Answer: Yes, we are using LoadRunner version LRE 2022.

4. Explain the load testing process.

  1. Know your testing environment.
  2. Set performance goals.
  3. Plan and design tests.
  4. Configure the test environment.
  5. Implement test design.
  6. Run the tests.
  7. Analyze and retest.

5. When do you do load and performance testing?

Answer: Load testing is done after QA testing. It's important for checking how the system performs under heavy use, unlike single-user testing which focuses on individual features.

6. What are the components of LoadRunner?

Answer: The components are Virtual User Generator, Controller, Agent process, LoadRunner Analysis and Monitoring, and LoadRunner Books Online.

7. What component of LoadRunner would you use to record a script?

Answer: You use the Virtual User Generator (VuGen) to record a script.

8. What component of LoadRunner would you use to play back the script in multi-user mode?

Answer: The Controller component is used to play back the script in multi-user mode during a scenario run.

9. What is a rendezvous point?

Answer: Rendezvous points make Vusers wait during testing so they can perform tasks at the same time, mimicking heavy user load on the server.

10. What is a scenario?

Answer: A scenario defines the events during testing, like how many users to simulate and what actions they'll take.

11. Explain the recording mode for a web Vuser script.

Answer: VuGen records user actions on a client application, monitoring communication with the server and creating function calls in a Vuser script.

12. Why do you create parameters?

Answer: Parameters vary input to the server, simulating real users. They help simulate different user behaviors.

13. What is correlation? Explain the difference between automatic correlation and manual correlation.

Answer: Correlation avoids errors from duplicate data. Automatic correlation sets rules to replace values, while manual correlation scans and replaces specific values.

14. How do you find out where correlation is required?

Answer: You can scan for correlations or compare scripts to find differences in values that need correlating.

15. Where do you set automatic correlation options?

Answer: In LoadRunner, you can set automatic correlation options in recording settings or by scanning for correlations.

16. What is a function to capture dynamic values in the web Vuser script?

Answer: The Web_reg_save_param function captures dynamic data in a web Vuser script.

17. When do you disable logging in Virtual User Generator, and when do you choose standard and extended logs?

Answer: Logging is disabled once the script is functional. Standard logs are used for debugging, and extended logs provide more detailed information.

18. How do you debug a LoadRunner script?

Answer: You can debug using "Run Step by Step" or breakpoints in VuGen. Debug information is written to the output window.

19. How do you write user-defined functions in LR? Give a few functions you wrote in your previous projects.

Answer: You create an external library and assign user-defined functions as parameters. Examples include GetVersion and GetCurrentTime.

20. What are the changes you can make in run-time settings?

Answer: You can change pacing, logging, think time, and general settings like Vuser processes.

21.Where do you set Iteration for Vuser testing?

Answer: Iterations are set in the Run Time Settings of VuGen, under the Pacing tab.

22.How do you perform functional testing under load?

Answer: By running multiple Vusers concurrently, you can test functionality under load and see how well the server handles it.

23.What is Ramp up?

How do you set this?

Answer: Ramp up gradually increases Vusers/load on the server. You can set it in the Scenario Scheduling Options.

24.What is the advantage of running the Vuser as a thread?

Answer: Running Vusers as threads allows more Vusers per generator, saving memory and enabling more concurrent users.

25.If you want to stop the execution of your script on error, how do you do that?

Answer: Use the lr_abort function to stop script execution on error, and uncheck "Continue on error" in Run -Time Settings.

26.What is the relationship between Response Time and Throughput?

Answer: Throughput indicates data received per second, and as it scales with Vusers, response time may increase if the server's bandwidth is insufficient.

27.Explain the configuration of your systems.

Answer: System configuration includes hardware, software, and settings. It should match the overall system configuration for accurate load testing.

28.How do you identify performance bottlenecks?

Answer: Performance monitors help find bottlenecks by measuring response time, throughput, and network delays.

29.If the web server, database, and Network are all fine, where could the problem be?

Answer: The problem could be in the system itself, application server, or code.

30.How did you find web server-related issues?

Answer: Web resource monitors analyze web server performance, measuring throughput, and HTTP responses.

31.How did you find database-related issues?

Answer: By running database monitors and analyzing data resource graphs, you can find database performance issues.

32.Explain all the web recording options.

Answer: Web recording options in LoadRunner capture user actions, HTTP/HTTPS data, and web-based interactions.

33.What is the difference between Overlay graph and Correlate graph?

Answer: Overlay graph combines two graphs with a shared x-axis, while Correlate graph plots one graph's y-axis against another's x-axis.

34.How did you plan the Load?

What are the Criteria?

Answer: Load test planning is based on Task Distribution Diagram and Transaction Profile to determine user numbers and transaction priorities.

35.What does vuser_init action contain?

Answer: The vuser_init action includes procedures for logging into a server.

36.What does vuser_end action contain?

Answer: The vuser_end section contains log-off procedures.

37.What is think time?

How do you change the threshold?

Answer: Think time is user wait time between actions. You can change the threshold in VuGen's Recording options.

38.What is the difference between standard log and extended log?

Answer: Standard log records basic script functions, while extended log includes more detailed debugging information.

39.Explain the following functions:

Answer: - `lr_debug_message`: Sends a debug message to the output log. - `lr_output_message`: Sends notifications to the Controller Output window and Vuser log file. - `lr_error_message`: Sends an error message to the LoadRunner Output window. - `lrd_stmt`: Associates a string with a cursor for SQL statements. - `lrd_fetch`: Fetches the next row from a result set.

40.Throughput - If the throughput scales upward as time progresses and the number of Vusers increase, this indicates that the bandwidth is sufficient.

Answer: If throughput increases with Vusers, it means bandwidth is enough.

41.Types of Goals in Goal-Oriented Scenario

Answer: LoadRunner provides goals like concurrent Vusers, hits per second, transactions per second, pages per minute, and desired response time.

42.Analysis Scenario (Bottlenecks)

Answer: Bottlenecks can be seen when response time sharply increases with more Vusers, indicating a server overload.

43.What is correlation?

Explain the difference between automatic correlation and manual correlation?

Answer: Correlation replaces unique data in scripts. Automatic correlation uses rules, while manual correlation scans and replaces values.

44.Where do you set automatic correlation options?

Answer: Automatic correlation settings are in LoadRunner's recording options and correlation tab.

45.What is a function to capture dynamic values in the web Vuser script?

Answer: The function is `Web_reg_save_param()` which captures dynamic data in a web Vuser script.

46. What is the purpose of pacing in load testing?

Answer: Pacing in load testing controls the speed at which Vusers or transactions are executed. It helps simulate real-world scenarios where users don't perform actions instantly.

47.How do you determine the appropriate load levels for testing?

Answer: The appropriate load levels are determined based on the expected usage patterns and peak times of the application. It involves analyzing historical data, user behavior, and business requirements.

48.What is the difference between stress testing and load testing?

Answer: Stress testing evaluates how the system performs under extreme conditions beyond its normal capacity, while load testing assesses the system's behavior under typical and peak loads.

49.Explain the concept of parameterization in load testing.

Answer: Parameterization allows testers to vary input data during each test iteration, making scripts more realistic. It involves replacing hard-coded values with parameters that can be randomized or derived from external sources.

50.How do you analyze test results in LoadRunner?

Answer: Test results in LoadRunner can be analyzed using various graphs and reports generated during test execution. Key performance indicators such as response time, throughput, and error rates are examined to identify performance bottlenecks and areas for improvement.

C PROGRAMS and functions in LOAD RUNNER

/********************************************************************/
/* Function Name: cg_random
/* Purpose      : Generate random alphabets/numbers/symbols
/* Input        : No.of letters, Capital or small(0 -for capital letters, 1 -for small letters, 
/*                2 - mixed case, 3 -numbers, 4 -symbols)
/* Output       : Random alphabets/numbers/symbols (param_name)
/* Created by   : G.Raviteja
/******************************************************************/

cg_random(char* param_name,int length,int alpha_num)
{
char buff[42] = "";
int i,r;
char c;
srand((unsigned int) time(0)); //Before invoking rand, call srand to seed the pseudo-random number generator 

if(alpha_num == 0)
{
for(i=0;i<length;i++)
{
r=rand() % 25 + 65; // A-Z = 65-90 = rand() % 25 + 65 [for values within specific range using the mod (%) operator]
c= (char) r;
buff[i]=c;
printf("%c",c);
}
}

else if(alpha_num == 1)
{
for(i=0;i<length;i++)
{
r=rand() % 25 + 97; // a-z = 97-122 = rand() % 25 + 97 [for values within specific range using the mod (%) operator]
c= (char) r;
buff[i]=c;
printf("%c",c);
}

}

else if(alpha_num == 2)
{
for(i=0;i<length;i++)
{
r=rand() % 57 + 65; // a-z = 65-122 = rand() % 57 + 65 [for values within specific range using the mod (%) operator]
if(r>90 && r<97)
{
                r=r+10;
c= (char) r;
               
}

else
{
c= (char) r;

}

buff[i]=c;
printf("%c",c);
        }

}

else if(alpha_num == 3)
{
for(i=0;i<length;i++)
{
r=rand() % 9 + 48; // 0-9 = 48-57 = rand() % 9 + 48 [for values within specific range using the mod (%) operator]
c= (char) r;
buff[i]=c;
printf("%c",c);
}

}

else if(alpha_num == 4)
{
for(i=0;i<length;i++)
{
r=rand() % 14 + 33; // !-/ = 33-47 = rand() % 14 + 33 [for values within specific range using the mod (%) operator]
c= (char) r;
buff[i]=c;
printf("%c",c);
}

}

else 
{
        lr_output_message("==>Enter value between 0-4 for argument 3<==");
}


lr_save_string(buff,param_name);

return 0;
}

/********************************************************************/
/* Function Name: cg_file_write
/* Purpose      : File write
/* Input        : Buffer and file name
/* Output       : Data written to file
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

int cg_file_write(char* buffer,char* filename)
{
int fp;
    
fp = fopen (filename,"w");
if(fp == NULL)
{
lr_error_message("ERROR: Unable to open file");
}

fprintf(fp,"%s",buffer);
fclose(fp);

}
/********************************************************************/
/* Function Name: cg_file_read
/* Purpose      : File read
/* Input        : file name
/* Output       : Reads content from file
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

int cg_file_read(char* filename)
{
int fp;

char data[1000];
char* buff;

int i=1;
int total, count =0;

//char* filename = "test1.txt";

fp = fopen(filename,"r");

if(fp == NULL)
{
lr_error_message("Cannot open %s", filename); 
return -1;
}

else
{
while(! feof(fp))
{
// Read 1000 bytes while maintaining a running count 

              //count = fread(data, sizeof(char), 1000, fp); 

 count = fgets(data, 1000, fp);

              if (ferror(fp)) { 

                     lr_output_message ("Error reading file %s", filename); 

                     break;

 }

 lr_output_message( "The line %d is ==> \"%s\"",i, data);

 i++;

              /*// Get the first line from the file 

if (fgets(data, 100, fp) == NULL) 

            lr_output_message("fgets error"); 

            else 

            lr_output_message( "The line %d is ==> \"%s\"",i, data); 

i++;*/

}
}

    fclose(fp);

   if (ferror(fp)) 
{
lr_error_message("Error closing file %s", filename); 
}

}


/********************************************************************/
/* Function Name: cg_PlainToURL
/* Purpose      : converts a plain text string into URL format string
/* Input        : StrIn - Input String, 
/* Output       : URL format string (StrOut - Output buffer)
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_PlainToURL(char* strIn, char* strOut)
{
int i;
char curChar;
char curStr[4] = {0};

strOut[0] = '\0';

for (i=0;curChar=strIn[i];i++)
{
if(isdigit(curChar) || isalpha(curChar)) // Verify whether the character is digit or alphabet
{
sprintf(curStr,"%c",curChar); // If yes, then print as such
}

else
{
sprintf(curStr,"%%%X",curChar); // else convert it into hex string
}

strcat(strOut,curStr); // Concatenate the output

}

return strOut;
}

/********************************************************************/
/* Function Name: cg_PlainToURL_lr
/* Purpose      : converts a plain text string into URL format string
/* Input        : sIn - String which needs to be converted to URL format
/* Output       : URL formatted string
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/
cg_PlainToURL_lr(char* sIn)
{
//char sIn[] = "t es%d$ + eprst_";

lr_save_string(sIn, "InputParam");

web_convert_param("InputParam", 
 "SourceEncoding=PLAIN",
 "TargetEncoding=URL", 
 LAST);

lr_output_message("%s", lr_eval_string("{InputParam}"));
}



/********************************************************************/
/* Function Name: cg_HTMLToPlain_lr
/* Purpose      : converts a URL format string into plain text string
/* Input        : sIn1 - HTML string which needs to be converted to Plain format
/* Output       : Plain formatted string
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/
cg_HTMLToPlain_lr(char* sIn1)
{
//char sIn1[] = "v%20mg%25d%24%20%2B%20vmguruprasath%5F";

lr_save_string(sIn1, "InputParam");

web_convert_param("InputParam", 
 "SourceEncoding=HTML",
 "TargetEncoding=PLAIN",
 LAST);

lr_output_message("%s", lr_eval_string("{InputParam}"));

}

/********************************************************************/
/* Function Name: cg_LTrim
/* Purpose      : Trims spaces on the left of the string
/* Input        : source string and the string to be trimmed
/* Output       : left trimmed string
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_ltrim(char *string, char junk)
{    
char* original = string;
char *p = original;
int trimmed = 0;
do 
{       
 if (*original != junk || trimmed) 
 {           
    trimmed = 1; 
*p++ = *original;
 } 
   }

   while (*original++ != '\0');

return string;
}

/********************************************************************/
/* Function Name: cg_rtrim
/* Purpose      : Trims spaces on the right of the string
/* Input        : source string and the string to be trimmed
/* Output       : right trimmed string
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_rtrim(char* string, char junk)
{    
char* original = string + strlen(string);
while(*--original == junk);
*(original + 1) = '\0';
return string;
}

/********************************************************************/
/* Function Name: cg_find_replace
/* Purpose      : Finds a string/character from the source and replaces with
/*                the specified replace string/character. 
/* Input        : source string, search string, replace string
/* Output       : 
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_replace(const char* src,const char* search,const char* replace)
{
    /* We need to find the length of the source string, seach and replace string*/

size_t size       = strlen(src) + 1;
size_t searchlen  = strlen(search);
size_t replacelen = strlen(replace);

/* Allocate memory to values */

char* value = (char*)malloc(size);

    /* defining return value */

char* ret = value;

ret = value;

/* Verify Malloc */

if (value != NULL)
    {
/* loop untill no match is found */
for(;;)
{
/* Find the search string */

const char* match = (char*)strstr(src,search);

if(match != NULL)
{
/* Found search text at location match,
* Find how many characters to copy in match */

size_t count = match - src;

/* Re-allocate memory, use a temp variable for pointer */

char* temp;

/* Calculating the total length of the string after allocation */

size += replacelen - searchlen;

/* realloc memory*/

temp = (char*)realloc(value,size);

if(temp == NULL)
{
/* Re allocation of memory failed so free the malloc'd memory*/

free(value);

return NULL;
}

/* Re-allocation successful. Now point the pointer to value */

ret = temp + (ret - value);

value = temp;

/* copy from the source to where we matched.
* Then move the source pointer to this point and move the 
* destination pointer ahead by same amount */

memmove(ret,src,count);

src += count;
ret += count;

/* Now copy the replacement text 'replace' at the position of match.
* Adjust the source pointer by the text we replaced 
* Adjust the destination pointer with the amount of replacement */

memmove(ret,replace,replacelen);

src += searchlen;
ret += replacelen;

}

else /* No Match found */
{
/* Copy the remaining part of the string */

strcpy(ret,src);

break;
}


}
}

return value;
}

void cg_find_replace(const char* source,const char* str,const char* repl)
{
char* after;

after = cg_replace(source,str,repl);

lr_output_message("The find string is: '%s' and replace string is '%s'",str,repl);

if(after != NULL)
{
lr_output_message("The string after replacement::> %s",after);
free(after);
}
}

/********************************************************************/
/* Function Name: cg_substr_index
/* Purpose      : Extracts a string between the start index and end index. 
/* Input        : Source string, Stat index and end index
/* Output       : Extracted sting between the start and end index
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_substr_index(char* source,int begin, int end)
{
int length = end-begin;

char* newstring;
char* tmpstring;

int i;

if(length<0)
{
return("-1");

}

newstring = (char*)malloc(length+1);

memset(newstring,'\0',length+1);

tmpstring = (char*)strdup(source);

for(i=1;i<begin;i++)
{
tmpstring++;
}

strncpy(newstring,tmpstring,length);

lr_output_message("Substring is ::>%s",newstring);

return newstring;

}


/********************************************************************/
/* Function Name: cg_substr_lb_index
/* Purpose      : Extracts a string between the start index and end of string. 
/* Input        : Source string and start index
/* Output       : Extracted string from start index to last.
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_substr_lb_index(char* src,int startIndex)
{
    char* buffer;
char* temp;

int cnt;

int length = strlen(src);

if(length<0)
{
return("-1");

}

buffer = (char*)malloc(length+1);

memset(buffer,'\0',length+1);

temp = (char*)strdup(src);

for(cnt=1;cnt<startIndex;cnt++)
{
temp++;
}

strncpy(buffer,temp,length);

lr_output_message("Substring from left boundary is ::>%s",buffer);

return buffer;

}

/********************************************************************/
/* Function Name: cg_substr
/* Purpose      : Extract a string between left boundary and right boundary. 
/* Input        : 
/* Output       : 
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_substr(char* source,char* lbound, char* rbound)
{

char* lposition;
char* rposition;
int begin,end;

    

int length;

char* newstring;
char* tmpstring;

    char* tmp;

int i;

int lblength = strlen(lbound);

lposition = (char *)strstr(source, lbound); 

    // strstr has returned the address. Now calculate * the offset from the beginning of str 

    begin = (int)(lposition - source + 1); 

lr_output_message ("The lbound \"%s\" was found at position %d", lbound, begin);

begin = begin + lblength;

rposition = (char *)strstr(source, rbound); 
    // strstr has returned the address. Now calculate * the offset from the beginning of str 
    end = (int)(rposition - source + 1); 

     
    lr_output_message ("The rbound \"%s\" was found at position %d", rbound, end); 

length= end-begin;

if(length<0)
{
        tmp = (char*)malloc(length + 1);

tmp = (char*)strdup(source);

for(i=1;i<begin;i++)
{
tmp++;
}

rposition = (char *)strstr(tmp, rbound);

end = (int)(rposition - tmp + 1);

lr_output_message ("The new rbound \"%s\" was found at position %d", rbound, end);

        length= end - 1;

if(length<0)
{
lr_output_message("ERROR: Right boundary value is found before left boundary value");

return("-1");
}

        
}

    
newstring = (char*)malloc(length+1);

memset(newstring,'\0',length+1);

tmpstring = (char*)strdup(source);

for(i=1;i<begin;i++)
{
tmpstring++;
}

strncpy(newstring,tmpstring,length);

lr_output_message("Substring is ::>%s",newstring);

        return newstring;
        
}

/********************************************************************/
/* Function Name: cg_substr_lb
/* Purpose      : Extract a string between left boundary and end of string. 
/* Input        : 
/* Output       : 
/* Created by   : G.Raviteja
/*www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_substr_lb(char* src,char* lbound)
{

char* lpos;
    char* newstring;
char* tmpstring;

int start,end,length,i;

    int lblength = strlen(lbound);

lpos = (char *)strstr(src, lbound); 

    // strstr has returned the address. Now calculate * the offset from the beginning of str 

    start = (int)(lpos - src + 1); 

lr_output_message ("The lbound \"%s\" was found at position %d", lbound, start);

start = start + lblength;

    length= strlen(src);

if(length<0)
{
lr_output_message("-->Enter string with some characters<--");

        return("-1");
        
}

    
newstring = (char*)malloc(length+1);

memset(newstring,'\0',length+1);

tmpstring = (char*)strdup(src);

for(i=1;i<start;i++)
{
tmpstring++;
}

strncpy(newstring,tmpstring,length);

lr_output_message("Substring is ::>%s",newstring);

        return newstring;

        
}

/********************************************************************/
/* Function Name: cg_substr_lb_cnt
/* Purpose      : Extract a string between left boundary and end of string
/*                for the given occurence.. 
/* Input        : 
/* Output       : 
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/******************************************************************/

char* cg_substr_lb_cnt(char* src,char* lbound, int cnt)
{

char* lpos;
    char* newstring;
char* tmpstring;

int start,end,length,i,j;

    int lblength = strlen(lbound);

lpos = (char *)strstr(src, lbound); 

    // strstr has returned the address. Now calculate * the offset from the beginning of str 

    start = (int)(lpos - src + 1); 

if(start<0)
{

lr_output_message("-->ERROR:The left boundary value'%s' - Not found in source <--",lbound);

return("-1");

    }

//lr_output_message ("The lbound \"%s\" was found at position %d", lbound, start);

start = start + lblength; // calculate the start position

    length= strlen(src);

if(length<0)
{
lr_output_message("-->ERROR:Enter string with some characters<--");

        return("-1");
        
}

    
newstring = (char*)malloc(length+1);

memset(newstring,'\0',length+1);

tmpstring = (char*)strdup(src);

/* Msg: move pointer for the number of occcurence */

for (j=0;j<cnt;j++) 
{
for(i=1;i<start;i++)
{
tmpstring++;
}

strncpy(newstring,tmpstring,length);

lpos = (char *)strstr(newstring, lbound); 

start = (int)(lpos - newstring + 1); 

if(start<0)
{

                lr_output_message("-->Last occurence of '%s' found for occurance count %d ;the occurence value entered is %d<--",lbound,j+1,cnt);

break;
        }

else
{
lr_output_message ("The lbound \"%s\" was found at position %d", lbound, start);

/* Calculate new start position */

start = start + lblength;

length= strlen(newstring);

if(length<0)
{
lr_output_message("-->ERROR:Enter string with some characters<--");

return("-1");
        
}
}


}

lr_output_message("Substring with occurence count %d is ::>%s",j+1,newstring);

        return newstring;

        
}

/***************************************************************************/
/* Function Name: cg_substr_cnt
/* Purpose      : Extract a string between left boundary and right boundary. 
/*                for the given occurrence
/* Input        : 
/* Output       : 
/* Created by   : G.Raviteja
/* www.easyloadrunner.blogspot.in
/************************************************************************/

char* cg_substr_cnt(char* source,char* lbound, char* rbound, int cnt)
{

char* lposition;
    char* rposition;
int begin,end,i,j,length;

    char* newstring;
char* tmpstring;

char* newstring1;
char* tmp;
char* temp;

    int lblength = strlen(lbound);

lposition = (char *)strstr(source, lbound); 

    // strstr has returned the address. Now calculate * the offset from the beginning of str 

    begin = (int)(lposition - source + 1); 

length= strlen(source);

if(length<0)
{
lr_output_message("Enter string with some characters");
}

newstring = (char*)malloc(length+1);

memset(newstring,'\0',length+1);

strncpy(newstring,source,length);


/* Verifying count values */

if(cnt == 0)
{
lr_output_message("Enter occurrence value as 1 or >1");

return("-1");
}

/* Moving begin index for the number of occurence */

if(cnt>1)
{
        temp = (char*)malloc(length+1);
temp = (char*)strdup(source);

for(j=0;j<cnt;j++)
{
for(i=1;i<begin;i++)
{
temp++;
}

lposition = (char *)strstr(temp, lbound);

begin = (int)(lposition - temp + 1);

begin = begin + lblength;

length= strlen(newstring);

            strncpy(newstring,temp,length);

//lr_output_message("The newstring value is :%s",newstring);

        }

/* Noting down the new begin position */

lposition = (char *)strstr(newstring, lbound);

begin = (int)(lposition - newstring + 1); 

if(begin<0)
{
lr_output_message("The argument occurence count exceeds the left boundary occurrence count");

return("-1");


}

    }

        newstring1 = (char*)malloc(length+1);

memset(newstring1,'\0',length+1);

tmpstring = (char*)strdup(newstring);

begin = begin + lblength;

/* Extracting string from the new begin value */

for(i=1;i<begin;i++)
{
tmpstring++;
}

/* Finding right boundary in the new string */

rposition = (char *)strstr(tmpstring, rbound);

end = (int)(rposition - tmpstring + 1);

/* Calculating length upto the begining of right boundary*/

length = end - 1;

if(length < 0)
{
lr_output_message("last occurrence of left boundary reached");

length = strlen(newstring);


}

/* Copying the extracted string to newstring 1*/
        
        strncpy(newstring1,tmpstring,length);

lr_output_message("Substring is ::>%s",newstring1);

        return newstring1;
}