I think that many readers are actively using LoadRunner. So, I’ve got a question: where do you take the test data from? The first option is to parametrize everything and save the dataset in .dat-files. It’s a good solution, but what if there are many scripts with common parameters in the use case? The second option is to use a database. It’s already better because the common parameters can be shared, but the configuration for some databases can be a nightmare for a newbie. I’ve got one more option that is both simple and effective.
Our topic will be a LoadRunner component – Virtual Table Server (VTS). To begin with, let’s sort out what it is and what to do with it. Its last versions have a js-node server on the backend, and its architecture reminds us of a database. But it just seems so at first glance. I’d rather compare VTS with a simple table because we can access practically any cell, row, or column using the column name or the row number. We can read, delete, and add data and empty the table – all of it without leaving LR. The details can be found below. First let’s discuss, where to find it and how to install it.
Installation
The habitation area is the folder \Additional Components\Virtual Table Server or OpenText site (registration is required to download the files). There shouldn’t be any difficulties during the installation. First, the temp folder should be selected, and then the main installer will run. During the installation, there will be an option to change the program folder, as well as an option to choose a server management port. It’s recommended to keep the default value of 4000 (of course, if the port is not already in use). For those who are lazy or value their time, there is an opportunity to automatically start the VTS. We activate the check-box, and after the installation, the browser with the application web interface will open.
Don’t forget to switch on the script connection to the server through “Access from Script” on the top right menu.
Data input
We’ve got several options: send the data from the database, import it from a CSV file, or use a script and do everything manually in the browser. I think the optimal version is importing data from a CSV file or using a script. I’m going to explain these two approaches. If you are interested in importing the database, take a look here.
CSV import
To begin with, we’ve got a CSV, so a regular text file with comma separators is enough. The first option is to use Import ->Import from CSV file in the web interface. Then we must choose the file, whisper the incantation, and olè; your data has already been pasted into the table. The second option is to use a script to do the job for you. You’ll need the file \VTS\web\vtscmd.js.
It works like this:
node vtscmd /import samples/Customers.csv /port 8888
The script can also carry out other useful tasks, such as emptying a table:
node vtscmd /delete_data /port 8888
Or create another one:
node vtscmd /start /port 2000 /name table_one
The full command list:
/help or /?
Help/start
Start a new table (requires /port and /name)/stop
Delete a table (requires /port and /name)/stop_all
Delete all tables/import
Load data from a CSV file (requires /port)/delete_data
Empty a table (requires /port)/list
Display the list of existing tablesand parameters:
/port
Table port/name
Table name. If the table name is not shown, then the main table is used/delimiter
Data separator in the CSV file. It is used in the /import command/domain
Domain for the NTML authorization/username
Username for the NTML authorization/password
Password for the NTML authorization/cert
It refers to the client certificate for authorization/key
It refers to the client key for authenticationThe only problem is that it doesn’t work with a remote host. For this purpose, we have to write scripts of our own. We are using a java-utility on the project that empties a table and imports a CSV. The data is sent via a POST query. Here are several examples of adding data to a cell:
curl –data ‘key=&value=&id=&oper=edit’
http://server:port/data/edit_cell
Emptying a table:
curl http://server:port/data/delete_all
Finally, here’s the most precious – CSV import. The file path can be full or relative, but the @ sign is necessary. Command run example from the folder with the file:
curl -F fileToUpload=@data.csv -H Accept:text/html,application/xhtml+xml,application/xml http://server:port/data/import_csv/
These requests are not working with the main table that is created by default. One more table on a separate port needs to be created and worked with.
Generally, if one expects tables to contain columns of different sizes, I recommend creating several tables in such a way that the data is comparable by size. For example, we create the first table with parameters with one value, the second table with parameters for 10 values, and so on. Of course, all of this should be used without exaggeration. A bit later, I will show the LR functions. They are very useful for receiving the whole parameter set, so it’s worth thinking about data management. The queries can be turned into a full-fledged application and used from the Jenkins script.
LoadRunner Script
Another option to add data is a VUGen script. For this purpose, a simple script is enough. To begin with, let’s prepare the data: it needs to be saved in VTS as regular parameters. Then, we write in the script the following:
char *VtsServer = “myVTSserver”;
int nPort = 8888;
int rc;
rc = lrvtc_connect(VtsServer,nPort,VTOPT_KEEP_ALIVE);
lr_log_message(“Connect result rc=%d\n”, rc);
rc = lrvtc_send_row1(“C_ID;C_info;C_credit”,
“{p_cid};{p_cid}_info;0”, “;”, VTSEND_SAME_ROW);
lr_log_message(“Send result rc=%d\n”, rc);
I recommend checking the data and/or the return value to prevent invalidated data or script failures. It’s especially important during the data reception – I sometimes receive an empty line instead of the required value.
int rc;
int colSize;
…
colSize = lrvtc_column_size(“O_ID”);
rc = lrvtc_query_row(colSize);
if (strcmp(lr_eval_string(“{O_ID}”),””)) {
lr_exit(LR_EXIT_VUSER, LR_FAIL);
}
lr_log_message(“query_row rc=%d\n”, rc);
lr_log_message(“%s, %s, %s, %s”,
lr_eval_string(“{O_ID}”),
lr_eval_string(“{O_customerID}”),
lr_eval_string(“{O_info}”),
lr_eval_string(“{O_status}”));
Finally, don’t forget to close the connection after finishing working with the table:
rc = lrvtc_disconnect();
lr_log_message(“Disconnect result rc=%d\n”, rc);
Data communication
I will explain several functions I’m using in my work: lrvtc_query_row ( int index ), which retrieves all parameters in the table’s index row. Each column corresponds to a parameter with the same name saved as a string. If no data exists in some cell, then NULL is written to the parameter.
lrvtc_query_column ( char *columnName, int rowIndex )
– it is the same function as the previous one, but it is applied to one column.lrvtc_retrieve_row ( )
– It is analogous to the first function, but it saves all raw data to the corresponding parameters. At the same time, all the rows are deleted from the table. All lower rows are lifted by a row.lrvtc_retrieve_message ( char *columnName )
– it receives the first-row value from the given column and deletes it from the table. All lower rows are lifted by a row.lrvtc_retrieve_messages1 ( char *columnNames, char *delimiter )
– it is the same function, but it is applied to several columns. The delimiter is a line or symbol that divides column names in the column names line.lrvtc_rotate_row ( sendflag )
– It retrieves values from a row, deletes them from the first row, and saves them in the last row. Here are the possible fag values: VTSEND_SAME_ROW – save the data to the same row. VTSEND_STACKED – save the data to a free cell on the table bottom. VTSEND_STACKED_UNIQUE – the data is only saved back to the table if it is unique; otherwise, it is only saved in the parameters.lrvtc_rotate_message ( columnName, sendflag )
– it is analog to the previous functions, receives the data from a required column, and reverts the column in the table. Flags: VTSEND_STACKED и VTSEND_STACKED_UNIQUE.lrvtc_rotate_messages1 ( char *columnNames, char *delimiter, char *sendflag )
– It functions analogously to the previous functions. Flags as in lrvtc_rotate_row.lrvtc_update_row1 ( char *columnNames, int rowIndex , char *values, char *delimiter )
– update the data in the indicated columns and lines.lrvtc_update_message ( char *columnName, int rowIndex , char *value )
– update the data in one cell with a required address.lrvtc_update_message_ifequals ( char *columnName, int rowIndex , char *value, char *ifEqualValue )
– change the value at the indicated address if it equals ifEqualValue.lrvtc_send_row1 ( char *columnNames, char *values, char *delimiter, unsigned char sendflag )
– save the data in the table under the indicated columns. A delimiter can be a line or a symbol. Flags as in lrvtc_rotate_row.lrvtc_send_message ( char *columnName, char *value )
– save the value at the end of the given column.lrvtc_send_if_unique ( char *columnName, char *value ) - save the data at the end of the given columns if it is unique.
It’s recommended to use indexes to optimize and speed up the search for unique values in tables with many lines.
lrvtc_ensure_index ( char *columnName )
– creates an index in the given column. Locks the column during index creation so that all operations on the given column are queued until the function finishes.lrvtc_drop_index ( char *columnName )
– deletes a created index.lrvtc_clear_row ( int rowIndex )
– the values in the given row will equal to an empty line. The row amount in the table stays the same.lrvtc_clear_column ( char *column_name )
– empty a column.lrvtc_clear_message ( char *columnName, int rowIndex )
– empty a cell. The cell is not deleted, but its value is set to an empty line. The row amount in the table stays the same.Known problems
On the one hand, the ease of configuration and communication with LR is a big plus. On the other hand, I don’t quite like a couple of things. First, spaces appear in the table in some cases. We’ve observed that while using the rotate_xxx function. It seems that the server has problems with processing concurrent queries from virtual users. Another issue is that there is no satisfactory API for initial data input and data deletion from the tables. For those looking to improve the performance of their API architectures, utilizing a specialized tool like a gRPC load testing tool can ensure scalable and high-performing services. I hope such functionalities will be enhanced in future versions, but for now, we have to invent our bicycles.
I recommend the described approach to everyone who still keeps many of the same parameters in different scripts. Just don’t forget to check the values you received.
Related insights in blog articles
SRE Roles and Responsibilities: Key Insights Every Engineer Should Know
Site Reliability Engineers (SREs) are crucial for maintaining the reliability and efficiency of software systems. They work at the intersection of development and operations to solve performance issues and ensure system scalability. This article will detail the SRE roles and responsibilities, offering vital insights into their duties and required skills. Key Takeaways Understanding Site Reliability […]
Understanding Error Budgets: What Is Error Budget and How to Use It
An error budget defines the allowable downtime or errors for a system within a specific period, balancing innovation and reliability. In this article, you’ll learn what is error budget, how it’s calculated, and why it’s essential for maintaining system performance and user satisfaction. Key Takeaways Understanding Error Budgets: What Is Error Budget and How to […]
Mastering Reliability: The 4 Golden Signals SRE Metrics
Introduction to Site Reliability Engineering Site Reliability Engineering is a modern IT approach designed to ensure that software systems are both highly reliable and scalable. By leveraging data and automation, SRE helps manage the complexity of distributed systems and accelerates software delivery. A key aspect of SRE is monitoring, which provides real-time insights into both […]
Reliability vs Availability: Key Differences
Defining Reliability and Availability What is Reliability? Reliability refers to the probability that a system will consistently perform as expected, delivering correct output over a set period of time. In the world of Site Reliability Engineering (SRE), reliability is a core metric that drives everything we do. It’s not just about whether a service works […]
Be the first one to know
We’ll send you a monthly e-mail with all the useful insights that we will have found and analyzed
People love to read
Explore the most popular articles we’ve written so far
- Benefits of Performance Testing for Businesses Sep 4, 2024
- Android vs iOS App Performance Testing: What’s the Difference? Dec 9, 2022
- How to Save Money on Performance Testing? Dec 5, 2022
- Cloud-based Application Testing: Features & Types Apr 15, 2020