def test_thread_count(db, api_client, default_account): date1 = datetime.datetime(2015, 1, 1, 0, 0, 0) date2 = datetime.datetime(2012, 1, 1, 0, 0, 0) date3 = datetime.datetime(2010, 1, 1, 0, 0, 0) date4 = datetime.datetime(2009, 1, 1, 0, 0, 0) date5 = datetime.datetime(2008, 1, 1, 0, 0, 0) thread1 = add_fake_thread(db.session, default_account.namespace.id) thread2 = add_fake_thread(db.session, default_account.namespace.id) test_subject = "test_thread_view_count_with_category" for thread in [thread1, thread2]: add_fake_message(db.session, default_account.namespace.id, thread, subject=test_subject, received_date=date1) add_fake_message(db.session, default_account.namespace.id, thread, subject=test_subject, received_date=date2, add_sent_category=True) add_fake_message(db.session, default_account.namespace.id, thread, subject=test_subject, received_date=date3) add_fake_message(db.session, default_account.namespace.id, thread, subject=test_subject, received_date=date4, add_sent_category=True) add_fake_message(db.session, default_account.namespace.id, thread, subject=test_subject, received_date=date5) resp = api_client.get_raw('/threads/?view=count&in=sent') assert resp.status_code == 200 threads = json.loads(resp.data) assert threads['count'] == 2
def test_basic_message_grouping(db, default_namespace): first_thread = add_fake_thread(db.session, default_namespace.id) first_thread.subject = 'Some kind of test' add_fake_message(db.session, default_namespace.id, thread=first_thread, subject='Some kind of test', from_addr=[('Karim Hamidou', '*****@*****.**')], to_addr=[('Eben Freeman', '*****@*****.**')], bcc_addr=[('Some person', '*****@*****.**')]) msg2 = add_fake_message(db.session, default_namespace.id, thread=None, subject='Re: Some kind of test', from_addr=[('Some random dude', '*****@*****.**')], to_addr=[('Karim Hamidou', '*****@*****.**')]) matched_thread = fetch_corresponding_thread(db.session, default_namespace.id, msg2) assert matched_thread is None, "the algo shouldn't thread different convos" msg3 = add_fake_message(db.session, default_namespace.id, thread=None) msg3.subject = 'Re: Some kind of test' msg3.from_addr = [('Eben Freeman', '*****@*****.**')] msg3.to_addr = [('Karim Hamidou', '*****@*****.**')] matched_thread = fetch_corresponding_thread(db.session, default_namespace.id, msg3) assert matched_thread is first_thread, "Should match on participants"
def test_generic_grouping(db, default_account): thread = add_fake_thread(db.session, default_account.namespace.id) message = add_fake_message(db.session, default_account.namespace.id, thread, subject="Golden Gate Park next Sat") folder = Folder(account=default_account, name='Inbox', canonical_name='inbox') ImapUid(message=message, account_id=default_account.id, msg_uid=2222, folder=folder) thread = add_fake_thread(db.session, default_account.namespace.id) account = add_generic_imap_account(db.session) message = add_fake_message(db.session, account.namespace.id, thread, subject="Golden Gate Park next Sat") thread = fetch_corresponding_thread(db.session, default_account.namespace.id, message) assert thread is None, ("fetch_similar_threads should " "heed namespace boundaries")
def test_namespace_deletion(db, default_account): from inbox.models import Account, Thread, Message from inbox.models.util import delete_namespace models = [Thread, Message] namespace = default_account.namespace namespace_id = namespace.id account_id = default_account.id account = db.session.query(Account).get(account_id) assert account thread = add_fake_thread(db.session, namespace_id) message = add_fake_message(db.session, namespace_id, thread) for m in models: c = db.session.query(m).filter(m.namespace_id == namespace_id).count() print "count for", m, ":", c assert c != 0 fake_account = add_generic_imap_account(db.session) fake_account_id = fake_account.id assert fake_account_id != account.id and \ fake_account.namespace.id != namespace_id thread = add_fake_thread(db.session, fake_account.namespace.id) thread_id = thread.id message = add_fake_message(db.session, fake_account.namespace.id, thread) message_id = message.id assert len( db.session.query(Namespace).filter( Namespace.id == namespace_id).all()) > 0 # Delete namespace, verify data corresponding to this namespace /only/ # is deleted delete_namespace(account_id, namespace_id) db.session.commit() assert len( db.session.query(Namespace).filter( Namespace.id == namespace_id).all()) == 0 account = db.session.query(Account).get(account_id) assert not account for m in models: assert db.session.query(m).filter( m.namespace_id == namespace_id).count() == 0 fake_account = db.session.query(Account).get(fake_account_id) assert fake_account thread = db.session.query(Thread).get(thread_id) message = db.session.query(Message).get(message_id) assert thread and message
def test_update_contacts_from_message(db, default_namespace, thread): # Check that only one Contact is created for repeatedly-referenced # addresses. add_fake_message(db.session, default_namespace.id, thread, from_addr=[('', '*****@*****.**')], cc_addr=[('', '*****@*****.**')]) assert db.session.query(Contact).filter_by( email_address='*****@*****.**').count() == 1 # Check that existing Contacts are used when we process a new message # referencing them. add_fake_message(db.session, default_namespace.id, thread, from_addr=[('', '*****@*****.**')], cc_addr=[('', '*****@*****.**')], to_addr=[('', '*****@*****.**'), ('', '*****@*****.**')]) assert db.session.query(Contact).filter( Contact.email_address.like('*****@*****.**'), Contact.namespace_id == default_namespace.id).count() == 3 alpha = db.session.query(Contact).filter_by( email_address='*****@*****.**', namespace_id=default_namespace.id).one() assert len(alpha.message_associations) == 4
def test_namespace_limiting(db, api_client, default_namespaces): dt = datetime.datetime.utcnow() subject = dt.isoformat() namespaces = db.session.query(Namespace).all() assert len(namespaces) > 1 for ns in namespaces: thread = Thread(namespace=ns, subjectdate=dt, recentdate=dt, subject=subject) add_fake_message(db.session, ns.id, thread, received_date=dt, subject=subject) db.session.add(Block(namespace=ns, filename=subject)) db.session.commit() for ns in namespaces: r = api_client.get_data('/threads?subject={}'.format(subject)) assert len(r) == 1 r = api_client.get_data('/messages?subject={}'.format(subject)) assert len(r) == 1 r = api_client.get_data('/files?filename={}'.format(subject)) assert len(r) == 1
def test_thread_sent_recent_date(db, api_client, default_account): date1 = datetime.datetime(2015, 1, 1, 0, 0, 0) date2 = datetime.datetime(2012, 1, 1, 0, 0, 0) date3 = datetime.datetime(2010, 1, 1, 0, 0, 0) date4 = datetime.datetime(2009, 1, 1, 0, 0, 0) date5 = datetime.datetime(2008, 1, 1, 0, 0, 0) thread1 = add_fake_thread(db.session, default_account.namespace.id) test_subject = "test_thread_sent_recent_date" add_fake_message(db.session, default_account.namespace.id, thread1, subject=test_subject, received_date=date1) add_fake_message(db.session, default_account.namespace.id, thread1, subject=test_subject, received_date=date2, add_sent_category=True) add_fake_message(db.session, default_account.namespace.id, thread1, subject=test_subject, received_date=date3) add_fake_message(db.session, default_account.namespace.id, thread1, subject=test_subject, received_date=date4, add_sent_category=True) add_fake_message(db.session, default_account.namespace.id, thread1, subject=test_subject, received_date=date5) resp = api_client.get_raw('/threads/') assert resp.status_code == 200 threads = json.loads(resp.data) for thread in threads: # should only be one assert datetime.datetime.fromtimestamp( thread['last_message_sent_timestamp']) == date2
def test_basic_message_grouping(db, default_namespace): first_thread = add_fake_thread(db.session, default_namespace.id) first_thread.subject = 'Some kind of test' add_fake_message(db.session, default_namespace.id, thread=first_thread, subject='Some kind of test', from_addr=[('Karim Hamidou', '*****@*****.**')], to_addr=[('Eben Freeman', '*****@*****.**')], bcc_addr=[('Some person', '*****@*****.**')]) msg2 = add_fake_message(db.session, default_namespace.id, thread=None, subject='Re: Some kind of test', from_addr=[('Some random dude', '*****@*****.**') ], to_addr=[('Karim Hamidou', '*****@*****.**')]) matched_thread = fetch_corresponding_thread(db.session, default_namespace.id, msg2) assert matched_thread is None, "the algo shouldn't thread different convos" msg3 = add_fake_message(db.session, default_namespace.id, thread=None) msg3.subject = 'Re: Some kind of test' msg3.from_addr = [('Eben Freeman', '*****@*****.**')] msg3.to_addr = [('Karim Hamidou', '*****@*****.**')] matched_thread = fetch_corresponding_thread(db.session, default_namespace.id, msg3) assert matched_thread is first_thread, "Should match on participants"
def test_namespace_deletion(db, default_account): from inbox.models import Account, Thread, Message from inbox.models.util import delete_namespace models = [Thread, Message] namespace = default_account.namespace namespace_id = namespace.id account_id = default_account.id account = db.session.query(Account).get(account_id) assert account thread = add_fake_thread(db.session, namespace_id) message = add_fake_message(db.session, namespace_id, thread) for m in models: c = db.session.query(m).filter( m.namespace_id == namespace_id).count() print "count for", m, ":", c assert c != 0 fake_account = add_generic_imap_account(db.session) fake_account_id = fake_account.id assert fake_account_id != account.id and \ fake_account.namespace.id != namespace_id thread = add_fake_thread(db.session, fake_account.namespace.id) thread_id = thread.id message = add_fake_message(db.session, fake_account.namespace.id, thread) message_id = message.id assert len(db.session.query(Namespace).filter(Namespace.id == namespace_id).all()) > 0 # Delete namespace, verify data corresponding to this namespace /only/ # is deleted delete_namespace(account_id, namespace_id) db.session.commit() assert len(db.session.query(Namespace).filter(Namespace.id == namespace_id).all()) == 0 account = db.session.query(Account).get(account_id) assert not account for m in models: assert db.session.query(m).filter( m.namespace_id == namespace_id).count() == 0 fake_account = db.session.query(Account).get(fake_account_id) assert fake_account thread = db.session.query(Thread).get(thread_id) message = db.session.query(Message).get(message_id) assert thread and message
def test_handle_noreply_addresses(db, default_namespace, thread): add_fake_message(db.session, default_namespace.id, thread, from_addr=[('Alice', '*****@*****.**')]) add_fake_message(db.session, default_namespace.id, thread, from_addr=[('Bob', '*****@*****.**')]) noreply_contact = db.session.query(Contact).filter( Contact.namespace == default_namespace, Contact.email_address == '*****@*****.**').one() assert noreply_contact.name is None add_fake_message(db.session, default_namespace.id, thread, from_addr=[('Alice', '*****@*****.**')]) add_fake_message(db.session, default_namespace.id, thread, from_addr=[('Alice Lastname', '*****@*****.**')]) contact = db.session.query(Contact).filter( Contact.namespace == default_namespace, Contact.email_address == '*****@*****.**').first() assert contact.name is not None
def test_transaction_creation_for_self_referential_message_relationship(db, default_namespace): # Make sure that updating the self-refential relationship # `Message.reply_to_message` does not create a spurious update delta for # the parent message. thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) reply = add_fake_message(db.session, default_namespace.id, thr) reply.reply_to_message = msg db.session.commit() assert reply.reply_to_message_id is not None assert msg.reply_to_message_id is None transaction = get_latest_transaction(db.session, "message", msg.id, default_namespace.id) assert transaction.record_id == msg.id assert transaction.object_type == "message" assert transaction.command == "insert"
def test_label_delete(db, gmail_account, label_client, api_version): headers = dict() headers['Api-Version'] = api_version # Make a new message gmail_thread = add_fake_thread(db.session, gmail_account.namespace.id) gmail_message = add_fake_message(db.session, gmail_account.namespace.id, gmail_thread) g_data = label_client.get_raw('/labels/', headers=headers) # Add label to message gmail_label = json.loads(g_data.data)[0] data = {"labels": [gmail_label['id']]} label_client.put_data('/messages/{}'.format(gmail_message.public_id), data, headers=headers) # DELETE requests should work on labels whether or not messages have them d_data = label_client.delete('/labels/{}'.format(gmail_label['id']), headers=headers) assert d_data.status_code == 200 if api_version == API_VERSIONS[0]: # Optimistic update. category_id = gmail_label['id'] category = db.session.query(Category).filter( Category.public_id == category_id).one() assert category.deleted_at != EPOCH assert category.is_deleted is True
def test_folder_delete(db, generic_account, folder_client, api_version): headers = dict() headers['Api-Version'] = api_version # Make a new message generic_thread = add_fake_thread(db.session, generic_account.namespace.id) gen_message = add_fake_message(db.session, generic_account.namespace.id, generic_thread) g_data = folder_client.get_raw('/folders/') # Add message to folder generic_folder = json.loads(g_data.data)[0] data = {"folder_id": generic_folder['id']} folder_client.put_data('/messages/{}'.format(gen_message.public_id), data) # Test that DELETE requests 403 on folders with items in them d_data = folder_client.delete('/folders/{}'.format(generic_folder['id'])) assert d_data.status_code == 400 # Make an empty folder resp = folder_client.post_data('/folders/', {"display_name": "Empty_Folder"}) empty_folder = json.loads(resp.data) # Test that DELETE requests delete empty folders d_data = folder_client.delete('/folders/{}'.format(empty_folder['id'])) assert d_data.status_code == 200 if api_version == API_VERSIONS[0]: # Did we update things optimistically? category_id = empty_folder['id'] category = db.session.query(Category).filter( Category.public_id == category_id).one() assert category.deleted_at != EPOCH assert category.is_deleted is True db.session.rollback()
def test_message_updates_create_thread_transaction(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) transaction = get_latest_transaction(db.session, "thread", thr.id, default_namespace.id) assert transaction.record_id == thr.id and transaction.object_type == "thread" assert transaction.command == "update" # An update to one of the message's propagated_attributes creates a # revision for the thread msg.is_read = True db.session.commit() new_transaction = get_latest_transaction(db.session, "thread", thr.id, default_namespace.id) assert new_transaction.id != transaction.id assert new_transaction.record_id == thr.id and new_transaction.object_type == "thread" assert new_transaction.command == "update" # An update to one of its other attributes does not msg.subject = "Ice cubes and dogs" db.session.commit() same_transaction = get_latest_transaction(db.session, "thread", thr.id, default_namespace.id) assert same_transaction.id == new_transaction.id
def test_message_delete(db, gmail_account): """ Ensure that all associated MessageCategories are deleted when a Message is deleted """ api_client = new_api_client(db, gmail_account.namespace) generic_thread = add_fake_thread(db.session, gmail_account.namespace.id) gen_message = add_fake_message(db.session, gmail_account.namespace.id, generic_thread) category_ids = [] for i in xrange(10): po_data = api_client.post_data('/labels/', {"display_name": str(i)}) assert po_data.status_code == 200 category_ids.append(json.loads(po_data.data)['id']) data = {"label_ids": category_ids} resp = api_client.put_data('/messages/{}'.format(gen_message.public_id), data) assert resp.status_code == 200 associated_mcs = db.session.query(MessageCategory). \ filter(MessageCategory.message_id == gen_message.id).all() assert len(associated_mcs) == 10 db.session.delete(gen_message) db.session.commit() assert db.session.query(MessageCategory). \ filter(MessageCategory.message_id == gen_message.id).all() == []
def test_message_label_updates(db, api_client, default_account, api_version, custom_label): """Check that you can update a message (optimistically or not), and that the update is queued in the ActionLog.""" headers = dict() headers['Api-Version'] = api_version # Gmail threads, messages have a 'labels' field gmail_thread = add_fake_thread(db.session, default_account.namespace.id) gmail_message = add_fake_message(db.session, default_account.namespace.id, gmail_thread) resp_data = api_client.get_data('/messages/{}'.format( gmail_message.public_id), headers=headers) assert resp_data['labels'] == [] category = custom_label.category update = dict(labels=[category.public_id]) resp = api_client.put_data('/messages/{}'.format(gmail_message.public_id), update, headers=headers) resp_data = json.loads(resp.data) if api_version == API_VERSIONS[0]: assert len(resp_data['labels']) == 1 assert resp_data['labels'][0]['id'] == category.public_id else: assert resp_data['labels'] == []
def test_message_updates_create_thread_transaction(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) transaction = get_latest_transaction(db.session, 'thread', thr.id, default_namespace.id) assert (transaction.record_id == thr.id and transaction.object_type == 'thread') assert transaction.command == 'update' # An update to one of the message's propagated_attributes creates a # revision for the thread msg.is_read = True db.session.commit() new_transaction = get_latest_transaction(db.session, 'thread', thr.id, default_namespace.id) assert new_transaction.id != transaction.id assert (new_transaction.record_id == thr.id and new_transaction.object_type == 'thread') assert new_transaction.command == 'update' # An update to one of its other attributes does not msg.subject = 'Ice cubes and dogs' db.session.commit() same_transaction = get_latest_transaction(db.session, 'thread', thr.id, default_namespace.id) assert same_transaction.id == new_transaction.id
def test_category_delete(db, gmail_account): """ Ensure that all associated MessageCategories are deleted when a Category is deleted """ api_client = new_api_client(db, gmail_account.namespace) po_data = api_client.post_data('/labels/', {"display_name": "Test_Label"}) assert po_data.status_code == 200 category_public_id = json.loads(po_data.data)['id'] category = db.session.query(Category).filter( Category.public_id == category_public_id).one() category_id = category.id for i in xrange(10): generic_thread = add_fake_thread(db.session, gmail_account.namespace.id) gen_message = add_fake_message(db.session, gmail_account.namespace.id, generic_thread) data = {"label_ids": [category_public_id]} resp = api_client.put_data('/messages/{}'. format(gen_message.public_id), data) assert resp.status_code == 200 associated_mcs = db.session.query(MessageCategory). \ filter(MessageCategory.category_id == category_id).all() assert len(associated_mcs) == 10 db.session.delete(category) db.session.commit() assert db.session.query(MessageCategory). \ filter(MessageCategory.category_id == category_id).all() == []
def test_message_delete(db, gmail_account): """ Ensure that all associated MessageCategories are deleted when a Message is deleted """ api_client = new_api_client(db, gmail_account.namespace) generic_thread = add_fake_thread(db.session, gmail_account.namespace.id) gen_message = add_fake_message(db.session, gmail_account.namespace.id, generic_thread) category_ids = [] for i in xrange(10): po_data = api_client.post_data('/labels/', {"display_name": str(i)}) assert po_data.status_code == 200 category_ids.append(json.loads(po_data.data)['id']) data = {"label_ids": category_ids} resp = api_client.put_data('/messages/{}'. format(gen_message.public_id), data) assert resp.status_code == 200 associated_mcs = db.session.query(MessageCategory). \ filter(MessageCategory.message_id == gen_message.id).all() assert len(associated_mcs) == 10 db.session.delete(gen_message) db.session.commit() assert db.session.query(MessageCategory). \ filter(MessageCategory.message_id == gen_message.id).all() == []
def test_message_label_updates(db, api_client, default_account, api_version, custom_label): """Check that you can update a message (optimistically or not), and that the update is queued in the ActionLog.""" headers = dict() headers['Api-Version'] = api_version # Gmail threads, messages have a 'labels' field gmail_thread = add_fake_thread(db.session, default_account.namespace.id) gmail_message = add_fake_message(db.session, default_account.namespace.id, gmail_thread) resp_data = api_client.get_data( '/messages/{}'.format(gmail_message.public_id), headers=headers) assert resp_data['labels'] == [] category = custom_label.category update = dict(labels=[category.public_id]) resp = api_client.put_data( '/messages/{}'.format(gmail_message.public_id), update, headers=headers) resp_data = json.loads(resp.data) if api_version == API_VERSIONS[0]: assert len(resp_data['labels']) == 1 assert resp_data['labels'][0]['id'] == category.public_id else: assert resp_data['labels'] == []
def test_category_delete(db, gmail_account): """ Ensure that all associated MessageCategories are deleted when a Category is deleted """ api_client = new_api_client(db, gmail_account.namespace) po_data = api_client.post_data('/labels/', {"display_name": "Test_Label"}) assert po_data.status_code == 200 category_public_id = json.loads(po_data.data)['id'] category = db.session.query(Category).filter( Category.public_id == category_public_id).one() category_id = category.id for i in xrange(10): generic_thread = add_fake_thread(db.session, gmail_account.namespace.id) gen_message = add_fake_message(db.session, gmail_account.namespace.id, generic_thread) data = {"label_ids": [category_public_id]} resp = api_client.put_data( '/messages/{}'.format(gen_message.public_id), data) assert resp.status_code == 200 associated_mcs = db.session.query(MessageCategory). \ filter(MessageCategory.category_id == category_id).all() assert len(associated_mcs) == 10 db.session.delete(category) db.session.commit() assert db.session.query(MessageCategory). \ filter(MessageCategory.category_id == category_id).all() == []
def test_reject_incompatible_reply_thread_and_message( db, api_client, message, thread, default_namespace): alt_thread = add_fake_thread(db.session, default_namespace.id) add_fake_message(db.session, default_namespace.id, alt_thread) thread = api_client.get_data('/threads')[0] alt_message_id = api_client.get_data('/threads')[1]['message_ids'][0] alt_message = api_client.get_data('/messages/{}'.format(alt_message_id)) assert thread['id'] != alt_message['thread_id'] reply_draft = { 'subject': 'test reply', 'reply_to_message_id': alt_message['id'], 'thread_id': thread['id'] } r = api_client.post_data('/drafts', reply_draft) assert r.status_code == 400
def test_reject_incompatible_reply_thread_and_message(db, api_client, message, thread, default_namespace): alt_thread = add_fake_thread(db.session, default_namespace.id) add_fake_message(db.session, default_namespace.id, alt_thread) thread = api_client.get_data('/threads')[0] alt_message_id = api_client.get_data('/threads')[1]['message_ids'][0] alt_message = api_client.get_data('/messages/{}'.format(alt_message_id)) assert thread['id'] != alt_message['thread_id'] reply_draft = { 'subject': 'test reply', 'reply_to_message_id': alt_message['id'], 'thread_id': thread['id'] } r = api_client.post_data('/drafts', reply_draft) assert r.status_code == 400
def test_adding_and_removing_message_on_thread_increments_version( db, thread, default_namespace): assert thread.version == 0 message = add_fake_message(db.session, default_namespace.id, thread) assert thread.version == 1 thread.messages.remove(message) db.session.commit() assert thread.version == 2
def different_imap_messages(db, generic_account, different_sorted_imap_threads, different_imap_folder): thread1, thread2, thread3 = different_sorted_imap_threads message1 = add_fake_message(db.session, generic_account.namespace.id, thread=thread1, from_addr=[{'name': '', 'email': '*****@*****.**'}], to_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], received_date=datetime. datetime(2015, 7, 9, 23, 50, 7), subject='LOL') add_fake_imapuid(db.session, generic_account.id, message1, different_imap_folder, 5000) message2 = add_fake_message(db.session, generic_account.namespace.id, thread=thread2, from_addr=[{'name': '', 'email': '*****@*****.**'}], to_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], received_date=datetime. datetime(2014, 7, 9, 23, 50, 7), subject='ROTFLMO') add_fake_imapuid(db.session, generic_account.id, message2, different_imap_folder, 5001) message3 = add_fake_message(db.session, generic_account.namespace.id, thread=thread3, from_addr=[{'name': '', 'email': '*****@*****.**'}], to_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], received_date=datetime. datetime(2013, 7, 9, 23, 50, 7), subject='ROFLCOPTER') add_fake_imapuid(db.session, generic_account.id, message3, different_imap_folder, 5002) return [message1, message2, message3]
def test_transaction_creation_for_self_referential_message_relationship( db, default_namespace): # Make sure that updating the self-refential relationship # `Message.reply_to_message` does not create a spurious update delta for # the parent message. thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) reply = add_fake_message(db.session, default_namespace.id, thr) reply.reply_to_message = msg db.session.commit() assert reply.reply_to_message_id is not None assert msg.reply_to_message_id is None transaction = get_latest_transaction(db.session, 'message', msg.id, default_namespace.id) assert transaction.record_id == msg.id assert transaction.object_type == 'message' assert transaction.command == 'insert'
def sorted_imap_messages(db, generic_account, sorted_imap_threads, imap_folder): thread1, thread2, thread3 = sorted_imap_threads message1 = add_fake_message(db.session, generic_account.namespace.id, thread=thread1, from_addr=[{'name': '', 'email': '*****@*****.**'}], to_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], received_date=datetime. datetime(2015, 7, 9, 23, 50, 7), subject='YOO!') add_fake_imapuid(db.session, generic_account.id, message1, imap_folder, 2000) message2 = add_fake_message(db.session, generic_account.namespace.id, thread=thread2, from_addr=[{'name': '', 'email': '*****@*****.**'}], to_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], received_date=datetime. datetime(2014, 7, 9, 23, 50, 7), subject='Hey!') add_fake_imapuid(db.session, generic_account.id, message2, imap_folder, 2001) message3 = add_fake_message(db.session, generic_account.namespace.id, thread=thread3, from_addr=[{'name': '', 'email': '*****@*****.**'}], to_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], received_date=datetime. datetime(2013, 7, 9, 23, 50, 7), subject='Sup?') add_fake_imapuid(db.session, generic_account.id, message3, imap_folder, 2002) return [message1, message2, message3]
def sorted_gmail_messages(db, default_account, sorted_gmail_threads, folder): thread1, thread2, thread3 = sorted_gmail_threads message1 = add_fake_message(db.session, default_account.namespace.id, thread=thread1, g_msgid=1, from_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], to_addr=[{'name': 'Barrack Obama', 'email': '*****@*****.**'}], received_date=datetime. datetime(2015, 7, 9, 23, 50, 7), subject='YOO!') add_fake_imapuid(db.session, default_account.id, message1, folder, 3000) message2 = add_fake_message(db.session, default_account.namespace.id, thread=thread2, g_msgid=2, from_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], to_addr=[{'name': 'Barrack Obama', 'email': '*****@*****.**'}], received_date=datetime. datetime(2014, 7, 9, 23, 50, 7), subject='Hey!') add_fake_imapuid(db.session, default_account.id, message2, folder, 3001) message3 = add_fake_message(db.session, default_account.namespace.id, thread=thread3, g_msgid=3, from_addr=[{'name': 'Ben Bitdiddle', 'email': '*****@*****.**'}], to_addr=[{'name': 'Barrack Obama', 'email': '*****@*****.**'}], received_date=datetime. datetime(2013, 7, 9, 23, 50, 7), subject='Sup?') add_fake_imapuid(db.session, default_account.id, message3, folder, 3002) return [message1, message2, message3]
def stub_message(db, new_message_from_synced, default_namespace, thread): message = add_fake_message(db.session, default_namespace.id, thread, subject="Golden Gate Park next Sat", from_addr=[('alice', '*****@*****.**')], to_addr=[('bob', '*****@*****.**')]) message.snippet = 'Banh mi paleo pickled, sriracha' message.body = """ Banh mi paleo pickled, sriracha biodiesel chambray seitan mumblecore mustache. Raw denim gastropub 8-bit, butcher PBR sartorial photo booth Pinterest blog Portland roof party cliche bitters aesthetic. Ugh. """ message = add_fake_message(db.session, default_namespace.id, thread, subject="Re:Golden Gate Park next Sat", from_addr=[('bob', '*****@*****.**')], to_addr=[('alice', '*****@*****.**')], cc_addr=[('Cheryl', '*****@*****.**')]) message.snippet = 'Bushwick meggings ethical keffiyeh' message.body = """ Bushwick meggings ethical keffiyeh. Chambray lumbersexual wayfarers, irony Banksy cred bicycle rights scenester artisan tote bag YOLO gastropub. """ draft = add_fake_message(db.session, default_namespace.id, thread, subject="Re:Golden Gate Park next Sat", from_addr=[('alice', '*****@*****.**')], to_addr=[('bob', '*****@*****.**')], cc_addr=[('Cheryl', '*****@*****.**')]) draft.snippet = 'Hey there friend writing a draft' draft.body = """ DIY tousled Tumblr, VHS meditation 3 wolf moon listicle fingerstache viral bicycle rights. Thundercats kale chips church-key American Apparel. """ draft.is_draft = True draft.reply_to_message = message db.session.commit() return message
def test_namespace_delete_cascade(db, default_account): from inbox.models import Account, Thread, Message models = [Thread, Message] namespace = default_account.namespace namespace_id = namespace.id account_id = default_account.id account = db.session.query(Account).get(account_id) assert account thread = add_fake_thread(db.session, namespace_id) add_fake_message(db.session, namespace_id, thread) for m in models: c = db.session.query(m).filter(m.namespace_id == namespace_id).count() print "count for", m, ":", c assert c != 0 fake_account = add_generic_imap_account(db.session) fake_account_id = fake_account.id assert fake_account_id != account.id and \ fake_account.namespace.id != namespace_id thread = add_fake_thread(db.session, fake_account.namespace.id) add_fake_message(db.session, fake_account.namespace.id, thread) assert len( db.session.query(Namespace).filter( Namespace.id == namespace_id).all()) > 0 # This test is separate from test_namespace_deletion because we want to # do a raw SQLAlchemy delete rather than using delete_namespace, which does # a bunch of extra work to ensure that objects associated with a Namespace # are actually deleted. db.session.query(Namespace).filter(Namespace.id == namespace_id).delete() db.session.commit() assert len( db.session.query(Namespace).filter( Namespace.id == namespace_id).all()) == 0
def test_distinct_results(api_client, db, default_namespace): """Test that limit and offset parameters work correctly when joining on multiple matching messages per thread.""" # Create a thread with multiple messages on it. first_thread = add_fake_thread(db.session, default_namespace.id) add_fake_message(db.session, default_namespace.id, first_thread, from_addr=[('', '*****@*****.**')], received_date=datetime.datetime.utcnow(), add_sent_category=True) add_fake_message(db.session, default_namespace.id, first_thread, from_addr=[('', '*****@*****.**')], received_date=datetime.datetime.utcnow(), add_sent_category=True) # Now create another thread with the same participants older_date = datetime.datetime.utcnow() - datetime.timedelta(hours=1) second_thread = add_fake_thread(db.session, default_namespace.id) add_fake_message(db.session, default_namespace.id, second_thread, from_addr=[('', '*****@*****.**')], received_date=older_date, add_sent_category=True) add_fake_message(db.session, default_namespace.id, second_thread, from_addr=[('', '*****@*****.**')], received_date=older_date, add_sent_category=True) second_thread.recentdate = older_date db.session.commit() filtered_results = api_client.get_data('/[email protected]' '&limit=1&offset=0') assert len(filtered_results) == 1 assert filtered_results[0]['id'] == first_thread.public_id filtered_results = api_client.get_data('/[email protected]' '&limit=1&offset=1') assert len(filtered_results) == 1 assert filtered_results[0]['id'] == second_thread.public_id filtered_results = api_client.get_data('/[email protected]' '&limit=2&offset=0') assert len(filtered_results) == 2 filtered_results = api_client.get_data('/[email protected]' '&limit=2&offset=1') assert len(filtered_results) == 1 # Ensure that it works when using the _in filter filtered_results = api_client.get_data('/threads?in=sent' '&limit=2&offset=0') assert len(filtered_results) == 2 filtered_results = api_client.get_data('/threads?in=sent' '&limit=1&offset=0') assert len(filtered_results) == 1
def test_longpoll_delta_newitem(db, api_client, default_namespace, thread): cursor = get_cursor(api_client, int(time.time() + 22), default_namespace) url = url_concat('/delta/longpoll', {'cursor': cursor}) start_time = time.time() # Spawn the request in background greenlet longpoll_greenlet = Greenlet.spawn(api_client.get_raw, url) # This should make it return immediately add_fake_message(db.session, default_namespace.id, thread, from_addr=[('Bob', '*****@*****.**')]) longpoll_greenlet.join() # now block and wait end_time = time.time() assert end_time - start_time < LONGPOLL_EPSILON parsed_responses = json.loads(longpoll_greenlet.value.data) assert len(parsed_responses['deltas']) == 3 assert set(k['object'] for k in parsed_responses['deltas']) == \ set([u'message', u'contact', u'thread'])
def test_ordering(api_client, db, default_namespace): for i in range(3): thr = add_fake_thread(db.session, default_namespace.id) received_date = (datetime.datetime.utcnow() + datetime.timedelta(seconds=22 * (i + 1))) add_fake_message(db.session, default_namespace.id, thr, received_date=received_date) ordered_results = api_client.get_data('/messages') ordered_dates = [result['date'] for result in ordered_results] assert ordered_dates == sorted(ordered_dates, reverse=True) ordered_results = api_client.get_data('/messages?limit=3') expected_public_ids = [ public_id for public_id, in db.session.query(Message.public_id). filter(Message.namespace_id == default_namespace.id). order_by(desc(Message.received_date)).limit(3)] assert expected_public_ids == [r['id'] for r in ordered_results]
def test_self_send(db, default_namespace): first_thread = add_fake_thread(db.session, default_namespace.id) first_thread.subject = 'Some kind of test' add_fake_message(db.session, default_namespace.id, thread=first_thread, subject='Some kind of test', from_addr=[('Karim Hamidou', '*****@*****.**')], to_addr=[('Karim Hamidou', '*****@*****.**')]) msg2 = add_fake_message(db.session, default_namespace.id, thread=None, subject='Re: Some kind of test', from_addr=[('Karim Hamidou', '*****@*****.**')], to_addr=[('Karim Hamidou', '*****@*****.**')]) matched_thread = fetch_corresponding_thread(db.session, default_namespace.id, msg2) assert matched_thread is first_thread, "Should match on self-send"
def test_threads_only_deleted_when_no_messages_left(db, default_account, default_namespace, marked_deleted_message, thread, folder): handler = DeleteHandler(account_id=default_account.id, namespace_id=default_namespace.id, provider_name=default_account.provider, uid_accessor=lambda m: m.imapuids, message_ttl=0) # Add another message onto the thread add_fake_message(db.session, default_namespace.id, thread) handler.check(marked_deleted_message.deleted_at + timedelta(seconds=1)) db.session.expire_all() # Check that the orphaned message was deleted. with pytest.raises(ObjectDeletedError): marked_deleted_message.id # Would raise ObjectDeletedError if thread was deleted. thread.id
def test_message_insert_creates_transaction(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) transaction = get_latest_transaction(db.session, "message", msg.id, default_namespace.id) assert transaction.command == "insert" # Test that the thread gets revised too transaction = get_latest_transaction(db.session, "thread", thr.id, default_namespace.id) assert transaction.command == "update"
def test_namespace_delete_cascade(db, default_account): from inbox.models import Account, Thread, Message models = [Thread, Message] namespace = default_account.namespace namespace_id = namespace.id account_id = default_account.id account = db.session.query(Account).get(account_id) assert account thread = add_fake_thread(db.session, namespace_id) add_fake_message(db.session, namespace_id, thread) for m in models: c = db.session.query(m).filter( m.namespace_id == namespace_id).count() print "count for", m, ":", c assert c != 0 fake_account = add_generic_imap_account(db.session) fake_account_id = fake_account.id assert fake_account_id != account.id and \ fake_account.namespace.id != namespace_id thread = add_fake_thread(db.session, fake_account.namespace.id) add_fake_message(db.session, fake_account.namespace.id, thread) assert len(db.session.query(Namespace).filter(Namespace.id == namespace_id).all()) > 0 # This test is separate from test_namespace_deletion because we want to # do a raw SQLAlchemy delete rather than using delete_namespace, which does # a bunch of extra work to ensure that objects associated with a Namespace # are actually deleted. db.session.query(Namespace).filter(Namespace.id == namespace_id).delete() db.session.commit() assert len(db.session.query(Namespace).filter(Namespace.id == namespace_id).all()) == 0
def test_message_updates_create_transaction(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) msg.is_read = True db.session.commit() transaction = get_latest_transaction(db.session, "message", msg.id, default_namespace.id) assert transaction.record_id == msg.id assert transaction.object_type == "message" assert transaction.command == "update"
def test_reply_to_message_cascade(db, default_namespace, thread, message): reply = add_fake_message(db.session, default_namespace.id, thread) reply.reply_to_message = message db.session.commit() db.session.expire_all() db.session.delete(message) db.session.commit() assert db.session.query(Message).filter(Message.id == message.id).all() == [] assert db.session.query(Message).filter(Message.id == reply.id).all() == [reply]
def test_ordering(api_client, db, default_namespace): for i in range(3): thr = add_fake_thread(db.session, default_namespace.id) received_date = (datetime.datetime.utcnow() + datetime.timedelta(seconds=22 * (i + 1))) add_fake_message(db.session, default_namespace.id, thr, received_date=received_date) ordered_results = api_client.get_data('/messages') ordered_dates = [result['date'] for result in ordered_results] assert ordered_dates == sorted(ordered_dates, reverse=True) ordered_results = api_client.get_data('/messages?limit=3') expected_public_ids = [ public_id for public_id, in db.session.query(Message.public_id).filter( Message.namespace_id == default_namespace.id).order_by( desc(Message.received_date)).limit(3) ] assert expected_public_ids == [r['id'] for r in ordered_results]
def test_addresses_canonicalized(db, default_namespace, thread): msg = add_fake_message(db.session, default_namespace.id, thread, from_addr=[('', '*****@*****.**')], cc_addr=[('', '*****@*****.**')], bcc_addr=[('', '*****@*****.**')]) # Because Gmail addresses with and without periods are the same, check that # there are three MessageContactAssociation instances attached to the # message (one each from the from/to/cc fields), but that they reference # the same contact. assert len(msg.contacts) == 3 assert len(set(association.contact for association in msg.contacts)) == 1
def test_message_updates_create_transaction(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) msg.is_read = True db.session.commit() transaction = get_latest_transaction(db.session, 'message', msg.id, default_namespace.id) assert transaction.record_id == msg.id assert transaction.object_type == 'message' assert transaction.command == 'update'
def test_message_insert_creates_transaction(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) transaction = get_latest_transaction(db.session, 'message', msg.id, default_namespace.id) assert transaction.command == 'insert' # Test that the thread gets revised too transaction = get_latest_transaction(db.session, 'thread', thr.id, default_namespace.id) assert transaction.command == 'update'
def test_object_type_distinguishes_messages_and_drafts(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) msg.is_draft = 1 db.session.commit() transaction = get_latest_transaction(db.session, "draft", msg.id, default_namespace.id) assert transaction.command == "update" db.session.delete(msg) db.session.commit() transaction = get_latest_transaction(db.session, "draft", msg.id, default_namespace.id) assert transaction.command == "delete"
def test_thread_received_recent_date(db, api_client, default_account): date1 = datetime.datetime(2015, 1, 1, 0, 0, 0) date2 = datetime.datetime(2012, 1, 1, 0, 0, 0) thread1 = add_fake_thread(db.session, default_account.namespace.id) date_dict = dict() add_fake_message(db.session, default_account.namespace.id, thread1, subject="Test Thread 1", received_date=date1, add_sent_category=True) add_fake_message(db.session, default_account.namespace.id, thread1, subject="Test Thread 1", received_date=date2) date_dict["Test Thread 1"] = date2 thread2 = add_fake_thread(db.session, default_account.namespace.id) add_fake_message(db.session, default_account.namespace.id, thread2, subject="Test Thread 2", received_date=date1, add_sent_category=True) date_dict["Test Thread 2"] = date1 resp = api_client.get_raw('/threads/') assert resp.status_code == 200 threads = json.loads(resp.data) for thread in threads: assert date_dict[thread['subject']] == \ datetime.datetime.fromtimestamp( thread['last_message_received_timestamp'])
def test_generic_drafts_flag_constrained_by_folder(db, generic_account, folder_role): msg_uid = 22 thread = add_fake_thread(db.session, generic_account.namespace.id) message = add_fake_message(db.session, generic_account.namespace.id, thread) folder = add_fake_folder(db.session, generic_account) add_fake_imapuid(db.session, generic_account.id, message, folder, msg_uid) new_flags = {msg_uid: Flags(('\\Draft', ), None)} update_metadata(generic_account.id, folder.id, folder_role, new_flags, db.session) assert message.is_draft == (folder_role == 'drafts')
def test_updating_message_categories_increments_version( db, thread, default_namespace): assert thread.version == 0 message = add_fake_message(db.session, default_namespace.id, thread) category = add_fake_category(db.session, default_namespace.id, 'mia kategorio') # Modifying message's categories increments the thread.version message.categories = [category] db.session.commit() assert thread.version == 2
def test_exclude_account(api_client, db, default_namespace, thread): ts = int(time.time() + 22) cursor = get_cursor(api_client, ts) # Create `account`, `message`, `thread` deltas default_namespace.account.sync_state = 'invalid' db.session.commit() add_fake_message(db.session, default_namespace.id, thread) # Verify the default value of `exclude_account`=True and # the account delta is *not* included sync_data = api_client.get_data('/delta?cursor={}'.format(cursor)) assert len(sync_data['deltas']) == 2 assert set([d['object'] for d in sync_data['deltas']]) == \ set(['message', 'thread']) # Verify setting `exclude_account`=True returns the account delta as well. sync_data = api_client.get_data('/delta?cursor={}&exclude_account=false'. format(cursor)) assert len(sync_data['deltas']) == 3 assert set([d['object'] for d in sync_data['deltas']]) == \ set(['message', 'thread', 'account'])
def test_object_type_distinguishes_messages_and_drafts(db, default_namespace): with db.session.no_autoflush: thr = add_fake_thread(db.session, default_namespace.id) msg = add_fake_message(db.session, default_namespace.id, thr) msg.is_draft = 1 db.session.commit() transaction = get_latest_transaction(db.session, 'draft', msg.id, default_namespace.id) assert transaction.command == 'update' db.session.delete(msg) db.session.commit() transaction = get_latest_transaction(db.session, 'draft', msg.id, default_namespace.id) assert transaction.command == 'delete'