r0c/test/stress.py

337 lines
7.2 KiB
Python
Raw Normal View History

2018-01-08 00:51:19 +00:00
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
from __future__ import print_function
"""stress.py: retr0chat stress tester"""
__version__ = "0.9"
__author__ = "ed <a@ocv.me>"
__credits__ = ["stackoverflow.com"]
__license__ = "MIT"
__copyright__ = 2018
import threading
import asyncore
import socket
import signal
import random
2018-01-08 00:51:19 +00:00
import time
import sys
PY2 = (sys.version_info[0] == 2)
if PY2:
from Queue import Queue
else:
from queue import Queue
class Client(asyncore.dispatcher):
def __init__(self, core):
2018-01-08 00:51:19 +00:00
asyncore.dispatcher.__init__(self)
self.core = core
self.explain = True
#self.explain = False
2018-01-08 00:51:19 +00:00
self.in_text = u''
self.outbox = Queue()
self.backlog = None
self.dead = False
self.stage = 'start'
self.actor_active = False
2018-01-08 00:51:19 +00:00
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect(('127.0.0.1', 2323))
thr = threading.Thread(target=self.actor)
thr.daemon = True # for emergency purposes
thr.start()
def actor(self):
self.actor_active = True
print('actor going up')
while not self.core.stopping:
time.sleep(0.02)
if self.stage == 'start':
if 'type the text below, then hit [Enter]:' in self.in_text:
self.stage = 'qwer'
self.in_text = u''
for ch in u'qwer asdf\n':
self.tx(ch)
time.sleep(0.02)
continue
if self.stage == 'qwer':
if 'text appeared as you typed' in self.in_text:
self.stage = 'color'
self.in_text = u''
self.tx(u'b')
self.outbox.put(b'\xff\xfa\x1f\x00\x80\x00\x24\xff\xf0') # 128x36
continue
if self.stage == 'color':
if 'does colours work?' in self.in_text:
self.stage = 'codec'
self.in_text = u''
self.tx(u'y')
continue
if self.stage == 'codec':
if 'which line looks like' in self.in_text:
self.stage = 'ready'
self.in_text = u''
self.tx(u'a')
#return self.flood_single_channel()
return self.jump_channels()
self.actor_active = False
def flood_single_channel(self):
while not self.core.stopping:
time.sleep(0.02)
if self.stage == 'ready':
if 'fire/' in self.in_text:
self.stage = 'main'
self.in_Text = u''
continue
if self.stage == 'main':
self.stage = 'done'
for n in range(4000):
time.sleep(0.01)
self.tx(u'{0} {1}\n'.format(time.time(), n))
continue
if self.stage == 'done':
time.sleep(1)
self.text = u'' # dont care
if not self.outbox.empty():
continue
self.tx(u'{0} done\n'.format(time.time()))
def expl(msg):
if not self.explain:
return
print(msg)
time.sleep(4)
def jump_channels(self):
script = []
active_chan = 0
member_of = ['#general']
channels_avail = ['#general','#1','#2','#3']
# maps to channels_avail
msg_id = [0,0,0,0]
# -------- acts ---------
# 0 - 9: next channel
# 10 - 14: join a channel
# 15 - 18: part a channel
# 19 - 36: send a message
for n in range(100000):
if n % 1000 == 0:
self.tx(b'at event {0}\n'.format(n))
while True:
next_act = random.randrange(37)
if next_act <= 9:
changed_from_i = active_chan
changed_from_t = member_of[active_chan]
active_chan += 1
script.append(b'\x18')
if active_chan >= len(member_of):
# we do not consider the status channel
script.append(b'\x18')
active_chan = 0
changed_to_i = active_chan
changed_to_t = member_of[active_chan]
if self.explain:
print('switching to next channel from {0} to {1} ({2} to {3})'.format(
changed_from_i, changed_to_i,
changed_from_t, changed_to_t))
for act in script:
self.outbox.put(act)
script = []
time.sleep(4)
break
if next_act <= 14:
if len(member_of) == len(channels_avail):
# out of channels to join, try a different act
continue
while True:
to_join = random.choice(channels_avail)
if to_join not in member_of:
break
member_of.append(to_join)
active_chan = len(member_of) - 1
script.append(b'/join {0}\n'.format(to_join))
break
if next_act <= 18:
if not member_of:
# out of channels to part, try a different act
continue
to_part = random.choice(member_of)
chan_idx = member_of.index(to_part)
# jump to the channel to part from
while active_chan != chan_idx:
active_chan += 1
script.append(b'\x18')
if active_chan >= len(member_of):
# we do not consider the status channel
script.append(b'\x18')
active_chan = 0
if active_chan == len(member_of) - 1:
del member_of[active_chan]
active_chan -= 1
else:
del member_of[active_chan]
script.append(b'/part\n')
break
if not member_of:
# not in any channels, try a different act
continue
chan_name = member_of[active_chan]
chan_idx = channels_avail.index(chan_name)
msg_id[chan_idx] += 1
script.append(b'{0} {1} {2}\n'.format(chan_name, msg_id[chan_idx], n))
self.tx(b'q\n'.format(n))
while not self.core.stopping:
if 'fire/' in self.in_text:
break
time.sleep(0.01)
for n, ev in enumerate(script):
if self.core.stopping:
break
if n % 100 == 0:
print(b'at event {0}\n'.format(n))
self.outbox.put(ev)
time.sleep(0.05)
print('done')
self.tx('done')
2018-01-08 00:51:19 +00:00
def handle_close(self):
self.dead = True
def tx(self, bv):
self.outbox.put(bv.encode('utf-8'))
2018-01-08 00:51:19 +00:00
def readable(self):
return not self.dead
def writable(self):
return (self.backlog or not self.outbox.empty())
2018-01-08 00:51:19 +00:00
def handle_write(self):
msg = self.backlog
if not msg:
msg = self.outbox.get()
sent = self.send(msg)
self.backlog = msg[sent:]
def handle_read(self):
if self.dead:
print('!!! read when dead')
return
data = self.recv(8192)
if not data:
self.dead = True
return
self.in_text += data.decode('utf-8', 'ignore')
#print(self.in_text)
2018-01-08 00:51:19 +00:00
class Core(object):
def __init__(self):
self.stopping = False
self.asyncore_alive = False
2018-01-08 00:51:19 +00:00
signal.signal(signal.SIGINT, self.signal_handler)
self.client = Client(self)
2018-01-08 00:51:19 +00:00
self.asyncore_thr = threading.Thread(target=self.asyncore_worker)
self.asyncore_thr.start()
def run(self):
print(' * test is running')
while not self.stopping:
time.sleep(0.1)
print('\r\n * actor stopping')
clean_shutdown = False
for n in range(0, 40): # 2sec
if not self.client.actor_active:
print(' * actor stopped')
clean_shutdown = True
break
time.sleep(0.05)
if not clean_shutdown:
print(' -X- actor is stuck')
print(' * asyncore stopping')
2018-01-08 00:51:19 +00:00
clean_shutdown = False
for n in range(0, 40): # 2sec
if not self.asyncore_alive:
print(' * asyncore stopped')
2018-01-08 00:51:19 +00:00
clean_shutdown = True
break
time.sleep(0.05)
if not clean_shutdown:
print(' -X- asyncore is stuck')
print(' * asyncore cleanup')
self.client.close()
2018-01-08 00:51:19 +00:00
print(' * test ended')
2018-01-08 00:51:19 +00:00
def asyncore_worker(self):
self.asyncore_alive = True
timeout = 0.05
while not self.stopping:
asyncore.loop(timeout, count=0.5/timeout)
self.asyncore_alive = False
def shutdown(self):
self.stopping = True
def signal_handler(self, signal, frame):
self.shutdown()
core = Core()
core.run()