yandex-tank/Tank/stepper/missile.py

142 lines
4.7 KiB
Python
Raw Normal View History

2013-05-27 13:06:28 +00:00
'''
Missile object and generators
2013-07-16 12:02:56 +00:00
2013-07-16 13:21:55 +00:00
You should update Stepper.status.ammo_count and Stepper.status.loop_count in your custom generators!
2013-05-27 13:06:28 +00:00
'''
from itertools import cycle
2013-07-15 11:51:50 +00:00
from module_exceptions import AmmoFileError
2013-07-23 14:22:37 +00:00
import os.path
2013-07-16 13:21:55 +00:00
import info
2013-05-27 13:06:28 +00:00
class HttpAmmo(object):
'''
Represents HTTP missile
'''
2013-05-27 13:06:28 +00:00
def __init__(self, uri, headers, method='GET', http_ver='1.1'):
self.method = method
self.uri = uri
self.proto = 'HTTP/%s' % http_ver
self.headers = headers
self.body = []
def to_s(self):
2013-06-25 13:18:36 +00:00
if self.headers:
headers = '\r\n'.join(self.headers) + '\r\n'
2013-06-26 12:52:03 +00:00
else:
headers = ''
2013-06-25 13:18:36 +00:00
return "%s %s %s\r\n%s\r\n" % (self.method, self.uri, self.proto, headers)
2013-05-27 13:06:28 +00:00
class SimpleGenerator(object):
'''
Generates ammo based on a given sample.
'''
2013-05-27 13:06:28 +00:00
def __init__(self, missile_sample):
'''
Missile sample is any object that has to_s method which
returns its string representation.
'''
2013-05-27 13:06:28 +00:00
self.missiles = cycle([(missile_sample.to_s(), None)])
def __iter__(self):
for m in self.missiles:
2013-07-16 13:21:55 +00:00
info.status.inc_loop_count()
info.status.inc_ammo_count() # loops equals ammo count
2013-05-27 13:06:28 +00:00
yield m
class UriStyleGenerator(object):
'''
Generates GET ammo based on given URI list.
'''
2013-07-16 12:18:46 +00:00
def __init__(self, uris, headers, http_ver='1.1'):
'''
uris - a list of URIs as strings.
'''
2013-05-27 13:06:28 +00:00
self.uri_count = len(uris)
self.missiles = cycle(
[(HttpAmmo(uri, headers, http_ver=http_ver).to_s(), None) for uri in uris])
2013-05-27 13:06:28 +00:00
def __iter__(self):
for m in self.missiles:
2013-07-16 13:21:55 +00:00
info.status.inc_ammo_count()
info.status.loop_count = info.status.ammo_count / self.uri_count
2013-07-16 12:18:46 +00:00
yield m
2013-05-27 13:06:28 +00:00
class AmmoFileReader(object):
2013-05-27 13:06:28 +00:00
'''Read missiles from ammo file'''
def __init__(self, filename):
2013-05-27 13:06:28 +00:00
self.filename = filename
def __iter__(self):
with open(self.filename, 'rb') as ammo_file:
2013-07-30 14:18:15 +00:00
info.status.af_size = os.path.getsize(self.filename)
2013-07-23 14:22:37 +00:00
chunk_header = ammo_file.readline().strip('\r\n')
2013-05-27 13:06:28 +00:00
while chunk_header:
2013-07-23 14:22:37 +00:00
if chunk_header is not '':
try:
fields = chunk_header.split()
chunk_size = int(fields[0])
marker = fields[1] if len(fields) > 1 else None
missile = ammo_file.read(chunk_size)
if len(missile) < chunk_size:
raise AmmoFileError(
"Unexpected end of file: read %s bytes instead of %s" % (len(missile), chunk_size))
2013-07-16 13:21:55 +00:00
info.status.inc_ammo_count()
yield (missile, marker)
except (IndexError, ValueError):
raise AmmoFileError(
"Error while reading ammo file. Position: %s, header: '%s'" % (ammo_file.tell(), chunk_header))
2013-07-23 14:22:37 +00:00
chunk_header = ammo_file.readline().strip('\r\n')
2013-07-16 12:18:46 +00:00
if not chunk_header:
2013-07-15 16:00:27 +00:00
ammo_file.seek(0)
2013-07-30 14:18:15 +00:00
info.status.af_position = 0
2013-07-30 11:47:54 +00:00
info.status.inc_loop_count()
2013-07-23 14:22:37 +00:00
chunk_header = ammo_file.readline().strip('\r\n')
2013-07-30 11:47:54 +00:00
else:
2013-07-30 14:18:15 +00:00
info.status.af_position = ammo_file.tell()
2013-08-12 10:04:00 +00:00
class SlowLogReader(object):
'''Read missiles from SQL slow log. Not usable with Phantom'''
def __init__(self, filename):
self.filename = filename
def __iter__(self):
with open(self.filename, 'rb') as ammo_file:
info.status.af_size = os.path.getsize(self.filename)
request = ''
loop_count = 0
while True:
for line in ammo_file:
info.status.af_position = ammo_file.tell()
if line.startswith('#') or line.startswith('/*'):
pass
else:
if ';' in line:
req_end, req_start = line.split(';')
result = ' '.join((request + req_end).split())
for kw in 'select insert update delete'.split():
if result.startswith(kw):
info.status.inc_ammo_count()
yield result
break
request = req_start
else:
request += line
loop_count += 1
ammo_file.seek(0)
info.status.af_position = 0
info.status.inc_loop_count()