def test_handle_message_no_organizers(send_sms, database): create_event() with pytest.raises(smschat.NoOrganizersAvailable): smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello") send_sms.assert_not_called()
def test_handle_message_no_organizers(send_sms, database): create_event() with pytest.raises(smschat.NoOrganizersAvailable): smschat.handle_message("1234", "5678", "Hello") send_sms.assert_not_called()
def test_handle_message_reply(send_sms, database): event = create_event() create_organizers(event) create_relays() # Send initial message to establish the chat. smschat.handle_message("1234", "5678", "Hello") # Reset the mock for send_sms send_sms.reset_mock() # Send a reply from one of the organizers. smschat.handle_message("101", "1111", "Goodbye") # Two messages should have been sent. One to the reporter, and one to the # other verified member. # The sender should be the hotline number for the reporter and the *first* # relay number (1111) for the member. assert send_sms.call_count == 2 send_sms.assert_has_calls( [ mock.call(sender="5678", to="1234", message="Bob: Goodbye"), mock.call(sender="1111", to="202", message="Bob: Goodbye"), ] )
def test_organizer_in_two_events(send_sms, database): """Tests the case where an organizer is in two different events. This causes issues with a naive relay assignment algorithm that will try to assign a relay used in event one for event two, leading to a database error. The second event should get a unique relay number, and having an organizer in both effectively reduces the available number of relays. """ event_one = create_event() event_two = create_event(name=EVENT_NAME_2, number=EVENT_NUMBER_2) create_organizers(event_one) create_organizers(event_two) create_relays() smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello") senders = set([call[2]["sender"] for call in send_sms.mock_calls]) assert senders == set([EVENT_NUMBER, RELAY_NUMBER]) # This should still work and should assign a different relay than the one above. smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER_2, "Hello") senders = set([call[2]["sender"] for call in send_sms.mock_calls]) assert senders == set( [EVENT_NUMBER, EVENT_NUMBER_2, RELAY_NUMBER, RELAY_NUMBER_2])
def test_handle_message_reply(send_sms, database): event = create_event() create_organizers(event) create_relays() create_chatroom(send_sms) # Send a reply from one of the organizers. smschat.handle_message(BOB_ORGANIZER_NUMBER, RELAY_NUMBER, "Goodbye") # Two messages should have been sent. One to the reporter, and one to the # other verified member. # The sender should be the hotline number for the reporter and the *first* # relay number (1111) for the member. assert send_sms.call_count == 2 send_sms.assert_has_calls([ mock.call( sender=EVENT_NUMBER, to=REPORTER_NUMBER, message=f"{BOB_ORGANIZER_NAME}: Goodbye", ), mock.call( sender=RELAY_NUMBER, to=ALICE_ORGANIZER_NUMBER, message=f"{BOB_ORGANIZER_NAME}: Goodbye", ), ])
def create_chatroom(send_sms, number=EVENT_NUMBER): # Send initial message to establish the chat. smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello") # Reset the mock for send_sms, because it's called # indirectly while creating the chatroom send_sms.reset_mock()
def test_handle_message_new_chat(send_sms, database): event = create_event() create_organizers(event) create_relays() smschat.handle_message("1234", "5678", "Hello") # A total of 5 messages: # The first should acknolwege the reporter. # The next two should have been sent to the two verified organizers to # introduce the chat. # The last two should relay the reporter's message. assert send_sms.call_count == 5 send_sms.assert_has_calls( [ mock.call( sender="5678", to="1234", message="You have started a new chat with the organizers of Test event.", ), # The sender should be the *first available* relay number (1111) mock.call( sender="1111", to="101", message="This is the beginning of a new chat for Test event, the last 4 digits of the reporters number are 1234.", ), mock.call( sender="1111", to="202", message="This is the beginning of a new chat for Test event, the last 4 digits of the reporters number are 1234.", ), mock.call(sender="1111", to="101", message="Reporter: Hello"), mock.call(sender="1111", to="202", message="Reporter: Hello"), ] ) # The database should have an entry for this chat. assert db.Chatroom.select().count() == 1 # And three entries for the connections, as there are three people in the # chat. room = db.Chatroom.get() connections = ( db.ChatroomConnection.select() .where(db.ChatroomConnection.chatroom == room) .order_by(db.ChatroomConnection.user_number) ) assert len(connections) == 3 assert connections[0].user_name == "Bob" assert connections[0].user_number == "101" assert connections[0].relay_number == "1111" assert connections[1].user_name == "Reporter" assert connections[1].user_number == "1234" assert connections[1].relay_number == "5678" assert connections[2].user_name == "Alice" assert connections[2].user_number == "202" assert connections[2].relay_number == "1111"
def test_handle_new_chat_after_stop_reply(send_sms, database): event = create_event() create_organizers(event) create_relays() create_chatroom(send_sms) # Verify a room currently exists for the reporter. initial_chat = highlevel.find_smschat_by_user_and_relay_numbers( REPORTER_NUMBER, EVENT_NUMBER) assert initial_chat # Verify the room no longer exists after reporter opts-out by texting stop. smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "STOP") assert not highlevel.find_smschat_by_user_and_relay_numbers( REPORTER_NUMBER, EVENT_NUMBER) # Send a new message from the reporter to re-establish the chat. create_chatroom(send_sms) # Verify a new room is recreated for the reporter under a new relay number. new_chat = highlevel.find_smschat_by_user_and_relay_numbers( REPORTER_NUMBER, EVENT_NUMBER) assert new_chat assert new_chat.id != initial_chat.id assert new_chat.relay_number != initial_chat.relay_number # Opt-out again, verify the room no longer exists. smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "STOP") assert not highlevel.find_smschat_by_user_and_relay_numbers( REPORTER_NUMBER, EVENT_NUMBER) # Verify the new relay number was used for the messages. assert send_sms.call_count == 3 send_sms.assert_has_calls([ mock.call( sender=new_chat.relay_number, to=BOB_ORGANIZER_NUMBER, message= f"{REPORTER_NAME}: This participant has chosen to leave the chat.", ), mock.call( sender=new_chat.relay_number, to=ALICE_ORGANIZER_NUMBER, message= f"{REPORTER_NAME}: This participant has chosen to leave the chat.", ), mock.call( sender=EVENT_NUMBER, to=REPORTER_NUMBER, message= "You've been successfully unsubscribed, you'll no longer receive messages from this number.", ), ])
def inbound_sms(): message = flask.request.get_json() user_number = lowlevel.normalize_e164_number(message["msisdn"]) relay_number = lowlevel.normalize_e164_number(message["to"]) message_text = message["text"] # Maybe handle verification, if this is a response to a verification message. if verification.maybe_handle_verification(user_number, message_text): return "", 204 # It's not verification, so hand it off to SMS chat try: smschat.handle_message(user_number, relay_number, message_text) except smschat.SmsChatError as err: smschat.handle_sms_chat_error(err, user_number, relay_number) return "", 204
def test_handle_message_no_event(send_sms, database): with pytest.raises(smschat.EventDoesNotExist): smschat.handle_message("1234", "5678", "Hello") send_sms.assert_not_called()
def test_handle_message_no_event(send_sms, database): with pytest.raises(smschat.EventDoesNotExist): smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello") send_sms.assert_not_called()
def test_handle_stop_reply(send_sms, database): event = create_event() create_organizers(event) create_relays() create_chatroom(send_sms) # Verify a room currently exists for the reporter, and is deleted after the # reporter opts-out by texting stop. assert highlevel.find_smschat_by_user_and_relay_numbers( REPORTER_NUMBER, EVENT_NUMBER) smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "STOP") assert not highlevel.find_smschat_by_user_and_relay_numbers( REPORTER_NUMBER, EVENT_NUMBER) # Three messages should have been sent. One for each of the two organizers, # notifying them that the reporter has left the chat, and one to the reporter, # to acknowledge that they opted out. assert send_sms.call_count == 3 send_sms.assert_has_calls([ mock.call( sender=RELAY_NUMBER, to=BOB_ORGANIZER_NUMBER, message= f"{REPORTER_NAME}: This participant has chosen to leave the chat.", ), mock.call( sender=RELAY_NUMBER, to=ALICE_ORGANIZER_NUMBER, message= f"{REPORTER_NAME}: This participant has chosen to leave the chat.", ), mock.call( sender=EVENT_NUMBER, to=REPORTER_NUMBER, message= "You've been successfully unsubscribed, you'll no longer receive messages from this number.", ), ]) # Reset the mock. send_sms.reset_mock() # Verify a room currently exists for this responder, and is deleted after the # responder opts-out by texting stop. assert highlevel.find_smschat_by_user_and_relay_numbers( BOB_ORGANIZER_NUMBER, RELAY_NUMBER) smschat.handle_message(BOB_ORGANIZER_NUMBER, RELAY_NUMBER, "Stop") assert not highlevel.find_smschat_by_user_and_relay_numbers( BOB_ORGANIZER_NUMBER, RELAY_NUMBER) # Two messages should have been sent. One to the remaining organizer, # notifying them that the Bob has left the chat, and one to Bob, # to acknowledge that they opted out. assert send_sms.call_count == 2 send_sms.assert_has_calls([ mock.call( sender=RELAY_NUMBER, to=ALICE_ORGANIZER_NUMBER, message= f"{BOB_ORGANIZER_NAME}: This participant has chosen to leave the chat.", ), mock.call( sender=RELAY_NUMBER, to=BOB_ORGANIZER_NUMBER, message= "You've been successfully unsubscribed, you'll no longer receive messages from this number.", ), ])
def test_handle_message_new_chat(send_sms, database): event = create_event() create_organizers(event) create_relays() smschat.handle_message(REPORTER_NUMBER, EVENT_NUMBER, "Hello") # A total of 5 messages: # The first should acknowledge the reporter. # The next two should have been sent to the two verified organizers to # introduce the chat. # The last two should relay the reporter's message. assert send_sms.call_count == 6 send_sms.assert_has_calls([ mock.call( sender=EVENT_NUMBER, to=REPORTER_NUMBER, message= f"You have started a new chat with the organizers of {EVENT_NAME}.", ), # The reporter should get a notice about how to opt out. mock.call( sender=EVENT_NUMBER, to=REPORTER_NUMBER, message= "Reply STOP at any time to opt-out of receiving messages from this conversation.", ), # The sender should be the *first available* relay number (1111) mock.call( sender=RELAY_NUMBER, to=BOB_ORGANIZER_NUMBER, message= f"This is the beginning of a new chat for {EVENT_NAME}, the last 4 digits of the reporter's number are {REPORTER_NUMBER}. " "Reply STOP at any time to opt-out of receiving messages from this conversation.", ), mock.call( sender=RELAY_NUMBER, to=ALICE_ORGANIZER_NUMBER, message= f"This is the beginning of a new chat for {EVENT_NAME}, the last 4 digits of the reporter's number are {REPORTER_NUMBER}. " "Reply STOP at any time to opt-out of receiving messages from this conversation.", ), mock.call( sender=RELAY_NUMBER, to=BOB_ORGANIZER_NUMBER, message=f"{REPORTER_NAME}: Hello", ), mock.call( sender=RELAY_NUMBER, to=ALICE_ORGANIZER_NUMBER, message=f"{REPORTER_NAME}: Hello", ), ]) # The database should have an entry for this chat. assert db.SmsChat.select().count() == 1 # And three entries for the connections, as there are three people in the # chat. room = db.SmsChat.get() connections = (db.SmsChatConnection.select().where( db.SmsChatConnection.smschat == room).order_by( db.SmsChatConnection.user_number)) assert len(connections) == 3 assert connections[0].user_name == BOB_ORGANIZER_NAME assert connections[0].user_number == BOB_ORGANIZER_NUMBER assert connections[0].relay_number == RELAY_NUMBER assert connections[1].user_name == REPORTER_NAME assert connections[1].user_number == REPORTER_NUMBER assert connections[1].relay_number == EVENT_NUMBER assert connections[2].user_name == ALICE_ORGANIZER_NAME assert connections[2].user_number == ALICE_ORGANIZER_NUMBER assert connections[2].relay_number == RELAY_NUMBER