def test_post_session_dispatch_failure(): """ Initially attempts to create a session when there are no VirtualTN's available. The service responds with a 400, and an appropriate message. Attempts again, when there is a VirtualTN in the pool, but reserved, the service will respond again with a 400. After releasing the VirtualTN, the request succesfully posts, and the response is checked for appropriate values. Ensures both session initialization SMS messages have been fired off. """ mock_controller = MockController() app.sms_controller = mock_controller app.sms_controller.resp.append(False) client = app.test_client() test_num = '12223334444' vnum = VirtualTN(test_num) db_session.add(vnum) db_session.commit() resp = client.post('/session', data=json.dumps({'participant_a': '13334445555', 'participant_b': '14445556666'}), content_type='application/json') data = json.loads(resp.data) vnum = VirtualTN.query.filter_by(value=test_num).one() assert resp.status_code == 500 assert vnum.session_id is None assert len(ProxySession.query.all()) == 0 assert data['message'] == "An error occured when requesting against Flowroute's API."
def test_inbound_handler_expired_session(fake_app, valid_session): """ An inbound message intended for a VirtualTN that is no longer in a session with the sender will no proxy to the other participant. Asserts a system message is fired back to the sender. """ valid_session.expiry_date = datetime.utcnow() db_session.add(valid_session) db_session.commit() expired_session = valid_session client = fake_app.test_client() req = { 'to': expired_session.virtual_TN, 'from': expired_session.participant_a, 'body': 'hello from participant a' } resp = client.post('/', data=json.dumps(req), content_type='application/json') # Indicating that we received the message from Flowroute assert resp.status_code == 200 sms = fake_app.sms_controller.requests[0] msg = "[{}]: {}".format(ORG_NAME.upper(), NO_SESSION_MSG) assert sms.content == msg assert sms.to == expired_session.participant_a assert sms.mfrom == expired_session.virtual_TN
def add_virtual_tn(): """ The VirtualTN resource endpoint for adding VirtualTN's from the pool. """ body = request.json try: value = str(body['value']) assert len(value) <= 18 except (AssertionError, KeyError): raise InvalidAPIUsage("Required argument: 'value' (str, length <= 18)", payload={'reason': 'invalidAPIUsage'}) virtual_tn = VirtualTN(value) try: db_session.add(virtual_tn) db_session.commit() except IntegrityError: db_session.rollback() msg = ("Did not add virtual TN {} to the pool " "-- already exists").format(value) log.info({"message": msg}) raise InvalidAPIUsage("Virtual TN already exists", payload={'reason': 'duplicate virtual TN'}) return Response(json.dumps({ "message": "Successfully added TN to pool", "value": value }), content_type="application/json")
def test_post_session_dispatch_failure(): """ Initially attempts to create a session when there are no VirtualTN's available. The service responds with a 400, and an appropriate message. Attempts again, when there is a VirtualTN in the pool, but reserved, the service will respond again with a 400. After releasing the VirtualTN, the request succesfully posts, and the response is checked for appropriate values. Ensures both session initialization SMS messages have been fired off. """ mock_controller = MockController() app.sms_controller = mock_controller app.sms_controller.resp.append(False) client = app.test_client() test_num = '12223334444' vnum = VirtualTN(test_num) db_session.add(vnum) db_session.commit() resp = client.post('/session', data=json.dumps({ 'participant_a': '13334445555', 'participant_b': '14445556666' }), content_type='application/json') data = json.loads(resp.data) vnum = VirtualTN.query.filter_by(value=test_num).one() assert resp.status_code == 500 assert vnum.session_id is None assert len(ProxySession.query.all()) == 0 assert data[ 'message'] == "An error occured when requesting against Flowroute's API."
def valid_session(virtual_tn): first_num = '12223334444' sec_num = '12223335555' proxy_sess = ProxySession(virtual_tn.value, first_num, sec_num) virtual_tn.session_id = proxy_sess.id db_session.add(virtual_tn) db_session.add(proxy_sess) db_session.commit() return proxy_sess
def test_post_session(): """ Initially attempts to create a session when there are no VirtualTN's available. The service responds with a 400, and an appropriate message. Attempts again, when there is a VirtualTN in the pool, but reserved, the service will respond again with a 400. After releasing the VirtualTN, the request succesfully posts, and the response is checked for appropriate values. Ensures both session initialization SMS messages have been fired off. """ mock_controller = MockController() app.sms_controller = mock_controller client = app.test_client() test_num = '12223334444' resp = client.post('/session', data=json.dumps({ 'participant_a': '13334445555', 'participant_b': '14445556666' }), content_type='application/json') data = json.loads(resp.data) assert resp.status_code == 400 assert 'Could not create a new session -- No virtual TNs available.' in data[ 'message'] vnum = VirtualTN(test_num) vnum.session_id = 'fake_session_id' db_session.add(vnum) db_session.commit() resp = client.post('/session', data=json.dumps({ 'participant_a': '13334445555', 'participant_b': '14445556666' }), content_type='application/json') data = json.loads(resp.data) assert resp.status_code == 400 vnum.session_id = None db_session.add(vnum) db_session.commit() resp = client.post('/session', data=json.dumps({ 'participant_a': '13334445555', 'participant_b': '14445556666' }), content_type='application/json') assert resp.status_code == 200 data = json.loads(resp.data) assert 'Created new session' in data['message'] assert data['virtual_tn'] == vnum.value assert len(mock_controller.requests) == 2 msg = "[{}]: {}".format(ORG_NAME.upper(), SESSION_START_MSG) sms = mock_controller.requests[0] assert sms.content == msg assert data['session_id'] is not None
def test_clean_expired_sessions(fresh_session): """ The 'clean_expired' method does clear expired ProxySessions """ new_tn, new_session = fresh_session new_session.expiry_date = datetime.utcnow() db_session.add(new_session) db_session.commit() sessions = ProxySession.query.all() assert len(sessions) == 1 ProxySession.clean_expired() sessions = ProxySession.query.all() assert new_tn.session_id is None assert len(sessions) == 0
def test_post_session(): """ Initially attempts to create a session when there are no VirtualTN's available. The service responds with a 400, and an appropriate message. Attempts again, when there is a VirtualTN in the pool, but reserved, the service will respond again with a 400. After releasing the VirtualTN, the request succesfully posts, and the response is checked for appropriate values. Ensures both session initialization SMS messages have been fired off. """ mock_controller = MockController() app.sms_controller = mock_controller client = app.test_client() test_num = '12223334444' resp = client.post('/session', data=json.dumps({'participant_a': '13334445555', 'participant_b': '14445556666'}), content_type='application/json') data = json.loads(resp.data) assert resp.status_code == 400 assert 'Could not create a new session -- No virtual TNs available.' in data['message'] vnum = VirtualTN(test_num) vnum.session_id = 'fake_session_id' db_session.add(vnum) db_session.commit() resp = client.post('/session', data=json.dumps({'participant_a': '13334445555', 'participant_b': '14445556666'}), content_type='application/json') data = json.loads(resp.data) assert resp.status_code == 400 vnum.session_id = None db_session.add(vnum) db_session.commit() resp = client.post('/session', data=json.dumps({'participant_a': '13334445555', 'participant_b': '14445556666'}), content_type='application/json') assert resp.status_code == 200 data = json.loads(resp.data) assert 'Created new session' in data['message'] assert data['virtual_tn'] == vnum.value assert len(mock_controller.requests) == 2 msg = "[{}]: {}".format(ORG_NAME.upper(), SESSION_START_MSG) sms = mock_controller.requests[0] assert sms.content == msg assert data['session_id'] is not None
def test_get_session(): """ Ensures the '/session' GET method returns json reflecting the state of the database. """ client = app.test_client() test_num_1 = '12223334444' test_num_2 = '12223335555' resp = client.get('/session') data = json.loads(resp.data) assert data['total_sessions'] == 0 assert data['sessions'] == [] sess_1 = ProxySession(test_num_1, 'cust_1_num', 'cust_2_num') sess_2 = ProxySession(test_num_2, 'cust_1_num', 'cust_2_num') db_session.add(sess_1) db_session.add(sess_2) db_session.commit() resp = client.get('/session') data = json.loads(resp.data) assert data['total_sessions'] == 2
def test_virtual_tn_available(tns, available): """ The 'get_next_available' function returns the first non-reserved VirtualTN. """ VirtualTN.query.delete() for num, available in tns.iteritems(): new_tn = VirtualTN(num) if not available: new_tn.session_id = 'active_session_id' db_session.add(new_tn) db_session.commit() available_tn = VirtualTN.get_next_available() if not available: assert available_tn is None else: for num, available in tns.iteritems(): if available: assert available_tn.value == str(num) return
def test_virtual_tn_available(tns, available): """ The 'get_next_available' function returns the first non-reserved VirtualTN. """ VirtualTN.query.delete() for num, available in tns.iteritems(): new_tn = VirtualTN(num) if not available: new_tn.session_id = "active_session_id" db_session.add(new_tn) db_session.commit() available_tn = VirtualTN.get_next_available() if not available: assert available_tn is None else: for num, available in tns.iteritems(): if available: assert available_tn.value == str(num) return
def test_delete_tn(): """ Creates a new virtual tn attached to a session, and requests to delete that number which is an illegal operation. The VirtualTN is then released, and the request is made again - this time succeeding. """ client = app.test_client() test_num = '12223334444' session = ProxySession(test_num, '12223334444', '12223335555', expiry_window=None) vnum = VirtualTN(test_num) vnum.session_id = 'fake_session_id' db_session.add(session) db_session.add(vnum) db_session.commit() resp = client.delete('/tn', data=json.dumps({'value': test_num}), content_type='application/json') data = json.loads(resp.data) assert data['status'] == 'failed' assert "Cannot delete the number." in data['message'] assert session.id in data['message'] assert resp.status_code == 400 db_session.delete(session) vnum.session_id = None db_session.add(vnum) db_session.commit() resp = client.delete('/tn', data=json.dumps({'value': test_num}), content_type='application/json') data = json.loads(resp.data) assert 'Successfully removed TN from pool' in data['message'] assert resp.status_code == 200
def add_virtual_tn(): """ The VirtualTN resource endpoint for adding VirtualTN's from the pool. """ body = request.json try: value = str(body["value"]) assert len(value) <= 18 except (AssertionError, KeyError): raise InvalidAPIUsage("Required argument: 'value' (str, length <= 18)", payload={"reason": "invalidAPIUsage"}) virtual_tn = VirtualTN(value) try: db_session.add(virtual_tn) db_session.commit() except IntegrityError: db_session.rollback() msg = ("Did not add virtual TN {} to the pool " "-- already exists").format(value) log.info({"message": msg}) raise InvalidAPIUsage("Virtual TN already exists", payload={"reason": "duplicate virtual TN"}) return Response( json.dumps({"message": "Successfully added TN to pool", "value": value}), content_type="application/json" )
def test_get_tns(): """ Adds two virtual numbers to the database, one reserved in a session and one free. The '/tn' GET route is requested to and assertions are made that the data returned reflects the state of the virtual tn's. """ client = app.test_client() num_1 = '12347779999' num_2 = '12347778888' vnum1 = VirtualTN(num_1) vnum2 = VirtualTN(num_2) vnum2.session_id = 'aaaaa' db_session.add(vnum1) db_session.add(vnum2) db_session.commit() resp = client.get('/tn') assert resp.status_code == 200 data = json.loads(resp.data) assert len(data['virtual_tns']) == 2 assert data['available'] == 1 assert data['in_use'] == 1 assert data['pool_size'] == 2
def test_delete_session(): """ Initially tries to delete a session from an id that is unknown. The service responds with a 404, and helpful message. A session is created an persisted to the database. A delete request for that session is executed, and SMS's are dispatched to the participants. """ mock_controller = MockController() app.sms_controller = mock_controller client = app.test_client() resp = client.delete('/session', data=json.dumps({'session_id': 'fake_id'}), content_type='application/json') data = json.loads(resp.data) assert resp.status_code == 404 msg = ("ProxySession {} could not be deleted because" " it does not exist".format('fake_id')) assert data['message'] == msg test_num_1 = '12223334444' vnum_1 = VirtualTN(test_num_1) sess_1 = ProxySession(test_num_1, 'cust_1_num', 'cust_2_num') vnum_1.session_id = sess_1.id db_session.add(sess_1) db_session.add(vnum_1) db_session.commit() resp = client.delete('/session', data=json.dumps({'session_id': sess_1.id}), content_type='application/json') assert resp.status_code == 200 data = json.loads(resp.data) assert data['message'] == 'Successfully ended the session.' assert data['session_id'] == sess_1.id sms = mock_controller.requests[0] msg = "[{}]: {}".format(ORG_NAME.upper(), SESSION_END_MSG) assert sms.content == msg assert len(mock_controller.requests) == 2
def test_inbound_handler_expired_session(fake_app, valid_session): """ An inbound message intended for a VirtualTN that is no longer in a session with the sender will no proxy to the other participant. Asserts a system message is fired back to the sender. """ valid_session.expiry_date = datetime.utcnow() db_session.add(valid_session) db_session.commit() expired_session = valid_session client = fake_app.test_client() req = {'to': expired_session.virtual_TN, 'from': expired_session.participant_a, 'body': 'hello from participant a'} resp = client.post('/', data=json.dumps(req), content_type='application/json') # Indicating that we received the message from Flowroute assert resp.status_code == 200 sms = fake_app.sms_controller.requests[0] msg = "[{}]: {}".format(ORG_NAME.upper(), NO_SESSION_MSG) assert sms.content == msg assert sms.to == expired_session.participant_a assert sms.mfrom == expired_session.virtual_TN
def fresh_session(): """ Clears out any outstanding rows in the VirtualTN and ProxySession tables. Creates and returns a linked VirtualTN and ProxySession. """ VirtualTN.query.delete() ProxySession.query.delete() new_tn = VirtualTN("1234567897") db_session.add(new_tn) db_session.commit() new_session = ProxySession(new_tn.value, "12223334444", "12223335555", expiry_window=1) new_tn.session_id = new_session.id db_session.add(new_tn) db_session.add(new_session) db_session.commit() return new_tn, new_session
def fresh_session(): """ Clears out any outstanding rows in the VirtualTN and ProxySession tables. Creates and returns a linked VirtualTN and ProxySession. """ VirtualTN.query.delete() ProxySession.query.delete() new_tn = VirtualTN('1234567897') db_session.add(new_tn) db_session.commit() new_session = ProxySession(new_tn.value, '12223334444', '12223335555', expiry_window=1) new_tn.session_id = new_session.id db_session.add(new_tn) db_session.add(new_session) db_session.commit() return new_tn, new_session
def add_proxy_session(): """ The ProxySession resource endpoint for adding a new ProxySession to the pool. """ body = request.json try: participant_a = body['participant_a'] participant_b = body['participant_b'] assert len(participant_a) <= 18 assert len(participant_b) <= 18 except (AssertionError, KeyError): raise InvalidAPIUsage( ("Required argument: 'participant_a' (str, length <= 18)" ", 'participant_b' (str, length <= 18)"), payload={'reason': 'invalidAPIUsage'}) if 'expiry_window' in body: expiry_window = body['expiry_window'] else: expiry_window = None # Release any VirtualTNs from expired ProxySessions back to the pool ProxySession.clean_expired() virtual_tn = VirtualTN.get_next_available() if virtual_tn is None: msg = "Could not create a new session -- No virtual TNs available." log.critical({"message": msg, "status": "failed"}) return Response(json.dumps({ "message": msg, "status": "failed" }), content_type="application/json", status=400) else: session = ProxySession(virtual_tn.value, participant_a, participant_b, expiry_window) try: virtual_tn.session_id = session.id db_session.add(session) db_session.add(virtual_tn) db_session.commit() except IntegrityError: db_session.rollback() msg = "There were two sessions attempting to reserve the same virtual tn. Please retry." log.error({"message": msg, "status": "failed"}) return Response(json.dumps({ "message": msg, "status": "failed" }), content_type="application/json", status=500) expiry_date = session.expiry_date.strftime( '%Y-%m-%d %H:%M:%S') if session.expiry_date else None recipients = [participant_a, participant_b] try: send_message(recipients, virtual_tn.value, SESSION_START_MSG, session.id, is_system_msg=True) except InternalSMSDispatcherError as e: db_session.delete(session) virtual_tn.session_id = None db_session.add(virtual_tn) db_session.commit() raise e msg = "ProxySession {} started with participants {} and {}".format( session.id, participant_a, participant_b) log.info({"message": msg, "status": "succeeded"}) return Response(json.dumps({ "message": "Created new session", "status": "succeeded", "session_id": session.id, "expiry_date": expiry_date, "virtual_tn": virtual_tn.value, "participant_a": participant_a, "participant_b": participant_b }), content_type="application/json")
def add_proxy_session(): """ The ProxySession resource endpoint for adding a new ProxySession to the pool. """ body = request.json try: participant_a = body["participant_a"] participant_b = body["participant_b"] assert len(participant_a) <= 18 assert len(participant_b) <= 18 except (AssertionError, KeyError): raise InvalidAPIUsage( ("Required argument: 'participant_a' (str, length <= 18)" ", 'participant_b' (str, length <= 18)"), payload={"reason": "invalidAPIUsage"}, ) if "expiry_window" in body: expiry_window = body["expiry_window"] else: expiry_window = None # Release any VirtualTNs from expired ProxySessions back to the pool ProxySession.clean_expired() virtual_tn = VirtualTN.get_next_available() if virtual_tn is None: msg = "Could not create a new session -- No virtual TNs available." log.critical({"message": msg, "status": "failed"}) return Response(json.dumps({"message": msg, "status": "failed"}), content_type="application/json", status=400) else: session = ProxySession(virtual_tn.value, participant_a, participant_b, expiry_window) try: virtual_tn.session_id = session.id db_session.add(session) db_session.add(virtual_tn) db_session.commit() except IntegrityError: db_session.rollback() msg = "There were two sessions attempting to reserve the same virtual tn. Please retry." log.error({"message": msg, "status": "failed"}) return Response( json.dumps({"message": msg, "status": "failed"}), content_type="application/json", status=500 ) expiry_date = session.expiry_date.strftime("%Y-%m-%d %H:%M:%S") if session.expiry_date else None recipients = [participant_a, participant_b] try: send_message(recipients, virtual_tn.value, SESSION_START_MSG, session.id, is_system_msg=True) except InternalSMSDispatcherError as e: db_session.delete(session) virtual_tn.session_id = None db_session.add(virtual_tn) db_session.commit() raise e msg = "ProxySession {} started with participants {} and {}".format(session.id, participant_a, participant_b) log.info({"message": msg, "status": "succeeded"}) return Response( json.dumps( { "message": "Created new session", "status": "succeeded", "session_id": session.id, "expiry_date": expiry_date, "virtual_tn": virtual_tn.value, "participant_a": participant_a, "participant_b": participant_b, } ), content_type="application/json", )
def virtual_tn(): virtual_tn = VirtualTN('12069992222') db_session.add(virtual_tn) db_session.commit() return virtual_tn