From a18f6d1b1ecef9a09c4281eb9a59d6313fe5f62d Mon Sep 17 00:00:00 2001 From: Bill Erickson Date: Tue, 7 May 2013 16:30:52 -0400 Subject: [PATCH] constrictor SIP2; login repair; item info load tests * login occurs within a thread lock to prevent multiple in-flight logins (for a single username), which Evergreen does not handle well. * add # iterations and task delay settings for load testing scripts Signed-off-by: Bill Erickson --- constrictor.properties | 6 ++++ contrib/sip2/sip2_client.py | 46 +++++++++++++++------------- contrib/sip2/sip2_item_info_endurance.py | 42 ++++++++++++++++++++----- contrib/sip2/sip2_mixed_batch.py | 2 +- contrib/sip2/sip2_patron_info_endurance.py | 2 +- contrib/sip2/sip2_patron_status_endurance.py | 2 +- 6 files changed, 69 insertions(+), 31 deletions(-) diff --git a/constrictor.properties b/constrictor.properties index 54b24ccbf..5cebd78fe 100644 --- a/constrictor.properties +++ b/constrictor.properties @@ -97,4 +97,10 @@ sip2.copyBarcodes= sip2.userBarcodes= # passwords must correspond to user barcodes by position in the list sip2.userPasswords= +# ms delay between requests; used for load testing +sip2.load.delay=100 +# number of requests to make per thread +# this is used in lieu of iterations since each iteration requires +# a SIP login, which tests a different kind of load entirely +sip2.load.iterations=100 diff --git a/contrib/sip2/sip2_client.py b/contrib/sip2/sip2_client.py index dd6ce9b7d..4f41be3ce 100644 --- a/contrib/sip2/sip2_client.py +++ b/contrib/sip2/sip2_client.py @@ -103,44 +103,48 @@ class SIP2Client(object): return data - def login(self, username, password, institution): + def login(self, script, username, password, institution): client = self class LoginTask(constrictor.task.Task): + ''' login occurs within a thread lock to allow for + complete login before new logins are attempted ''' def __init__(self): constrictor.task.Task.__init__(self, self.__class__.__name__) def run(self, **kw): + resp = None + script.lock.acquire() + try: + resp = self.send_login() + finally: + script.lock.release() + + return resp + + def send_login(self): + log.log_info("LoginTask: %s %s %s" % (username, password, institution)) msg = '9300CN%s|CO%s|CP%s|' % (username, password, institution) - for i in range(3): - - client.send_msg(msg) - data = client.recv_msg() + client.send_msg(msg) + data = client.recv_msg() - if data is None: - # let's start over and try again - time.sleep(random.random() / 100) - client.disconnect() - client.init_socket() - continue + if data is None: + log.log_error("SIP2 login failed with no server response") + return False - if data[:3] == '941': - log.log_info("SIP2 login OK") - return True + elif data[:3] == '941': + log.log_info("SIP2 login OK") + return True - else: - log.log_error("SIP2 login failed: %s" % data) - return False - - log.log_error("SIP2 login failed with no server response") - return False + else: + log.log_error("SIP2 login failed: %s" % data) + return False - time.sleep(random.random() / 100) # reduce the chance of initial login collisions return LoginTask().start() def item_info_request(self, institution, copy_barcode): diff --git a/contrib/sip2/sip2_item_info_endurance.py b/contrib/sip2/sip2_item_info_endurance.py index 3774fba17..36c6c260b 100644 --- a/contrib/sip2/sip2_item_info_endurance.py +++ b/contrib/sip2/sip2_item_info_endurance.py @@ -13,6 +13,7 @@ # GNU General Public License for more details. # ----------------------------------------------------------------------- +import time import constrictor.script import constrictor.properties import constrictor.log as log @@ -32,17 +33,44 @@ class SIP2ItemInfoEnduranceScript(constrictor.script.Script): institution = props.get_property('sip2.institution') server = props.get_property('sip2.server') port = int(props.get_property('sip2.port')) - barcodes = props.get_property('sip2.copyBarcodes').split(',') - copy_barcode = barcodes[constrictor.script.ScriptThread.get_thread_id()] + iters = int(props.get_property('sip2.load.iterations')) or 10 + delay = props.get_property('sip2.load.delay') or 0 + delay = float(delay) / 1000 # milliseconds + + log.log_info( + "SIP2ItemInfoEndurance iterations=%d delay=%f" % ( + iters, delay)) client = sip2_client.SIP2Client(server, port) - client.init_socket() + if not client.init_socket(): + log.log_error("Unable to talk to SIP server at %s" % server) + return + + if not client.login(self, username, password, institution): + log.log_error("SIP login failed user=%s pass=%s institution=%s" % ( + username, password, institution)) + return + + # with this simple loop, threads are sharing barcodes. + # since these are info requests only (i.e. no data is + # affected), that should be OK. + barcode_idx = 0; + barcode_cnt = len(barcodes) + for i in range(iters): + + if barcode_idx == barcode_cnt: barcode_idx = 0 + barcode = barcodes[barcode_idx] + barcode_idx += 1 + + log.log_debug("SIP item_info_request for %s" % barcode) + + if not client.item_info_request(institution, barcode): + log.log_error( + "Error calling item_info_request for '%s'" % barcode) + break - if client.login(username, password, institution): - for i in range(100): - if not client.item_info_request(institution, copy_barcode): - break + if delay: time.sleep(delay) client.disconnect() diff --git a/contrib/sip2/sip2_mixed_batch.py b/contrib/sip2/sip2_mixed_batch.py index 0b1b9bdf9..512e7c018 100644 --- a/contrib/sip2/sip2_mixed_batch.py +++ b/contrib/sip2/sip2_mixed_batch.py @@ -46,7 +46,7 @@ class SIP2MixedBatchScript(constrictor.script.Script): client = sip2_client.SIP2Client(server, port) client.init_socket() - if client.login(username, password, institution): + if client.login(self, username, password, institution): for i in range(100): if not client.item_info_request(institution, copy_barcode): break diff --git a/contrib/sip2/sip2_patron_info_endurance.py b/contrib/sip2/sip2_patron_info_endurance.py index 90c1059af..e9c74d1c8 100644 --- a/contrib/sip2/sip2_patron_info_endurance.py +++ b/contrib/sip2/sip2_patron_info_endurance.py @@ -38,7 +38,7 @@ class SIP2PatronInfoEnduranceScript(constrictor.script.Script): client = sip2_client.SIP2Client(server, port) - if client.init_socket() and client.login(username, password, institution): + if client.init_socket() and client.login(self, username, password, institution): for i in range(100): if not client.patron_info_request(institution, user_barcode): break diff --git a/contrib/sip2/sip2_patron_status_endurance.py b/contrib/sip2/sip2_patron_status_endurance.py index 1ecac40be..61899ad37 100644 --- a/contrib/sip2/sip2_patron_status_endurance.py +++ b/contrib/sip2/sip2_patron_status_endurance.py @@ -41,7 +41,7 @@ class SIP2PatronStatusEnduranceScript(constrictor.script.Script): client = sip2_client.SIP2Client(server, port) - if client.init_socket() and client.login(username, password, institution): + if client.init_socket() and client.login(self, username, password, institution): for i in range(100): if not client.patron_status_request(institution, user_barcode, user_password): break -- 2.11.0