Siege的源码二次开发-定制化测试工具

1)下载官方2.64版。

2)安装

./configure

make

make install.

可执行文件路径为/usr/local/bin/siege.

 

3)运行查看配置

linux-ntr1:/usr/local/bin # ./siege -C
the config file ,filename:/root/.siegerc
CURRENT  SIEGE  CONFIGURATION
JoeDog/1.00 [en] (X11; I; Siege 2.56)
Edit the resource file to change the settings.
----------------------------------------------
version:                        2.56
verbose:                        true
debug:                          false
protocol:                       HTTP/1.1
connection:                     close
concurrent users:               15
time to run:                    n/a
repetitions:                    n/a
delay:                          1 sec
internet simulation:            false
benchmark mode:                 false
failures until abort:           20
named URL:                      none
URLs file:                      /usr/local/etc/urls.txt
logging:                        true
log file:                       /usr/local/var/siege.log
resource file:                  /root/.siegerc
allow redirects:                true
allow zero byte data:           false

可见:版本号,debug模式关闭,并发用户数15,

需要访问的URL列表为/usr/local/etc/urls.txt.

写日志,siege程序的主配置文件为/root/.siegerc.

 ~~~~~~~~~~~~~~~~~~~~~~~~~~~开始改造

(4)改造1,支持登陆。

由于siege本身是支持登陆的,但是请求头是固定的,而公司的请求头有要求。

改造的原理如下:

load_conf( char *filename )
{
 ...
 if( !strncasecmp( option, "login-url", 9 ))
 {
      my.login = TRUE;
      my.loginurl = value;
    } 
 ...
}

所以在配置文件中指定login-url即可:

这里只需要根据配置文件的样板来做即可,POST 后面可以添加JSON格式的数据,比如id啊,密码啊以及其它之类的。

自己处理即可。

 

之前说了,公司的请求头比较严格,所以需要修改登录URL对应的请求头,也就是添加字段。

如何修改文件头呢?

SIEGEhttp_post
{
...
else{
    rlen=snprintf(
      request, sizeof( request ),
      "POST %s %s\015\012"
      "Host: %s\015\012"
      "Cookie: %s\015\012"
      "Accept: */*\015\012"
      "Accept-Encoding: * \015\012"
      "User-Agent: %s\015\012%s"
      "Connection: %s\015\012"
      "Content-type: application/x-www-form-urlencoded\015\012"
      "Content-length: %d\015\012\015\012"
      "%*.*s\015\012",
      fullpath, protocol, host, cookie, my.uagent, 
      my.extra, keepalive, len, len, (int)len, data
    );
  }
}

直接在这里写吗?麻烦。。。为了可配置化。

先扩充数据结构:

struct CONFIG
{
  int  logging;      /* boolean, log transactions to log file   */
  int  shlog;        /* show log file configuration directive.  */
  char logfile[128]; /* alternative user defined simbot.log     */ 
  int  verbose;      /* boolean, verbose output to screen       */
  int  display;      /* boolean, display the thread id verbose  */
  int  config;       /* boolean, prints the configuration       */
  int  cusers;       /* default concurrent users value.         */
  int  delay;        /* range for random time delay, see -d     */
  int  timeout;      /* socket connection timeout value, def:10 */
  int  bench;        /* signifies a benchmarking run, no delay  */
  int  internet;     /* boolean, tell siege to use random mode. */
  int  time;         /* length of the siege in hrs, mins, secs  */
  int  secs;         /* time value for the lenght of the siege  */
  int  reps;         /* reps to run the test, default infinite  */ 
  char file[128];    /* urls.txt file, default in joepath.h     */
  int  length;       /* length of the urls array, made global   */
  int  debug;        /* boolean, undocumented debug command     */
  int  mark;         /* boolean, signifies a log file mark req. */ 
  char *markstr;     /* user defined string value to mark file  */
  char *url;         /* URL for the single hit invocation.      */
  int  protocol;     /* 0=HTTP/1.0; 1=HTTP/1.1                  */
  int  cookies;      /* boolean, to use cookies or not.         */
  char uagent[256];  /* user defined User-Agent string.         */
  char *username;    /* WWW-Authenticate user name              */
  char *password;    /* WWW-Authenticate password.              */
  char *auth;        /* WWW-Authenticate base64 usr:pas holder  */
  int  authorize;    /* WWW-Authenticate boolean, require auth  */
  int  keepalive;    /* boolean, connection keep-alive value    */
  int  signaled;     /* timed based testing notification bool.  */
  char extra[512];   /* extra http request headers              */ 
  int  proxy;        /* boolean, TRUE == use a proxy server.    */
  char *proxysrv;    /* hostname for the proxy server.          */
  int  proxyport;    /* port number for proxysrv                */ 
  int  login;        /* boolean, client must login first.       */
  char *loginurl;    /* the initial login URL, first URL hit.   */
  int  failures;     /* number of failed attempts before abort. */
  int  failed;       /* total number of socket failures.        */
  int  expire;       /* boolean, TRUE == expire cookies ea. run */
  int  follow;       /* boolean, TRUE == follow 302             */
  int  zero_ok;      /* boolean, TRUE == zero bytes data is OK. */ 
  
};

