Before Implementation > Design |
After you receive the SDK, you should study the SDK documentation and start design.
The design should include the following:
Required functionality of the protocol. The services of the application that must be exercised, the scenarios that must be run to make the load test realistic, and so on.
Methodology for communicating with the application. Use a subset of an existing client application or create the requests in the protocol code to generate requests and handle responses.
Requirements derived from the expected client-side environment. On what computer configurations and operating systems will the load generators run.
Usage. Usage characteristics and use cases of the protocol.
Feasibility. How complex does the protocol have to be? Are all the knowledge and skills available? Perhaps only some of the required functionality can be implemented economically. If so, what will be the limitations of the protocol?
Error handling. Protocol error handling and retries.
Asynchronous processes requirements.
The list of script APIs. What does each test step do? What arguments are required?
One goal of protocol design is to find the best balance between two requirements, which are often contradictory: scalability of the protocol and usability of the script.
The first requirement is that the protocol be scalable. The test run should have a small enough resource usage to enable running enough Vusers to perform load testing. This means loading as few client application DLLs as possible. These are generally the DLLs at the lowest level, close to the communication level. A protocol can also be designed to generate the communication with the server directly, without loading client application DLLs.
The second requirement is script usability. The script must be understandable to the testing personnel. The testing team must be able to modify the script if necessary. It must be possible to understand from the script what kind of response is expected. For these reasons, the script should relate to recognizable business processes and activities.
For example, the following script is not usable:
sendBuffer(outData); rcvBuffer(inData); sendBuffer(outData); rcvBuffer(inData); ... sendBuffer(outData); rcvBuffer(inData);
A usable script might look as follows:
rc = logon(usrname, psword, server, domain); if (rc) lr_exit(LR_EXIT_VUSER, LR_FAIL); fileList = remote_dir(serverPath); if (fileList != NULL) { rc = download(clientPath, serverPath, fileList[0]); }
The contradiction between scalability and usability lies in the design of most client applications. The UI level generally responds to user actions with calls to functions at a high logical level, which in turn call lower level support functions, and so on down to the communication layer. A script that exercises the UI level is immediately understandable, but at test run time may require loading almost the entire client application.
A script that directly addresses the communication layer will have a very small resource footprint, but may be incomprehensible to the testers. A protocol that works at a very low level may also have to deal with difficult issues of encryption, authentication, and general data manipulation that are well handled by the client application.
The task is to abstract high level script functions from the lowest possible level in the application. The larger the logical gap between the client application functions to be called and the script functions, the more processing is required from the protocol, and so the more difficult the programming task.
The designer must identify the lowest level at which there are well-known client calls. From this level, a usable script can be derived at an acceptable level of programming effort.
If your protocol has limited scalability, this must be documented.
LoadRunner deals with text according to the user's locale. If the application requires input or returns responses not compatible with the locale, or if there is a business requirement for error messages or logging that requires conversions to or from the locale, the protocol must handle them.
The SDK provides utilities to help with these conversions. See ConvertFromLocale
and ConvertToLocale
in the HP LoadRunner Function Reference.
Many protocols are expected to be used together with other protocols. Your protocol should not duplicate functionality already available in related protocols. The test step names should be consistent among the protocols, but not so similar as to be confusing. Argument names should be identical when the concept is identical, and must not be the same when the concept is different.
For example, the Flash Remoting (AMF) protocol is generally used with the Web or Web Services protocol. The AMF protocol does not duplicate functionality to deal with proxy servers, correlation, or authentication, all of which are implemented in the Web protocol.
Configure VuGen so that your protocol cannot be implemented as a multi-script with an incompatible protocol.
Your protocol must not overwrite the configuration of another protocol or modify another protocol's functionality.
The load generator running the test should add as little time as possible to the total test time. The purpose of running a load test is to check the performance of the server application. If the time added to a transaction by the load generator running the protocol is too great, the test results become difficult to evaluate.
A Vuser should run much faster than the real-world client application. Ideally, the time consumed by the Vuser in a transaction is negligible compared to the time consumed by the server application.
Memory consumption has a direct affect on scalability. The larger the memory footprint of a Vuser, the fewer Vusers can be run on a given load generator.
Scalability and performance are better if the protocol supports each Vuser running in its own thread. In addition to making your own code thread-safe, avoid, if possible, using third-party libraries or other resources that are not thread-safe. For example, the Windows Internet (WinINet) API manages the sockets at the process level rather than the thread level, and therefore cannot be used when each virtual user is run as a thread.
Consider the following when determining your naming conventions:
Terms consistent with application. The terms used in the protocol for names, actions, and descriptions should reflect the terminology of the application to be tested. Where no special terms exist, use widely accepted professional terminology appropriate to the application.
Assigned prefixes. The names of all API functions you implement for use in test steps must begin with the protocol ID. This ensures that all functions across all protocols have unique names.
Consistent look and feel. Names should have a consistent look and feel with other protocols, particularly protocols expected to be used in scripts together with your protocol. Scripts written for most protocols use the utility functions protocol (lr functions) and many also use common protocols like Web. Look at the HP LoadRunner Function Reference for these and other related protocols before setting your conventions.
Lower case names. Most recent C-language protocols have function names in lower case, with the terms separated by an underscore—for example, web_custom_request. This convention is recommended.
Convention for order of verbs and nouns. Decide on a consistent convention for the order of verbs and the objects of the verbs (nouns) in the function name. Many protocols use the convention <ProtocolPrefix>_object_verb—for example, xx_option_click, xx_option_doubleclick, xx_option_set, xx_option_clear, and so on. For other protocols, it is more natural to describe the function in terms of the action. For example, ftp_get_last_handshake_duration, ftp_get_last_error_id, and so on.
Convention for function argument names. Decide on a convention for function argument names. Many recent protocols that use named arguments, use the Pascal naming convention for the key of the argument and to refer to the argument in documentation. For example, "TargetObjectId={targetParam}", "MustUnderstand=false", and so on. Protocols using positional arguments can use Hungarian notation, the Java convention, the Pascal convention, all lower-case, and so on. The decision depends on the context, but should be consistent within one protocol.
Do not use reserved words of the language in which the scripts may be written except according to the standard usage.
If you define any constants for your protocol, begin the constant name with your protocol prefix to avoid redefining constants already in use. You may define and use constants in common use in VuGen, such as LAST, as long as your definition is identical to that in common use, for example:
#define LAST "LAST"