Let's Go!

LoadRunner_GUID,关联长度问题,中文乱码,用Eclipse编写脚本,执行Linux命令,Memcached

上一篇 / 下一篇  2011-07-28 18:26:14 / 个人分类:LoadRunner

以下均转自:http://hi.baidu.com/higkoo/blog/category/Loadrunner/index/0

 

5. LoadRunner实现:模拟生成UUID/GUID

GUID: 即Globally Unique Identifier(全球唯一标识符) 也称作 UUID(Universally Unique IDentifier) 。 GUID是一个通过特定算法产生的二进制长度为128位的数字标识符,用于指示产品的唯一性。GUID 主要用于在拥有多个节点、多台计算机的网络或系统中,分配必须具有唯一性的标识符。

LUID就是指locally unique identifier,GUID/UUID大家是比较熟悉的,和GUID/UUID的要求保证全局唯一不同,LUID只要保证局部唯一,就是指在系统的每一次运行期间保证是唯一的就可以了。

  在 Windows 平台上,GUID 广泛应用于微软的产品中,用于标识如如注册表项、类及接口标识、数据库、系统目录等对象。

    灵感来自:LoadRunner生成唯一数 + LoadRunner实现:计算字符串Md5 。

   原理非常简单,先生成唯一字符串,然后算Md5。以下代码就是在Md5的基础上稍稍加工一下:

void Md5toLUID(char* inStr,char *outStr)
{
    int i;
    strncpy(outStr,inStr,8);
    strcat(outStr,"-");
    for (i=9;i<13;i++)
        outStr[i]=inStr[i-1];
    strcat(outStr,"-");
    for (i=14;i<18;i++)
        outStr[i]=inStr[i-2];
    strcat(outStr,"-");
    for (i=19;i<23;i++)
        outStr[i]=inStr[i-3];
    strcat(outStr,"-");
    for (i=24;i<37;i++)
        outStr[i]=inStr[i-4];
    strcat(outStr,"\0");
}
调用方法:

void main()
{
    char uStr[33],lStr[37];
    int i;
   
    for (i=0;i<10;i++) {
        lr_save_int(i,"iValue");
        GetUniqueString(lr_eval_string("{iValue}"),uStr);
        GetMd5FromString(uStr,uStr);
        Md5toLUID(uStr,lStr);
        lr_output_message(lStr);
    }
}
输出:

main.c(18): b7f163a8-f89c-59e3-6705-a3823a358c0d
main.c(18): 20fcb7ab-0879-9572-fb5b-5c9848b37930
main.c(18): 869b718d-126c-eaeb-b099-b1ec15d3c9db
main.c(18): fd12c050-0975-3641-1de9-3685431d4a01
main.c(18): 604bbc51-e787-1955-d721-ee5032640629
main.c(18): 4fffdc48-0c44-66c9-34d7-697e473d20da
main.c(18): a5d0d30c-5053-03e8-6e1a-1f112ef49007
main.c(18): 4babb152-de2f-1136-d4a6-8aa78a90f2c7
main.c(18): 833f6f33-da3d-efeb-7ec8-95f5491bf1a1
main.c(18): 89148aad-8040-e70c-b406-69d56f570293

   测试的时候这个LUID,就可以当成GUID/UUID使用了。除非同时使用了多个Contorller而且脚本组名也相同,而且即使是如此,取到重复值的机率也非常小!

函数就是在拼接“-”到指定位置,平常用得更多的是字符串替换:C语言实现:替换字符串中指定字符。

 

6. LoadRunner/C语言 实现:生成GUID

在LoadRunner里使用GUID有以下三种方法:

1、使用LoadRunner自带的函数:已实现。

2、使用C++封装DLL供LoadRunner调用。

3、直接调用Windows系统API,方式和第2种类似。


下面是使用第3种方式的实现示例:

vuser_init(){
lr_load_dll("ole32.dll");
}