在后面加上我们需要的几个字段,为了保密这里就不贴加上的字段了,

然后需要在配置文件中加上key/value.

然后在解析配置文件的函数中添加代码支持:

修改load_conf函数
if(!strncasecmp(option,*key1*, sizeof(*key1*))){
   		my.key1 = value;
   	}

   if(!strncasecmp(option,"字段2", sizeof("字段2"))){
   		my.key2 = value;
   	}

以上代码是示意。

 好,现在有了值,我们把字段嵌入到文件头里,

修改SIEGEhttp_post函数即可。

编译查看效果检验正确性。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

测试时报错:

Execution exception[[NullPointerException: null]]

原来是两个问题:

1) http 请求头的content-type
 /* "Content-type: application/x-www-form-urlencoded\015\012"*/
修改为 "Content-type: application/json\015\012"

2)配置文件里/root/.siegerc里的login-url的post的内容必须一致为json格式。

再测试,顺利通过!

登陆成功!

~~~~~~~~~~~~~~~~~~~~登陆后,开始执行业务URL

发现取不到之前的cookie.

百般思索,用gdb跟了下,才找到原因,login-url的域名和urls.txt的域名不一致

一个是IP,一个是name.再来修改。

修改完之后还是不行,发现新版增加了cookie超时的功能,怎么破?

问题原因:

函数get_cookie_header内

 if(cur->expires <= now)
{
          continue;
}

导致之前保存的cookie节点无用。continue直接忽略了。

那么什么时候设置的cur->expires?

~~~~~~~~~~~~~~~~~~~~

http_read_headers函数里,有一个子函数add_cookie( pthread_self(), host, h->cookie );

 显然是这里读取请求头,解析请求头,保存cookie

将这里作为突破口!

~~~~

add_cookie函数里有个子函数

parse_cookie(cookiestr, &ck);

看看parse_cookie做了什么事情。

用gdb跟一下,

心得就是:每次都读取cookie的每个字段,跟已经有的cookie字段比较

基本思想就是一个upsert.你懂的。

为了简单,直接在get_cookie_header函数里屏蔽时间比较。

也就是把下面的代码屏蔽

  if(cur->expires <= now)
{
          continue;
}

 然后测试:发现返回

HTTP/1.1 404 Not Found

纳尼?

经过跟测试人员交流,发现测试与生产的代码有差异,生产环境OK,但是测试环境有问题

等待修复!!!Soga。

~~~~~~~~~~~~~~~~~~~~~~~~~~~·waiting...

等待的同时,发现一个问题,配置文件里我指定了2个URL,为啥debug只打出一个url>>>?

本来以为是把代码改错了,看了下代码,才发现原来我为了调试代码设置参数:

并发用户数1 / 每个用户的重复次数为1.

重复次数为1,当然只执行1次URL了。修改为2尝试。

bingo!返回了结果。成功了!

~~~~~~~~~~~~~~~~~~~~~~~~~~~还别高兴太早!

发现了最严重的问题,测试结束后,

Data transferred:	        0.00 MB

这又是为啥?

原因就是,如果只是做了几次交互,数量传输比较少,就会造成输出时很小的数字输出0,这是 siege格式控制产生的问题,还得修改最后统计的格式。

屏蔽
fprintf(stderr, "Data transferred:\t%12.2f MB\n",        data_get_megabytes(D)); /*%12llu*/
修改成
 fprintf(stderr, "Data transferred:\t%12.2f  Bytes\n",        data_get_bytes(D)); /*%12llu*/

 修改函数

float
data_get_throughput(DATA this)
{
  if(this->elapsed==0)
    return 0;
  return this->bytes / (this->elapsed * 1024.0*1024.0);
}

改造成直接返回this->bytes/ ( this->elapsed ) .

好了,改造完成,开始测试:!!!

这里再设置下超时时间,如果远程服务器返回数据要等很长时间,那就终止连接。

函数

__socket_check

设置了超时时间跟my.timeout有关,默认为:

(gdb) p my.timeout
$1 = 30

这个实在等不了,果断修改配置文件。

# Connection timeout value. Set the value in seconds for 
# socket connection timeouts. The default value is 30 seconds.
# ex: timeout = 30
#
timeout = 3

大功告成,就是这么简单!

 

你可能感兴趣的:(siege)