def test_merge_overlapping_students_incomplete_contacts(self): """Ensure merging students with overlaps with different contacts.""" from sosbeacon.event.contact_marker import ContactMarker students_1 = { '123': [{ 'name': 'Billy Bob', 'methods': ['324321', '*****@*****.**'] }], '345': [{ 'name': 'Josh Jones', 'methods': ['443241', '*****@*****.**'] }] } students_2 = { '123': [{ 'name': 'Sam Smith', 'methods': ['123432', '*****@*****.**'] }], '345': [{ 'name': 'Jenny Benny', 'methods': ['234232', '*****@*****.**'] }] } left = ContactMarker(students=copy.deepcopy(students_1)) right = ContactMarker(students=copy.deepcopy(students_2)) left.merge(right) for key in students_1: students_1[key].extend(students_2[key]) self.assertEqual(students_1, left.students)
def test_merge_students(self): """Ensure merging students.""" from sosbeacon.event.contact_marker import ContactMarker students_1 = { '123': [{ 'name': 'Sam Smith', 'methods': ['123432', '*****@*****.**'] }], '345': [{ 'name': 'Josh Jones', 'methods': ['443241', '*****@*****.**'] }], '231': [{ 'name': 'Betty Boop', 'methods': ['321133', '*****@*****.**'] }], } students_2 = { 'ABC': [{ 'name': 'Julie James', 'methods': ['5433423', '*****@*****.**'] }], } left = ContactMarker(students=copy.deepcopy(students_1)) right = ContactMarker(students=copy.deepcopy(students_2)) left.merge(right) students_1.update(students_2) self.assertEqual(students_1, left.students)
def test_matching_markers(self, find_markers_for_methods_mock): """Ensure a marker is returned when there are multiple existing markers. """ from google.appengine.ext import ndb from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import get_marker_for_methods from sosbeacon.event.event import Event marker1_key = mock.Mock(spec=ndb.Key) marker1_key.kind.return_value = "ContactMarker" marker1 = ContactMarker(key=marker1_key, short_id='A') marker2_key = mock.Mock(spec=ndb.Key) marker2_key.kind.return_value = "ContactMarker" marker2 = ContactMarker(key=marker2_key, short_id='Z') find_markers_for_methods_mock.return_value = (marker1, marker2) event_key = ndb.Key(Event, 'EVENTKEY') ret_value = get_marker_for_methods(event_key, ['123']) self.assertIn(ret_value, (marker1, marker2))
def setUp(self): from google.appengine.datastore.datastore_stub_util import \ TimeBasedHRConsistencyPolicy from sosbeacon.event.contact_marker import ContactMarker self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.setup_env(app_id='testapp') self.testbed.init_datastore_v3_stub( consistency_policy=TimeBasedHRConsistencyPolicy()) self.testbed.init_memcache_stub() self.marker1 = ContactMarker(id='a', students={'a': 'student_a'}, methods=['method_a']) self.marker2 = ContactMarker( id='b', students={'b': 'student_b'}, methods=['method_b'], ) self.marker3 = ContactMarker( id='c', students={'c': 'student_c'}, methods=['method_c'], ) self.marker4 = ContactMarker( id='d', students={'d': 'student_d'}, methods=['method_d'], )
def test_merge_ack_to_non_ack(self): """Ensure merging acked to non-acked acks.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(acknowledged=False) right = ContactMarker(acknowledged=True) left.merge(right) self.assertTrue(left.acknowledged)
def test_merge_no_students(self): """Ensure merging with no students.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker() right = ContactMarker() left.merge(right) self.assertIsNone(left.students)
def test_merge_different_name(self): """Ensure merging with two different names.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(name='Name 3') right = ContactMarker(name='Name 4') left.merge(right) self.assertEqual('Name 3', left.name)
def test_merge_non_ack(self): """Ensure merging two non-acked doesn't ack.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(acknowledged=False) right = ContactMarker(acknowledged=False) left.merge(right) self.assertFalse(left.acknowledged)
def test_merge_missing_name(self): """Ensure merging missing name with name.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(name='Name 2') right = ContactMarker() left.merge(right) self.assertEqual('Name 2', left.name)
def test_merge_new_name(self): """Ensure merging no name with new name.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker() right = ContactMarker(name='Name 1') left.merge(right) self.assertEqual('Name 1', left.name)
def test_merge_no_names(self): """Ensure merging with no names.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker() right = ContactMarker() left.merge(right) self.assertEqual(None, left.name)
def test_merge_different_short_id(self): """Ensure merging with different short ids.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(short_id='N123') right = ContactMarker(short_id='Z312') left.merge(right) self.assertEqual('N123', left.short_id)
def test_merge_missing_short_id(self): """Ensure merging short id with no short id.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(short_id='N213') right = ContactMarker() left.merge(right) self.assertEqual('N213', left.short_id)
def test_merge_last_viewed_date_with_same(self): """Ensure merging acked with acked preserves ack date.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(last_viewed_date=334) right = ContactMarker(last_viewed_date=334) left.merge(right) self.assertEqual(334, left.last_viewed_date)
def test_merge_last_viewed_date(self): """Ensure merging acked to non-acked sets view date.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(last_viewed_date=0) right = ContactMarker(last_viewed_date=12345) left.merge(right) self.assertEqual(12345, left.last_viewed_date)
def test_merge_unviewed(self): """Ensure merging two non-acked doesn't set view date.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker() right = ContactMarker() left.merge(right) self.assertEqual(0, left.last_viewed_date)
def test_merge_acks(self): """Ensure merging two acked stays acked.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(acknowledged=True) right = ContactMarker(acknowledged=True) left.merge(right) self.assertTrue(left.acknowledged)
def test_merge_last_viewed_date_with_non_acked(self): """Ensure merging non-acked with acked preserves view date.""" from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(last_viewed_date=321123) right = ContactMarker(last_viewed_date=0) left.merge(right) self.assertEqual(321123, left.last_viewed_date)
def test_merge_last_viewed_date_with_larger(self): """Ensure merging more recently acked with earlier acked keeps most recent ack date. """ from sosbeacon.event.contact_marker import ContactMarker left = ContactMarker(last_viewed_date=20) right = ContactMarker(last_viewed_date=200) left.merge(right) self.assertEqual(200, left.last_viewed_date)
def test_merge_no_methods_with_methods(self): """Ensure merging no methods with methods preserves methods.""" from sosbeacon.event.contact_marker import ContactMarker methods = ['123312', '*****@*****.**'] left = ContactMarker() right = ContactMarker(methods=methods[:]) left.merge(right) self.assertEqual(sorted(methods), sorted(left.methods))
def test_merge_same_methods(self): """Ensure merging same methods doesn't dupe.""" from sosbeacon.event.contact_marker import ContactMarker methods = [ '1234567890', '*****@*****.**', '2098765432', '*****@*****.**' ] left = ContactMarker(methods=methods[:]) right = ContactMarker(methods=methods[:]) left.merge(right) self.assertEqual(sorted(set(methods[:])), sorted(left.methods))
def create_marker_user(event_key, message_key, user_key): """Scan over the given set of groups, sending the broadcast to everyone in those groups. """ from sosbeacon.utils import insert_tasks from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import get_marker_for_methods from sosbeacon.student import Student from sosbeacon.student import DEFAULT_STUDENT_ID methods = set() if message_key.get().message_type == "eo": methods.add(user_key.get().email) else: methods.add(user_key.get().phone) methods.add(user_key.get().email) marker = get_marker_for_methods(event_key, methods) student_key = ndb.Key(Student, "%s-%s" % (DEFAULT_STUDENT_ID, user_key.id()), namespace="_x_") if not marker: # TODO: What needs set? short_id = str(ContactMarker.allocate_ids(size=1, parent=event_key)[0]) key_id = "%s:%s" % (event_key.id(), user_key.id()) marker = ContactMarker( id=key_id, event=event_key, first_name=user_key.get().first_name, last_name=user_key.get().last_name, students={str(student_key.id()): []}, short_id=short_id, methods=[user_key.get().email, user_key.get().phone], count_comment=0, count_visit=0, is_user=True, ) marker.acknowledged = True marker.put() tasks = [] for method in methods: # TODO: Batch tasks or start tasks.append(get_broadcast_method_to_user_task(event_key, message_key, user_key, method)) if len(tasks) > 10: insert_tasks(tasks, USER_TX_QUEUE) tasks = [] if tasks: insert_tasks(tasks, USER_TX_QUEUE)
def test_sort_place_holders(self, find_markers_for_methods_mock, insert_update_marker_task_mock): """Ensure an exsting short_id is returned, and contact merged, if there is a matching marker. """ from google.appengine.ext import ndb from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import create_or_update_marker from sosbeacon.event.event import Event from sosbeacon.event.message import Message from sosbeacon.student import Student marker1_key = mock.Mock(spec=ndb.Key) marker1_key.kind.return_value = "ContactMarker" marker1_key.urlsafe.return_value = "CONTACTMARKER" marker1 = ContactMarker(key=marker1_key, short_id='A') marker1_key.get.return_value = marker1 find_markers_for_methods_mock.return_value = (marker1, ) event_key = ndb.Key(Event, 'EVENTKEY') student_key = ndb.Key(Student, 'STUDENTKEY') message_key = ndb.Key(Message, 'MESSAGEKEY') ret_value = create_or_update_marker(event_key, student_key, message_key, {'a': True}, ['123']) self.assertEqual('A', ret_value) self.assertEqual(1, insert_update_marker_task_mock.call_count)
def test_methods_get_merged(self, insert_merge_task_mock, marker_put_mock): """Test that existing methods don't get duplicated and new methods get added. """ from google.appengine.ext import ndb from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import update_marker methods = ['abc'] marker_key = mock.Mock(spec=ndb.Key) marker_key.kind.return_value = "ContactMarker" marker = ContactMarker(key=marker_key, students={}, methods=methods[:]) marker_key.get.return_value = marker student_key = mock.Mock(spec=ndb.Key) student_key.id.return_value = "STUDENTKEY" contact = {'id': 1} new_methods = ['abc', '123', '456'] update_marker(marker_key, student_key, contact, new_methods[:]) all_methods = sorted(set(new_methods) | set(methods)) self.assertEqual(all_methods, sorted(marker.methods)) self.assertTrue(marker_put_mock.called) self.assertEqual(1, insert_merge_task_mock.call_count)
def test_student_gets_added(self, insert_merge_task_mock, marker_put_mock): """Test a new student is added to the marker.""" from google.appengine.ext import ndb from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import update_marker methods = ['abc'] marker_key = mock.Mock(spec=ndb.Key) marker_key.kind.return_value = "ContactMarker" marker = ContactMarker(key=marker_key, students={}, methods=methods[:]) marker_key.get.return_value = marker student_key = mock.Mock(spec=ndb.Key) student_key.id.return_value = "STUDENTKEY" contact = {'name': 'jimmy'} update_marker(marker_key, student_key, contact.copy(), methods) self.assertIn(student_key.id(), marker.students) self.assertEqual([contact.copy()], marker.students[student_key.id()]) self.assertTrue(marker_put_mock.called) self.assertEqual(1, insert_merge_task_mock.call_count)
def test_contact_gets_added_to_student(self, insert_merge_task_mock, marker_put_mock): """Test that new contact is added to the existing student.""" from google.appengine.ext import ndb from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import update_marker methods = ['abc'] student_key = mock.Mock(spec=ndb.Key) student_key.id.return_value = "STUDENTKEY" student_contacts = {'name': 'Joe Blow'} marker_key = mock.Mock(spec=ndb.Key) marker_key.kind.return_value = "ContactMarker" marker = ContactMarker( key=marker_key, students={student_key.id(): [student_contacts.copy()]}, methods=methods[:]) marker_key.get.return_value = marker contact = {'name': 'Some Dude'} update_marker(marker_key, student_key, contact.copy(), methods) self.assertIn(student_key.id(), marker.students) self.assertIn(contact.copy(), marker.students[student_key.id()]) self.assertTrue(marker_put_mock.called) self.assertEqual(1, insert_merge_task_mock.call_count)
def test_merge_methods_with_overlapping_methods(self): """Ensure merging new methods with overlapping methods doesn't dupe.""" from sosbeacon.event.contact_marker import ContactMarker base_methods = [ '1234567890', '*****@*****.**', '2098765432', '*****@*****.**' ] methods_1 = base_methods + ['123312', '*****@*****.**'] methods_2 = base_methods + ['848423', '*****@*****.**'] left = ContactMarker(methods=methods_1[:]) right = ContactMarker(methods=methods_2[:]) left.merge(right) self.assertEqual(sorted(set(methods_1 + methods_2)), sorted(left.methods))
def test_sort_place_holders(self, find_markers_for_methods_mock): """Ensure multiple place holders are sorted correctly.""" from google.appengine.ext import ndb from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import get_marker_for_methods from sosbeacon.event.event import Event marker1_key = mock.Mock(spec=ndb.Key) marker1_key.kind.return_value = "ContactMarker" marker1 = ContactMarker(key=marker1_key, short_id='A') marker1_key.get.return_value = marker1 marker2_key = mock.Mock(spec=ndb.Key) marker2_key.kind.return_value = "ContactMarker" marker2 = ContactMarker(key=marker2_key, short_id='Z') marker2_key.get.return_value = marker2 find_markers_for_methods_mock.return_value = ( ContactMarker(place_holder=marker1_key), ContactMarker(place_holder=marker2_key), ContactMarker(place_holder=marker1_key), ContactMarker(place_holder=marker2_key), ContactMarker(place_holder=marker1_key), ) event_key = ndb.Key(Event, 'EVENTKEY') ret_value = get_marker_for_methods(event_key, ['123']) self.assertIs(marker1, ret_value)
class TestUpdateMarkerPair(unittest.TestCase): """Ensure update_marker_pair updates the two markers, and remerges if a marker is out of date. """ def setUp(self): from google.appengine.datastore.datastore_stub_util import \ TimeBasedHRConsistencyPolicy from sosbeacon.event.contact_marker import ContactMarker self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.setup_env(app_id='testapp') self.testbed.init_datastore_v3_stub( consistency_policy=TimeBasedHRConsistencyPolicy()) self.testbed.init_memcache_stub() self.marker1 = ContactMarker( id='a', students={'a': 'student_a'}, methods=['method_a'] ) self.marker2 = ContactMarker( id='b', students={'b': 'student_b'}, methods=['method_b'], ) def test_both_valid(self): """Test that the two markers are put if both are valid.""" from sosbeacon.event.contact_marker import update_marker_pair self.marker1.put() self.marker2.put() update_marker_pair(self.marker1, self.marker2) def test_exception_raised_if_one_ood(self): """Test that the an exception is raised is a marker is stale.""" from sosbeacon.event.contact_marker import update_marker_pair self.marker1.put() self.marker2.put() evil_marker1 = self.marker1.key.get(use_cache=False) evil_marker1.put(use_cache=False) self.assertRaisesRegexp( Exception, "revision out of date.", update_marker_pair, self.marker1, self.marker2)
def setUp(self): from google.appengine.datastore.datastore_stub_util import \ TimeBasedHRConsistencyPolicy from sosbeacon.event.contact_marker import ContactMarker self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.setup_env(app_id='testapp') self.testbed.init_datastore_v3_stub( consistency_policy=TimeBasedHRConsistencyPolicy()) self.testbed.init_memcache_stub() self.marker1 = ContactMarker( id='a', students={'a': 'student_a'}, methods=['method_a'] ) self.marker2 = ContactMarker( id='b', students={'b': 'student_b'}, methods=['method_b'], )
def test_merge_no_students_with_students(self): """Ensure merging no students with students.""" from sosbeacon.event.contact_marker import ContactMarker students = { '123': [{ 'name': 'Sam Smith', 'methods': ['123432', '*****@*****.**'] }], '345': [{ 'name': 'Josh Jones', 'methods': ['443241', '*****@*****.**'] }], '231': [{ 'name': 'Betty Boop', 'methods': ['321133', '*****@*****.**'] }], } left = ContactMarker() right = ContactMarker(students=copy.deepcopy(students)) left.merge(right) self.assertEqual(students, left.students)
class TestUpdateMarkerPair(unittest.TestCase): """Ensure update_marker_pair updates the two markers, and remerges if a marker is out of date. """ def setUp(self): from google.appengine.datastore.datastore_stub_util import \ TimeBasedHRConsistencyPolicy from sosbeacon.event.contact_marker import ContactMarker self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.setup_env(app_id='testapp') self.testbed.init_datastore_v3_stub( consistency_policy=TimeBasedHRConsistencyPolicy()) self.testbed.init_memcache_stub() self.marker1 = ContactMarker(id='a', students={'a': 'student_a'}, methods=['method_a']) self.marker2 = ContactMarker( id='b', students={'b': 'student_b'}, methods=['method_b'], ) def test_both_valid(self): """Test that the two markers are put if both are valid.""" from sosbeacon.event.contact_marker import update_marker_pair self.marker1.put() self.marker2.put() update_marker_pair(self.marker1, self.marker2) def test_exception_raised_if_one_ood(self): """Test that the an exception is raised is a marker is stale.""" from sosbeacon.event.contact_marker import update_marker_pair self.marker1.put() self.marker2.put() evil_marker1 = self.marker1.key.get(use_cache=False) evil_marker1.put(use_cache=False) self.assertRaisesRegexp(Exception, "revision out of date.", update_marker_pair, self.marker1, self.marker2)
def create_marker_user(event_key, message_key, user_key): """Scan over the given set of groups, sending the broadcast to everyone in those groups. """ from sosbeacon.utils import insert_tasks from sosbeacon.event.contact_marker import ContactMarker from sosbeacon.event.contact_marker import get_marker_for_methods from sosbeacon.student import Student from sosbeacon.student import DEFAULT_STUDENT_ID methods = set() if message_key.get().message_type == 'eo': methods.add(user_key.get().email) else: methods.add(user_key.get().phone) methods.add(user_key.get().email) marker = get_marker_for_methods(event_key, methods) student_key = ndb.Key(Student, "%s-%s" % (DEFAULT_STUDENT_ID, user_key.id()), namespace='_x_') if not marker: # TODO: What needs set? short_id = str(ContactMarker.allocate_ids(size=1, parent=event_key)[0]) key_id = "%s:%s" % (event_key.id(), user_key.id()) marker = ContactMarker( id=key_id, event=event_key, first_name=user_key.get().first_name, last_name=user_key.get().last_name, students={str(student_key.id()): []}, short_id=short_id, methods=[user_key.get().email, user_key.get().phone], count_comment=0, count_visit=0, is_user=True) marker.acknowledged = True marker.put() tasks = [] for method in methods: # TODO: Batch tasks or start tasks.append( get_broadcast_method_to_user_task(event_key, message_key, user_key, method)) if len(tasks) > 10: insert_tasks(tasks, USER_TX_QUEUE) tasks = [] if tasks: insert_tasks(tasks, USER_TX_QUEUE)
def send_email_robocall_to_user(message_key, event_key): from sosbeacon.event.contact_marker import ContactMarker import sendgrid import settings user_key = message_key.get().user message = message_key.get() logging.info("Sending notice to %s via mail api.", user_key.get().email) contact_markers = ContactMarker.query(ContactMarker.event == event_key) string_date = "%s %s, %s at %s:%s %s (GMT)" % ( message.added.strftime("%B"), message.added.strftime("%d"), message.added.strftime("%Y"), message.added.strftime("%I"), message.added.strftime("%M"), message.added.strftime("%p"), ) subject = "School Beacon ROBOCALL service for alert %s was requested by you" % event_key.id() body = ( "School Beacon ROBOCALL service for alert <span style='color: red'>%s</span> was requested by you" % event_key.id() ) body = ( body + " on " + "<br><span style='color:red'>" + string_date + "</span>.<br><br>" + " The following numbers were called: <br>" ) for contact_marker in contact_markers: for method in contact_marker.methods: if "@" not in method: body += str(method) + "<br>" body += "<br><br>The following text was delivered:<br> <span style='color:red'>%s</span>" % message.message["email"] s = sendgrid.Sendgrid(settings.SENDGRID_ACCOUNT, settings.SENDGRID_PASSWORD, secure=True) email = sendgrid.Message(user_key.get().email, subject, body, body) email.add_to(user_key.get().email) s.web.send(email)