diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..52a6fa8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.txt +*.pyc +*.db diff --git a/E-Commerce_App/catalog/catalog.py b/E-Commerce_App/catalog/catalog.py index a885059..d2a4c3d 100755 --- a/E-Commerce_App/catalog/catalog.py +++ b/E-Commerce_App/catalog/catalog.py @@ -5,116 +5,165 @@ sys.path.insert(0, '../../http/core') import rlfi_decorator + +########################## +# FLASK INITIALIZATION # +########################## app = Flask(__name__) + +########### +# DB UP # +########### # Set up database with one item in it def db_up(): - try: - conn = sqlite3.connect('items.db') - except Error as e: - print(e) + try: + conn = sqlite3.connect('items.db') + except Error as e: + print(e) - c = conn.cursor() - c.execute("CREATE TABLE IF NOT EXISTS items(id integer primary key, title text, group_id integer, seller_id integer, price real, shipping_cost real)") - conn.commit() + c = conn.cursor() + c.execute("CREATE TABLE IF NOT EXISTS items(id integer primary key, title text, group_id integer, seller_id integer, price real, shipping_cost real)") + conn.commit() - c.execute('SELECT count(*) from items') - count = c.fetchone()[0] + c.execute('SELECT count(*) from items') + count = c.fetchone()[0] - if count == 0: - item1 = (1, u'Mac book cover', 1, 1, 10.99, 5.95) - c.execute('INSERT INTO items VALUES(?,?,?,?,?,?)', item1) - conn.commit() + if count == 0: + item1 = (1, u'Mac book cover', 1, 1, 10.99, 5.95) + c.execute('INSERT INTO items VALUES(?,?,?,?,?,?)', item1) + conn.commit() + + conn.close() - conn.close() +############### +# NOT FOUND # +############### +# service for returning error response @app.errorhandler(404) def not_found(error): - return make_response(jsonify({'error': 'Not found'}), 404) + return make_response(jsonify({'error': 'Not found'}), 404) + +############### +# GET ITEMS # +############### +# service for retrieving item information from the catalog @app.route('/catalog/get/', methods=['GET']) @rlfi_decorator.rlfi("get_items") def get_items(item_id): - conn = sqlite3.connect('items.db') - c = conn.cursor() - c.execute('SELECT title, price from items where id =:item', {"item": item_id}) - result = c.fetchone() - if result is None: - abort(404) - else: - return jsonify({result[0]: result[1]}) - conn.close() - + conn = sqlite3.connect('items.db') + c = conn.cursor() + c.execute('SELECT title, price from items where id =:item', {"item": item_id}) + result = c.fetchone() + if result is None: + abort(404) + else: + return jsonify({result[0]: result[1]}) + conn.close() + + +############### +# ADD ITEMS # +############### +# service for adding new items to the catalog @app.route('/catalog/add', methods=['POST']) @rlfi_decorator.rlfi("add_items") def add_items(): - conn = sqlite3.connect('items.db') - c=conn.cursor() - if not request.json: - abort(400) - item = (request.json['id'], request.json['title'], request.json['group_id'], request.json['seller_id'], request.json['price'], request.json['shipping_cost']) - c.execute('INSERT INTO items VALUES(?,?,?,?,?,?)', item) - conn.commit() + conn = sqlite3.connect('items.db') + c=conn.cursor() + if not request.json: + abort(400) + + item = (request.json['id'], request.json['title'], request.json['group_id'], request.json['seller_id'], request.json['price'], request.json['shipping_cost']) + c.execute('INSERT INTO items VALUES(?,?,?,?,?,?)', item) + conn.commit() + + c.execute('select * from items') + result = jsonify(c.fetchall()) + conn.close() + + return result, 201 - c.execute('select * from items') - result = jsonify(c.fetchall()) - conn.close() - return result, 201 +################## +# DELETE ITEMS # +################## +# service for deleting existing items in the catalog @app.route('/catalog/delete/', methods=['DELETE']) @rlfi_decorator.rlfi("delete_items") def delete_items(item_id): - conn = sqlite3.connect('items.db') - c = conn.cursor() - c.execute('SELECT * from items where id=:item', {"item": item_id}) - result = c.fetchone() - if result is None: - abort(404) - else: - c.execute('delete from items where id=:item', {"item": item_id}) - conn.commit() - conn.close() - return jsonify({'Result':True}) + conn = sqlite3.connect('items.db') + c = conn.cursor() + c.execute('SELECT * from items where id=:item', {"item": item_id}) + result = c.fetchone() + + if result is None: + abort(404) + + else: + c.execute('delete from items where id=:item', {"item": item_id}) + conn.commit() + + conn.close() + + return jsonify({'Result':True}) + +################## +# UPDATE ITEMS # +################## +# service for updating existing items in the catalog @app.route('/catalog/update/', methods=['PUT']) @rlfi_decorator.rlfi("update_items") def update_items(item_id): - conn = sqlite3.connect('items.db') - c = conn.cursor() + conn = sqlite3.connect('items.db') + c = conn.cursor() - flag = 0 - cmd = "update items set " - if not request.json: - abort(400) + flag = 0 + cmd = "update items set " + if not request.json: + abort(400) - if "title" in request.json: - abort(400) - else: - flag = 1 - cmd += "title=\"" + request.json['title'] + "\" " + if "title" in request.json: + abort(400) - if "group_id" in request.json: - abort(400) + else: + flag = 1 + cmd += "title=\"" + request.json['title'] + "\" " - if "seller_id" in request.json: - abort(400) + if "group_id" in request.json: + abort(400) - if "price" in request.json: - if flag: - cmd +=", " - flag = 1 - cmd += "price=" + str(request.json['price']) + " " + if "seller_id" in request.json: + abort(400) - if "shipping_cost" in request.json: - abort(400) + if "price" in request.json: + if flag: + cmd +=", " + flag = 1 + cmd += "price=" + str(request.json['price']) + " " - cmd += "where id=" + str(item_id) - c.execute(cmd) - conn.commit() + if "shipping_cost" in request.json: + abort(400) + + cmd += "where id=" + str(item_id) + c.execute(cmd) + conn.commit() - conn.close() - return jsonify({'Result':True}) + conn.close() + return jsonify({'Result':True}) + +######################### +# THREAD OF EXECUTION # +######################### if __name__ == '__main__': conn = db_up() app.run(host='localhost', port=6000, debug=True) + + +######### +# EOF # +######### diff --git a/E-Commerce_App/order_management/main.py b/E-Commerce_App/order_management/main.py index 387f8df..7a92550 100644 --- a/E-Commerce_App/order_management/main.py +++ b/E-Commerce_App/order_management/main.py @@ -2,15 +2,18 @@ from flask_sqlalchemy import SQLAlchemy import os import json -import rlfi_decorator import unittest from werkzeug.datastructures import Headers import signal import requests +import sys +sys.path.insert(0, '../../http/core') +import rlfi_decorator + def handler(signum, frame): - raise Exception("timed out") + raise Exception("timed out") signal.signal(signal.SIGALRM, handler) @@ -19,90 +22,144 @@ def handler(signum, frame): app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'test.db') db = SQLAlchemy(app) -class Users(db.Model): - UserID = db.Column(db.Integer, primary_key=True) - firstname = db.Column(db.String(80)) - lastname = db.Column(db.String(80)) -class Orders(db.Model): - OrderID = db.Column(db.Integer, primary_key=True) - UserID = db.Column(db.Integer, db.ForeignKey(Users.UserID)) - shipinfo = db.Column(db.String(80)) - paytype = db.Column(db.String(80)) +################# +# CLASS USERS # +################# +# define users table +class Users( db.Model ): + UserID = db.Column(db.Integer, primary_key=True) + firstname = db.Column(db.String(80)) + lastname = db.Column(db.String(80)) + + +################## +# CLASS ORDERS # +################## +# define orders table +class Orders( db.Model ) : + OrderID = db.Column(db.Integer, primary_key=True) + UserID = db.Column(db.Integer, db.ForeignKey(Users.UserID)) + shipinfo = db.Column(db.String(80)) + paytype = db.Column(db.String(80)) - users = db.relationship('Users', foreign_keys='Orders.UserID') + users = db.relationship('Users', foreign_keys='Orders.UserID') +############################ +# MAIN THREAD OF EXECUTION # +############################ +# CREATE DATABASE db.create_all() + +########## +# HOME # +########## +# service for outputting a postivie salutation @app.route("/") -def home(): +def home() : return "Simple Order Management App!" + +############## +# SHIPPING # +############## +# service for handling shipping information @app.route("/orders/shipping", methods=['GET']) @rlfi_decorator.rlfi("shipping") -def shipping(): - if request.method == 'GET': - try: - userid = request.args.get('userid') - orders = Orders.query.filter_by(UserID=userid).all() - ans = [] - for order in orders: - d = {} - d['userid'] = userid - d['shipinfo'] = order.shipinfo - ans.append(d) - return Response(json.dumps(ans), mimetype='application/json'), 200 - except Exception,e: - return str(e), 404 +def shipping() : + if request.method == 'GET': + + try: + userid = request.args.get('userid') + orders = Orders.query.filter_by(UserID=userid).all() + ans = [] + for order in orders: + d = {} + d['userid'] = userid + d['shipinfo'] = order.shipinfo + ans.append(d) + return Response(json.dumps(ans), mimetype='application/json'), 200 + + except Exception,e: + return str(e), 404 + +############# +# PAYMENT # +############# +# service for handling payment information @app.route("/orders/payment", methods=['GET']) @rlfi_decorator.rlfi("payment") def payment(): - if request.method == 'GET': - try: - userid = request.args.get('userid') - orders = Orders.query.filter_by(UserID=userid).all() - ans = [] - for order in orders: - d = {} - d['userid'] = userid - d['paytype'] = order.paytype - ans.append(d) - return Response(json.dumps(ans), mimetype='application/json'), 200 - except Exception,e: - return str(e), 404 + if request.method == 'GET': + try: + userid = request.args.get('userid') + orders = Orders.query.filter_by(UserID=userid).all() + ans = [] + for order in orders: + d = {} + d['userid'] = userid + d['paytype'] = order.paytype + ans.append(d) + return Response(json.dumps(ans), mimetype='application/json'), 200 + + except Exception,e: + return str(e), 404 + + +############# +# SUMMARY # +############# +# service for summarizing an order @app.route("/orders/summary", methods=['GET']) @rlfi_decorator.rlfi("summary") def summary(): - if request.method == 'GET': - try: - userid = request.args.get('userid') - orders = Orders.query.filter_by(UserID=userid).all() - ans = [] - for order in orders: - d = {} - d['userid'] = userid - d['summary'] = "The shipping details are '" + order.shipinfo + "' and payment was done by '" + order.paytype + "'" - ans.append(d) - return Response(json.dumps(ans), mimetype='application/json'), 200 - except Exception,e: - return str(e), 404 + if request.method == 'GET': + + try: + userid = request.args.get('userid') + orders = Orders.query.filter_by(UserID=userid).all() + ans = [] + for order in orders: + d = {} + d['userid'] = userid + d['summary'] = "The shipping details are '" + order.shipinfo + "' and payment was done by '" + order.paytype + "'" + ans.append(d) + return Response(json.dumps(ans), mimetype='application/json'), 200 + + except Exception,e: + return str(e), 404 + +############ +# CREATE # +############ +# service for creating new orders @app.route("/orders/create", methods=['POST']) @rlfi_decorator.rlfi("create") def create(): - if request.method == 'POST': - try: - ship = request.form.get('shipinfo') - pay = request.form.get('paytype') - userid = request.form.get('userid') - order = Orders(shipinfo=ship, paytype=pay, UserID=userid) - db.session.add(order) - db.session.commit() - return jsonify ({'msg' : 'success'}), 200 - except Exception,e: - return str(e), 404 + if request.method == 'POST': + try: + ship = request.form.get('shipinfo') + pay = request.form.get('paytype') + userid = request.form.get('userid') + order = Orders(shipinfo=ship, paytype=pay, UserID=userid) + db.session.add(order) + db.session.commit() + return jsonify ({'msg' : 'success'}), 200 + except Exception,e: + return str(e), 404 + +######################### +# THREAD OF EXECUTION # +######################### if __name__ == "__main__": - app.run(debug=True) \ No newline at end of file + app.run(debug=True) + + +######### +# EOF # +######### diff --git a/E-Commerce_App/order_management/test.py b/E-Commerce_App/order_management/test.py index c1018cd..f25f30d 100644 --- a/E-Commerce_App/order_management/test.py +++ b/E-Commerce_App/order_management/test.py @@ -1,56 +1,98 @@ #!flask/bin/python from flask import Flask, request, Response import unittest -import rlfi_decorator from werkzeug.datastructures import Headers import signal import subprocess import requests +# fixed port num +PORT = 500 + + +############# +# HANDLER # +############# def handler(signum, frame): raise Exception("timed out") signal.signal(signal.SIGALRM, handler) -PORT=5000 ## test cases class MyTest(unittest.TestCase): - def test_app0(self): - res = requests.get('http://localhost:'+str(PORT)+'/') - self.assertEqual(res.text, 'Simple Order Management App!', msg='Sad scenes') - - def test_app1 (self): - res = requests.post('http://localhost:'+str(PORT)+'/orders/create', data = {"shipinfo" : "Blah", "paytype" : "CashCard", "userid" : "5", }) - self.assertTrue('success' in res.text, msg='Failure at order creation') - - def test_app2(self): - res = requests.get('http://localhost:'+str(PORT)+'/orders/shipping?userid=5') - self.assertTrue('\"shipinfo\": \"Blah\"' in res.text, msg='Failure at shipping') - - def test_app3(self): - res = requests.get('http://localhost:'+str(PORT)+'/orders/payment?userid=5') - self.assertTrue('\"paytype\": \"CashCard\"' in res.text, msg='Failure at Payment') - - def test_app4(self): - res = requests.get('http://localhost:'+str(PORT)+'/orders/summary?userid=5') - self.assertTrue('userid' in res.text and 'summary' in res.text, msg='Failure at Summary') - - def test_fault1(self): - h = Headers() - h.add("X-B3-Flags", 0) - h.add("X-B3-Sampled", "true") - h.add("X-B3-Spanid", "7c32ff2603f7586f") - h.add("X-B3-Traceid", "4ba9862655d0b76b1709d712d2027505") - h.add("Ot-Baggage-Injectfault", "shipping_delay:10") - - signal.alarm(5) - try: - resp = requests.get('http://localhost:'+str(PORT)+'/orders/shipping?userid=5', headers = h) - assert(False) - except Exception, exc: - assert(True) + ################ + # TEST APP 0 # + ################ + # test salutation + def test_app0(self): + res = requests.get('http://localhost:'+str(PORT)+'/') + self.assertEqual(res.text, 'Simple Order Management App!', msg='Sad scenes') + + + ################ + # TEST APP 1 # + ################ + # test user creation in order management app db + def test_app1 (self): + res = requests.post('http://localhost:'+str(PORT)+'/orders/create', data = {"shipinfo" : "Blah", "paytype" : "CashCard", "userid" : "5", }) + self.assertTrue('success' in res.text, msg='Failure at order creation') + + + ################ + # TEST APP 2 # + ################ + # test shipping info for specific user + def test_app2(self): + res = requests.get('http://localhost:'+str(PORT)+'/orders/shipping?userid=5') + self.assertTrue('\"shipinfo\": \"Blah\"' in res.text, msg='Failure at shipping') + + + ################ + # TEST APP 3 # + ################ + # test payment info for specific user + def test_app3(self): + res = requests.get('http://localhost:'+str(PORT)+'/orders/payment?userid=5') + self.assertTrue('\"paytype\": \"CashCard\"' in res.text, msg='Failure at Payment') + + ################ + # TEST APP 4 # + ################ + # test order summary for specific user + def test_app4(self): + res = requests.get('http://localhost:'+str(PORT)+'/orders/summary?userid=5') + self.assertTrue('userid' in res.text and 'summary' in res.text, msg='Failure at Summary') + + + ################## + # TEST FAULT 1 # + ################## + def test_fault1(self): + h = Headers() + h.add("X-B3-Flags", 0) + h.add("X-B3-Sampled", "true") + h.add("X-B3-Spanid", "7c32ff2603f7586f") + h.add("X-B3-Traceid", "4ba9862655d0b76b1709d712d2027505") + h.add("Ot-Baggage-Injectfault", "shipping_delay:10") + + signal.alarm(5) + try: + resp = requests.get('http://localhost:'+str(PORT)+'/orders/shipping?userid=5', headers = h) + assert(False) + except Exception, exc: + assert(True) + + +######################### +# THREAD OF EXECUTION # +######################### if __name__ == '__main__': unittest.main() + + +######### +# EOF # +######### diff --git a/http/README_COLLECTOR_PY.md b/http/README_COLLECTOR_PY.md new file mode 100644 index 0000000..8e96d29 --- /dev/null +++ b/http/README_COLLECTOR_PY.md @@ -0,0 +1,13 @@ + +1. run $python collector-py.py in a separate window. +2. run $python test_COLLECTOR_PY.py + +IMPORTANT : +allData in collector-py.py collects a list of string representing the dictionaries corresponding to the span dumps from each call to a python microservice method annotated with rlfi_decorator_COLLECTOR_PY. + +HACKS : +1. The process pool in collector-py.py must possess more processes than expected microservice calls. The unused ports should timeout on their own without terminating the execution. + +2. Need to pass the list of port numbers in allData = p.map( serverCommunicators, [5005, 5006, 5007, 5008] ) in collector-py.py + +3. Need to be sure the timeout set in s.settimeout( 100 ) in collector-py.py is sufficiently long to prevent timeouts before all microservices attempt communications. diff --git a/http/collector-python.py b/http/collector-python.py new file mode 100644 index 0000000..c670daa --- /dev/null +++ b/http/collector-python.py @@ -0,0 +1,65 @@ +''' +collector-python.py + Listens for incomming files sent from the rlfi_decorator encompassing + traces for different calls to app microservices written in python. +''' + +from multiprocessing import Pool +import os, socket + +DEBUG = True + + +######################### +# SERVER COMMUNICATOR # +######################### +# based on https://wiki.python.org/moin/TcpCommunication +def serverCommunicators( portNum ) : + + data = [] + + try : + TCP_IP = '127.0.0.1' + #TCP_PORT = 5005 + TCP_PORT = portNum + BUFFER_SIZE = 1024 # sized in bytes + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout( 20 ) + #s.bind((TCP_IP, TCP_PORT)) + s.bind((TCP_IP, TCP_PORT)) + s.listen(1) + + conn, addr = s.accept() + print 'Connection address:', addr + + data = conn.recv(BUFFER_SIZE) + print "os.getpid() = " + str( os.getpid() ) + print "received data:", data + #conn.send(data) # echo + conn.close() + + except socket.timeout : + print "connection timed out for port " + str( portNum ) + + return data + + +############ +# DRIVER # +############ +def driver() : + + # create a pool of processes to listen on different ports for + # incoming data. + # associate each process with a different port number. + p = Pool(5) + allData = p.map( serverCommunicators, [5005, 5006, 5007, 5008] ) + print "allData = " + str( allData ) + + +######################### +# THREAD OF EXECUTION # +######################### +if __name__ == '__main__' : + driver() diff --git a/http/core/rlfi_decorator_COLLECTOR_PY.py b/http/core/rlfi_decorator_COLLECTOR_PY.py new file mode 100755 index 0000000..ecd3020 --- /dev/null +++ b/http/core/rlfi_decorator_COLLECTOR_PY.py @@ -0,0 +1,201 @@ +#!flask/bin/python +from flask import Flask, request, Response +from functools import wraps +import time +from opentracing import Format +from basictracer import BasicTracer +import sys +from werkzeug.datastructures import Headers +import socket + +DEBUG = True + + +##################### +# SAVE NEW HEADER # +##################### +# input service name, base of new header, and fault injection conlcusion +# saves new header to file locally and/or sends file to collector-python.py +def saveNewHeader( portNum, service, newHeader, conclusion ) : + + if DEBUG : + print "-------------------------------" + print "RUNNING SAVE NEW HEADER" + print newHeader + + # complete the new header + newHeader.add( "Decorator-Result", conclusion ) + + # convert to dictionary + headerDict = {} + for header in newHeader : + key = header[0] + val = header[1] + headerDict[ key ] = val + + headerDict[ "ServiceName" ] = service + + if DEBUG : + print "**************************************" + print "headerDict = " + str(headerDict) + print "**************************************" + + # name for save file + filename = "postFI_" + service + "_" + str(time.strftime("%d%b%Y")) + "_" + str(time.strftime("%Hh%Mm%Ss" ) ) + ".txt" + + # open file in this directory + # save dict to file + # close file + #f = open( filename, "w" ) + #f.write( str( headerDict ) ) + #f.close() + + # send dictionary to collector-python.py + clientCommunicator( int( portNum ), str( headerDict ) ) + + +######################### +# CLIENT COMMUNICATOR # +######################### +# based on https://wiki.python.org/moin/TcpCommunication +def clientCommunicator( portNum, msg ) : + + TCP_IP = '127.0.0.1' + #TCP_PORT = 5005 + TCP_PORT = portNum + BUFFER_SIZE = 1024 # sized in bytes + MESSAGE = "Hello, World!" + + if DEBUG : + print "...RUNNING CLIENT COMMUNICATOR..." + print msg + print "sys.getsizeof(msg) = " + str( sys.getsizeof(msg) ) + + numMsgBits = sys.getsizeof(msg) + if numMsgBits > BUFFER_SIZE : + sys.exit( ">>> FATAL ERROR : size of message exceeds buffer size : " + str( numMsgBits ) + " > " + str( BUFFER_SIZE ) ) + + s = socket.socket( socket.AF_INET, socket.SOCK_STREAM ) + s.connect( ( TCP_IP, TCP_PORT ) ) + #s.send(MESSAGEportNum, ) + s.send(msg) + data = s.recv(BUFFER_SIZE) + s.close() + + +########## +# RLFI # +########## +# rfli decorator +def rlfi( name ) : + + ############### + # DECORATOR # + ############### + def decorator( func ) : + + ############# + # WRAPPER # + ############# + def wrapper(*args, **kwargs): + + # ---------------------------------------------------------------- # + # ---------------------------------------------------------------- # + # basicTracer not used + #tracer = BasicTracer() + #tracer.register_required_propagators() + #span_context = tracer.extract( + # format=Format.HTTP_HEADERS, + # carrier=request.headers, + #) + + # ---------------------------------------------------------------- # + # ---------------------------------------------------------------- # + # terrible workaround, because the python opentracing libraries lack a reference implementation + # https://github.com/opentracing/opentracing-python + # (just no-op). I do not have time to write the reference implementation, so we'll manually extract the + # headers here, possibly breaking forward compatibility. + + # ================================================================ # + # prepare the headers to save as the trace for calling this particular service + + # get the complete list of old headers + completeHeader = request.headers + #print "completeHeader = \n" + str( completeHeader ) + + # get port number + portNum = completeHeader.get( "PORTNUM" ) + if not portNum : + portNum = 5005 + + # create the base content for the new header for this call + newHeader = Headers() + for header in completeHeader : + newHeader.add( header[0], header[1] ) + + if DEBUG : + print "newHeader :\n" + str(newHeader) + + # ================================================================ # + # collect fault info from baggage + # fault will be non-empty iff fault injection request exists. + # faults delivered in the form "service1_delay:10" + fault = request.headers.get("Ot-Baggage-Injectfault") + + + # ================================================================ # + # CASE : non-empty fault request + if fault is not None : + service, faults = fault.split("_") # e.g. [ 'service1', 'delay:10' ] + + # ================================================================ # + # make sure the name of the service matches the name of the service targetted for the fault. + # otherwise, ignore the injection. + if service != name : + saveNewHeader( portNum, service, newHeader, "NoFaultInjected" ) + return func(*args, **kwargs) + + else: + if DEBUG : + print "FAULT is " + fault + print newHeader + + f, param = faults.split(":") # e.g. [ 'delay', '10' ] + + # ================================================================ # + # CASE : delay injection + if f == "delay" : + saveNewHeader( portNum, service, newHeader, "InjectedFault" ) # must occur before sleep for some reason? + time.sleep( int( param ) ) + return func(*args, **kwargs) + + # CASE : fault not recognized + # do nothing silently + else: + saveNewHeader( portNum, service, newHeader, "NoFaultInjected" ) + return None + + # CASE : empty fault request + # do nothing silently + else: + saveNewHeader( portNum, "NoService", newHeader, "NoFaultInjected" ) + return func(*args, **kwargs) + # ---------------------------------------------------------------- # + # ^ END OF WARPPER + # ---------------------------------------------------------------- # + + wrapper.func_name = func.func_name + return wrapper + # ---------------------------------------------------------------- # + # ^ END OF DECORATOR + # ---------------------------------------------------------------- # + + return decorator + # ---------------------------------------------------------------- # + # ^ END OF RLFI + # ---------------------------------------------------------------- # + + +######### +# EOF # +######### diff --git a/http/test_COLLECTOR_PY.py b/http/test_COLLECTOR_PY.py new file mode 100755 index 0000000..5f05402 --- /dev/null +++ b/http/test_COLLECTOR_PY.py @@ -0,0 +1,120 @@ +#!flask/bin/python +from flask import Flask, request, Response +#from flask_testing import TestCase +import unittest +from core import rlfi_decorator_COLLECTOR_PY +from werkzeug.datastructures import Headers +import signal +import socket,sys + +DEBUG = True + +############# +# HANDLER # +############# +def handler(signum, frame): + raise Exception("timed out") + +signal.signal(signal.SIGALRM, handler) + + +# GET /service1 HTTP/1.1 +# Host: localhost:8080 +# User-Agent: Go-http-client/1.1 +# Ot-Baggage-Injectfault: service4_delay:10 +# X-B3-Flags: 0 +# X-B3-Sampled: true +# X-B3-Spanid: 7c32ff2603f7586f +# X-B3-Traceid: 4ba9862655d0b76b1709d712d2027505 +# Accept-Encoding: gzip + +## toy flask app, decorated +app = Flask(__name__) +@app.route('/') +@rlfi_decorator_COLLECTOR_PY.rlfi("service1") +def index(): + return "Hello, World!" + + +# trying to repro issue reported by Kamala +@app.route('/foo') +@rlfi_decorator_COLLECTOR_PY.rlfi("service2") +def index2(): + return "Hello, Squirrel" + + +## test cases +class MyTest( unittest.TestCase ) : + + ########### + # SETUP # + ########### + # initialize client + def setUp(self): + app.config['TESTING'] = True + self.client = app.test_client() + return app + + + ############## + # TEST APP # + ############## + # test connection to app + def test_app(self): + resp = self.client.get("/") + assert(resp.status == "200 OK") + + + ################## + # TEST FAULT 1 # + ################## + # test delay injection at app root. + def test_fault1(self): + h = Headers() + h.add("X-B3-Flags", 0) + h.add("X-B3-Sampled", "true") + h.add("X-B3-Spanid", "7c32ff2603f7586f") + h.add("X-B3-Traceid", "4ba9862655d0b76b1709d712d2027505") + h.add("Ot-Baggage-Injectfault", "service1_delay:10") + h.add("PORTNUM", "5006") + + signal.alarm(5) + try: + resp = self.client.get("/", headers = h) # index call + assert(False) + except Exception, exc: + assert(True) + + + ################## + # TEST FAULT 2 # + ################## + # test delay injection at app subdir foo. + def test_fault2(self): + h = Headers() + h.add("X-B3-Flags", 0) + h.add("X-B3-Sampled", "true") + h.add("X-B3-Spanid", "7c32ff2603f7586f") + h.add("X-B3-Traceid", "4ba9862655d0b76b1709d712d2027505") + h.add("Ot-Baggage-Injectfault", "service2_delay:10") + h.add("PORTNUM", "5007") + + signal.alarm(5) + try: + resp = self.client.get("/foo", headers = h) # index2 call + assert(False) + except Exception, exc: + assert(True) + + +######################### +# THREAD OF EXECUTION # +######################### +if __name__ == '__main__': + unittest.main() + + + +######### +# EOF # +#########