3/10/2016 - Brotli DFE for LoadRunner

    DFE is the acronym for Data Format Exchange. DFE's in LoadRunner allow you to modify responses and requests which transforms them in to another format. LoadRunner comes with some built-in DFE's, such as JSON to XML, this DFE will take JSON data in the request or response and transform it to XML, which with helper functions easily allows parsing of the data.

    Brotli, created by Google, is a generic-purpose lossless compression algorithm that compresses data using a combination of a modern variant of the LZ77 algorithm, Huffman coding and 2nd order context modeling, with a compression ratio comparable to the best currently available general-purpose compression methods. It is similar in speed with deflate but offers more dense compression.

    The Brotli DFE compresses/decompresses HTTP requests and responses allowing you to generate scripts when the HTTP server uses this data encoding. Please contact us if you are interested in purchasing this DFE.

03/03/2016 - Deploy LoadRunner VTS on Linux

clang 3.7
[email protected]
node v0.10.17
LoadRunner v12.50 Community Edition

01.  Download node-leveldb (https://github.com/my8bird/node-leveldb) from the master branch.  
02.  Download Node source code for build v0.10.17 (https://nodejs.org/download/release/v0.10.17/node-v0.10.17.tar.gz)
03.  Download the Node binaries for Linux x64 (https://nodejs.org/download/release/v0.10.17/node-v0.10.17-linux-x64.tar.gz)
04.  Extract the 3 packages above, the directories will be referred to as $node-leveldb_src, $node_v0.10.17_src, $node_v0.10.17
05.  Export NODE_PATH:  export NODE_PATH=$node_v0.10.17/lib/node_modules
06.  Export the linker and compiler to clang:  export CXX=clang++; export LINK=clang++
05.  Change to the $node-leveldb_src directory
06.  Execute $node_v0.10.17/lib/node_modules/npm/bin/node-gyp-bin/node-gyp rebuild --nodedir=$node-leveldb_src
07.  Goto: <LRINSTALL_FILES>\DVD\Additional Components\Virtual Table Server\ and extract SetupVTS.exe with WinZip.
08.  After extracting SetupVTS, use lessmsi (http://lessmsi.activescott.com/) to extract .\SetupVTS\HP_VTS_x64.msi
09.  After extracting HP_VTS_x64.msi to a folder, copy .\SourceDir\HP\VTS\web\* to your linux server, referred to as $vts below
10.  Copy $node-leveldb_src/build/Release/leveldb.node to $vts/node_modules/leveldb/lib
11.  Replace $vts/main.js and $vts/log.js with these modified versions: main.js log.js
12.  Create tmp and data directories in $vts:  mkdir $vts/data; mkdir $vts/tmp
13.  Modify $vts/configure.json dbPath and logger.transports.file.path values to $vts/data and $vts/tmp
14.  Start the server:  cd $vts; $node_v0.10.17/bin/node main.js

05/28/2015 - Atlassian Bamboo ALM Plugin

After seeing some interest from a recent client, and LinkedIn, for using Bamboo as their CI tool we decided to put together an ALM plugin that allows users to run tests from within Bamboo. This plugin will allow users to execute automated test scripts residing in ALM. We are releasing the binary for the plugin today and we'll be posting a link to the git repoitory in the next few weeks.




01/23/2015 - Using a Rust DLL in your VuGen Scripts

On occasion the need arises for a performance engineer to expand their scripts with an external function. This function usually resides in an external DLL which we need to reference. For the most part this external function is likely to be written in C/C++. But what if we decide we want to use a different language, like Rust. In this post, I will demonstrate how to construt a small Rust function that will intern access one of LoadRunner's functions. Once we compile our new function we will be able to access it from a VuGen script.

First, let's look at the Rust function. This code was written to compile against a recent nightly build [rustc 1.0.0-nightly (29bd9a06e 2015-01-20 23:03:09 +0000)]. The code isn't documented and I won't be stepping through line by line to explain it. The purpose of this post is just to demonstrate the feasibility. To ease our use of the Win32 API, I am making use of a 3rd party Rust library.

#![crate_type = "dylib"]

extern crate libc;
extern crate "kernel32-sys" as kernel32;
extern crate winapi;

use winapi::*;
use kernel32::*;
use std::ffi::CString;

type LROUTPUTMESSAGE = extern "C" fn(LPCSTR, ...) -> i32;

pub extern "stdcall" fn DllMain(module: u32, reason_for_call: u32, reserved: *mut libc::c_void) -> BOOL 
    return 1;

pub extern "stdcall" fn rustTest() -> u32
    let funcstr = CString::from_slice(b"lr_output_message");
    let dll = CString::from_slice(b"lrun50.dll");

    let handle = unsafe { GetModuleHandleA(dll.as_ptr())};

    if handle == 0 as *mut winapi::HINSTANCE__ 
        return 0;

    let lr_output_message: LROUTPUTMESSAGE = unsafe {  std::mem::transmute(GetProcAddress(handle, funcstr.as_ptr())) };
    if unsafe {::std::mem::transmute::<_,*mut DWORD >(lr_output_message).is_null()} 
        return 0;

    lr_output_message("0x%.08x - %s\0".as_ptr() as LPCSTR, 0xDEADBEEFu32, "An output message from Rust\0".as_ptr() as LPCSTR);

    return 1;

Now that we have our Rust code, let's compile it to a DLL. Because we specifid a 'crate type' above, we don't have to specify any special command line arguments for the compiler to know it's a DLL; as would be the case with C.

C:\Temp\>rustc test.rs -L . -o test.dll

Once we've compiled our code, we can now use it in our script. Below is a small example of loading our DLL and calling our external function.



    lr_output_message("retval = %d",rustTest());

    return 0;

And the corresponding output to script execution...

Virtual User Script started at : 1/22/2015 3:36:00 PM
Starting action vuser_init.
Web Turbo Replay of LoadRunner 12.0.0 for Windows 8.1; build 2739 (Nov 30 2014 23:13:05)    [MsgId: MMSG-27143]
Run mode: HTML      [MsgId: MMSG-26993]
Run-Time Settings file: "C:\Users\Developer\Documents\VuGen\Scripts\WebHttpHtml10\\default.cfg"     [MsgId: MMSG-27141]
vuser_init.c(6): 0xdeadbeef - An output message from Rust
vuser_init.c(6): retval = 1
Ending action vuser_init.
Running Vuser...

In conclustion, this is a simple proof of concept. No more, no less. Keep in mind that Rust v1.0 has not been finalized yet, which means this code could break in future nightly builds/final build. Another topic to note is the size of the Rust DLL, which compiled as is, is 2.6MB. I have not investigated if it is possible to slim some bloat off of the file. As is, this likely wouldn't be feasible to run this in a 'Per Process' test. Which means that in a 'Per Thread' VUser test, we would need to be aware of any thread-safety issues.