char* lr_guid_gen(char* paramName){
typedef struct _GUID    {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;

GUID m_guid;
char buf[50];
char pNameStr[50];   

CoCreateGuid(&m_guid);
// 定义输出格式
//sprintf (buf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", // 大写
// sprintf (buf, "{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",// 小写
sprintf (buf, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",// 小写
m_guid.Data1, m_guid.Data2, m_guid.Data3,
m_guid.Data4[0], m_guid.Data4[1], m_guid.Data4[2], m_guid.Data4[3],
m_guid.Data4[4], m_guid.Data4[5], m_guid.Data4[6], m_guid.Data4[7]);   

lr_save_string(buf, paramName);
sprintf(pNameStr,"{%s}",paramName);

return lr_eval_string(pNameStr);
}


Action(){
lr_output_message(lr_guid_gen("GUID"));
}

vuser_end(){
return 0;
}

相对自己编写DLL而言,调用系统API更安全更稳定。

而且C++要求测试人员有一定的编码能力,编写的代码要稳定且安全。

每次修改GUID的输出方式,需要重新修改并编译DLL或编写多个导出。

直接调用系统API,安全稳定。且输出格式随手掌控。

 

7. LoadRunner 函数 web_reg_save_param 的长度问题

发现web_reg_save_param在查找字符串时有问题,找不到指定字符串。

    使用 web_reg_save_param("Wholebody","LB=", "RB=","Notfound=warning","Search=Body", LAST); 可以把整个服务器返回的Body内容都拿出来。

    譬如内容如下:

{"content":"0zIUKjQevu6ygxCSsggU+g30XZL1rEAGOWsjRPQ9CHz1Np28wP4HZ26scc\/sHX9Yq\/hEhB+Au4OwRnIdTUFCP1sDvGb+MY8e2C6aP2ZsBxgpMdiPSkZZ30N9OE+fjTdugiXfAdQMgjzkuluTqbpI6Dhbcyv2k\/ymM9f+zTBOS2wfKOSbVMEnVrBla31XCkvFLJXb60YUrLlVuhUioTcIKXe3800iYQ6ipL3FF9sg6QBkFZ7vri3\/y06le7LMxMS9BrSJs03SLtqHlA2frbaTnFuaLmeDzIvWWDeie4o9r6QWrYtO3MfQ37aK9xn1hh\/A"}

    但是如果你只想要content值的时候,使用 web_reg_save_param("Content","LB=content\":\"", "RB=\"}","Notfound=warning","Search=Body", LAST); 结果是找不到!

    如果把右匹配改为"RB=cc",就可以取到值。起初以为转义字符串导致web_reg_save_param出错从而没有取到值。

    后来作了静态页面专门试验发现和转义字符没有关系,怀疑和长度有关系。但整个Body都取出来了,Body会更长呀。而且如果RB设为空,也能取到值。又让人不去怀疑长度问题。

    长话短说,就是长度问题!添加web_set_max_html_param_len("1024");即可

    为什么会这样呢?分析一下,如果RB留空的话,LoadRunner应该直接给变量赋值为一个指针,所以结束就可以到末尾。如果RB不为空,那么需要经过赋值。而默认长度是256,超长就导致内容错误,所以添加长度设定后就能正常取到值了。

8. LoadRunner无法显示XML的问题

最近测试一个升级程序遇到以下问题:
    要求测试一个XML文件的下载性能。然后发现以下情况:
直接访问URL,无法显示网页:
脚本的目录下,还有“t6_a.xml”;快照不可用,导致无法查看源文件,也不能进行其它操作。

请教了小荷老师:
1、不是所有服务器返回的内容都能看到快照的。
2、 如果非要看快照,你可以试试 url-based () web/http property。
3、 这个快照不可用,不会导致你无法看源文件。
4、 如果你现在确实再无法切换回源文件,这可能因为有语法错误,你在切换的界面的时候,录制脚本的内容已经被改变了。
所以你可以先不着急看快照,先看源文件,检查你的脚本,有没有格式很奇怪的,或者没有结束的,或者xml的语法被当作你的给处理的情况。
     顿时云开雾散,使用URL模式录制问题解决!相比较HTML模式和URL模式的录制日志、脚本、回放日志,都完全相同的。
    小荷老师的四点说得很到位:并不是所有返回内容都是可以在LR里用快照查看的;第2点我没有想到会解决问题;是否有录制到源文件,和快照不能查看不是必然的关系;第4点我倒是有遇到过,是XML树,不过可以正常显示,但源码里有个标记和HTML里不一样。
问题解决了,在此特别感谢小荷老师! 


9.  LoadRunner中文出现乱码的解决办法


录制选项,高级,支持字符集,UTF-8。
一般情况下不需要开启此选项,否则在Submit里会出现有乱码。
如果未开启此功能还出现乱码,可尝试开启此选项。

如果开启此选项还是有乱码,且乱码处的内容你需要进行参数化,可使用lr_convert_string_encoding函数将字符转化为你需要的模式。


函数原型:

int lr_convert_string_encoding ( const char *sourceString, const char *fromEncoding, const char *toEncoding, const char *paramName);

sourceString The string to convert
fromEncoding The encoding of the sourceString
toEncoding The encoding to convert of the string saved in parameter paramName
paramName The name of the parameter in which the destination string will be saved

 

Constant Value
LR_ENC_SYSTEM_LOCALE NULL
LR_ENC_UTF8 "utf-8"
LR_ENC_UNICODE "ucs-2"


//中文乱码互相转换:
   lr_convert_string_encoding("乱码内容",LR_ENC_UTF8,LR_ENC_SYSTEM_LOCALE,"mt") ;

    lr_output_message(" 2 ---\n%s",lr_eval_string("{mt}")) ;

        lr_convert_string_encoding("未通过审核应用",LR_ENC_SYSTEM_LOCALE,LR_ENC_UTF8,"dt") ;

    lr_output_message(" 3 ---\n%s",lr_eval_string("{dt}")) ;


浏览器也有转码功能:菜单“查看”-->编码-->Unicode(UTF-8)

为什么要启用UTF-8,某些请求中会出现:


web_custom_request("CALL-H001I",
        "EncType=text/xml; charset=UTF-8",
……);

这时候,此函数你就派得上用场了!

lr_convert_string_encoding函数的使用,直接查看帮助即可。

说明:
1. 在树视图里的源码(serverResponse)的乱码是没法解决的;
2. 在树视图的页面显示可以是正常,源码视图也可以显示正常;
3. 虽然在server Response显示乱码,但查找中文字符串还是正常的。

 

10. 使用Eclipse编写LoadRunner测试脚本

真是后知后觉,今天才开始尝试用Eclipse编写LoadRunner脚本。

    过去多数都用LoadRunner自带的IDE编写,也有用过Visual Stdio插件。复杂一点的使用DLL或JAR扩展。虽然调试起来比较麻烦,但把常用函数和方法包装起来,一劳永逸还算值得。

    最近项目时间紧,希望能快速开发测试脚本。

    过去遇到的xml、json都不算复杂,用LoadRunner自带函数和C函数一起处理一下就好了。最痛苦的一次是使用LoadRunner实现 Web/Http协议 + Windows Sockets协议 + Mysql + Memcached 脚本的编写,懂LoadRunner的同学应该能明白。虽然内置C编译器,能使用C++扩展,但用法并不完全一样,陷阱多多。使用Java Vuser也没有不像Java开发那样自如。

    今天,我已无法忍受用C语句的char解析服务端返回的大堆Json串了! 忍无可忍,不可再忍

    解析Json串还是用Java最方便,若能使用Eclipse编写LoadRunner脚本是件多么美好的事情呀,就像LoadRunner的VS插件一样。


方法很简单:

    1、使用Eclipse新建一个Java工程

    2、将“%LoadRunner_Home%\classes\lrapi”目录导入到工程中

    3、将工程导出为Jar包,譬如:命名为lrapi.jar

    4、再新建Java工程时,将lrapi.jar引入扩展库中

    5、"import lrapi.lr;"即可使用LoadRunner函数了

    6、 “import lrapi.web;”则可使用LoadRunner的WEB函数

 

 

 

 

11. 在LoadRunner向远程Linux/Unix执行命令行并收集性能数据

前面介绍过在LoadRunner的Java协议实现“使用SSH连接Linux”,当然连接之后的故事由你主导。

    今天要讲的,是一个非Java版本。是对“在LoadRunner中执行命令行程序之:popen()取代system()”的一个升华。

     下面的脚本,是在LoadRunner里连接Linux/Unix远程服务器,收集其磁盘IO的负载到测试结果中。

涉及到三个知识点:

    1、LoadRunner自带“PuTTY Link”的使用,路径为“%LR_PATH%\bin\plink.exe”;

    2、Linux/Unix的磁盘监控指令,读者也可以扩展为其它任何实用指令;

    3、LoadRunner自带函数lr_user_data_point的使用,保存自定义数据到测试结果。

脚本贴出如下:

#define BUFFER_SIZE 20480 // 初始给它 20 KB
extern char* strtok(char *token, const char *delimiter); // 显示申明
Action(){
    long fp; // 数据流
    int count; // 用于保存流长度
    char buffer[BUFFER_SIZE]; // 给数据流分配内存空间
    char * row_token; // 记录每一行的地址
    char field_name[100]; // 第一列的名称
    int field_value; // 保存系列的值
    char lrudp_name[100]; // 保存LR自定义指标值
    int rc; // 保存返回值

    lr_start_transaction("DiskIO");// Linux采样方式: plink -ssh -l username -pw password hostname command
    lr_save_string("higkoo", "UserName");
    lr_save_string("123456", "Password");
    lr_save_string("192.168.10.31", "Server");
    lr_save_string("iostat -xc | awk 'NR >2 {print $1, $10}'", "Command"); // 使用iostat拿到磁盘IO的状态信息
    lr_save_string(lr_eval_string("\"%LR_PATH%\\bin\\plink\" -ssh -l {UserName} -pw {Password} {Server} \"{Command}\" 2>&1 "), "Result"); // 使用plink连接远程Linux服务器并拿到执行结果
    fp = popen(lr_eval_string("{Result}"), "r");
    if (fp == NULL) {
        lr_error_message("执行命令失败");
        return -1;
    }

    count = fread(buffer, sizeof(char), BUFFER_SIZE, fp); // 读取结果
    if (feof(fp) == 0) {
        lr_error_message("返回结果太大,请给数据流分配更大内存空间,谢谢!");
        return -1;
    }
    if (ferror(fp)) {
        lr_error_message ("监控指令返回错误");
        return -1;
    }
    if (count == 0) {
        lr_error_message("监控指令返回结果为熔");
        return -1;
    }
    buffer[count] = NULL;

    row_token = (char*) strtok(buffer, "\n"); // 按换行符分割
    if (row_token == NULL) {
        lr_error_message ("未发现有效数据");
        return -1;
    }
    while (row_token != NULL) { // 开始读取数据
        rc = sscanf(row_token, "%s %d", field_name, &field_value); //分割名称与值
        if (rc != 2) {
            lr_error_message("Incorrect number of items read from the row.");
            return -1;
        }

        sprintf(lrudp_name, "disk_busy_%s", field_name);// 自定义数据的名称
        lr_user_data_point(lrudp_name, field_value);// 保存到LR自定义数据

        row_token = (char*) strtok(NULL, "\n");
    }

    pclose(fp);

    lr_end_transaction("DiskIO", LR_AUTO);
}
功能实现了,后面的故事你来讲~~ 

在LoadRunner中执行命令行程序之:popen()取代system()
http://hi.baidu.com/higkoo/blog/item/3f6e6a467e02a0076b63e5b5.html
在LoadRunner向远程Linux/Unix执行命令行并收集性能数据
http://hi.baidu.com/higkoo/blog/item/5ab2ea82f36b559ef703a67a.html

 

 

12.  LoadRunner使用Libmemcached与Memcached通讯

在一包含业务的大数据量测试过程中,需要使用快速、大容量的数据库。

    可考虑的有关系型数据库或键值缓存数据库,建立集群。 LoadRunner操作Mysql实例:C语言篇已完成。

    今日来尝试在LoadRunner里操作Memcached,使用Libmemcached。

    首先下载源码:?http://svn.coderepos.org/share/lang/c/libmemcached-win32

      然后按照说明进行编译,源码里还有测试代码和示例代码。编译方法有三种:

        一、使用?mingw32进行编译,打开? Visual Studio Command Prompt:


?    ?    cd libmemcached-latest\libmemcached
?    ?    mingw32-make -f Makefile.w32

?    ?    cd ..\cilents
?    ?    mingw32-make -f Makefile.w32

?    ?    cd ..\..\example
?    ?    mingw32-make -f Makefile.w32

    二、使用Visual Studio 2005或更高版本执行编译:
?    ?    libmemcached-latest\visualc\libmemcached.sln
    三、使用nmake进行编译,?打开? Visual Studio Command Prompt:
?    ?    cd libmemcached-latest\libmemcached
?    ?    nmake -f Makefile.msc

??    ?    cd ..\cilents
?    ?    nmake -f Makefile.msc

?    ?    cd ..\..\example
??    ?    nmake -f Makefile.msc

    编译过程将生成memcached.dll,供LoadRunner扩展调用。如下图:
?

 

 

源码:


#define SERVER_NAME "192.168.223.106"
#define SERVER_PORT 11211
Action(){ //先加载libmemcached.dll
    int memc;
    int rc;
    int value_length=0;
    intf lags=0;
    int result;
    long int num;
    char* key="name";
    char* value="higkoo";
    char* discription="Performance";

    memc=memcached_create(NULL);
    rc=memcached_server_add(memc,SERVER_NAME,SERVER_PORT);
    lr_output_message("server add: %s\n",memcached_strerror(memc,rc));

     rc=memcached_set(memc,key,strlen(key),value,strlen(value),0,0);
     lr_output_message("set '%s' to '%s': %s\n",key,value,memcached_strerror(memc,rc));

    result=memcached_get(memc,key,strlen(key),&value_length,&flags,&rc);
    lr_output_message("get '%s': %s\n",key,memcached_strerror(memc,rc));
    lr_output_message("%s = %s\n",key,result);

    rc=memcached_behavior_set(memc,0,1);
    lr_output_message("behavior. set to non-block: %s\n",memcached_strerror(memc,rc));

    result=memcached_get(memc,key,strlen(key),&value_length,&flags,&rc);
    lr_output_message("get '%s': %s\n",key,memcached_strerror(memc,rc));
    lr_output_message("%s = %s\n",key,value);

    rc=memcached_set(memc,key,strlen(key),discription,strlen(discription),0,0);
    lr_output_message("set '%s' to '%s': %s\n",key,discription,memcached_strerror(memc,rc));

    rc=memcached_increment(memc,key,strlen(key),1,&num);
    lr_output_message("incr '%s': %s\n",key,memcached_strerror(memc,rc));
    rc=memcached_increment(memc,key,strlen(key),1,&num);
    lr_output_message("incr '%s': %s\n",key,memcached_strerror(memc,rc));
    rc=memcached_increment(memc,key,strlen(key),1,&num);
    lr_output_message("incr '%s': %s\n",key,memcached_strerror(memc,rc));
    rc=memcached_decrement(memc,key,strlen(key),1,&num);
    lr_output_message("decr '%s': %s\n",key,memcached_strerror(memc,rc));

    result=memcached_get(memc,key,strlen(key),&value_length,&flags,&rc);
    lr_output_message("get '%s': %s\n",key,memcached_strerror(memc,rc));
    lr_output_message("test= %s\n",value);

    rc=memcached_delete(memc,key,strlen(key),0);
    lr_output_message("delete '%s': %s\n",key,memcached_strerror(memc,rc));

    result=memcached_get(memc,key,strlen(key),&value_length,&flags,&rc);
    lr_output_message("get(was deleted) '%s': %s\n",key,memcached_strerror(memc,rc));

    memcached_free(memc);
}


...


TAG:

引用 删除 dqpiwangjian   /   2012-09-26 14:13:48
5
墨帅 引用 删除 lbxoqy   /   2012-05-29 13:57:31
5
 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar