def test_add_remove_tags_by_name(api_client, thread, db, default_namespace): add_fake_thread(db.session, default_namespace.id) assert 'foo' not in [tag['name'] for tag in api_client.get_data('/tags/')] assert 'bar' not in [tag['name'] for tag in api_client.get_data('/tags/')] api_client.post_data('/tags/', {'name': 'foo'}) api_client.post_data('/tags/', {'name': 'bar'}) thread_id = api_client.get_data('/threads/')[0]['id'] thread_path = '/threads/{}'.format(thread_id) api_client.put_data(thread_path, {'add_tags': ['foo']}) api_client.put_data(thread_path, {'add_tags': ['bar']}) tag_names = [tag['name'] for tag in api_client.get_data(thread_path)['tags']] assert 'foo' in tag_names assert 'bar' in tag_names # Check that tag was only applied to this thread another_thread_id = api_client.get_data('/threads/')[1]['id'] tag_names = get_tag_names( api_client.get_data('/threads/{}'.format(another_thread_id))) assert 'foo' not in tag_names api_client.put_data(thread_path, {'remove_tags': ['foo']}) api_client.put_data(thread_path, {'remove_tags': ['bar']}) tag_names = get_tag_names(api_client.get_data(thread_path)) assert 'foo' not in tag_names assert 'bar' not in tag_names
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) new_namespace = Namespace() db.session.add(new_namespace) db.session.commit() message = add_fake_message(db.session, new_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_add_remove_tags_by_name(api_client, thread, db, default_namespace): add_fake_thread(db.session, default_namespace.id) assert 'foo' not in [tag['name'] for tag in api_client.get_data('/tags/')] assert 'bar' not in [tag['name'] for tag in api_client.get_data('/tags/')] api_client.post_data('/tags/', {'name': 'foo'}) api_client.post_data('/tags/', {'name': 'bar'}) thread_id = api_client.get_data('/threads/')[0]['id'] thread_path = '/threads/{}'.format(thread_id) api_client.put_data(thread_path, {'add_tags': ['foo']}) api_client.put_data(thread_path, {'add_tags': ['bar']}) tag_names = [ tag['name'] for tag in api_client.get_data(thread_path)['tags'] ] assert 'foo' in tag_names assert 'bar' in tag_names # Check that tag was only applied to this thread another_thread_id = api_client.get_data('/threads/')[1]['id'] tag_names = get_tag_names( api_client.get_data('/threads/{}'.format(another_thread_id))) assert 'foo' not in tag_names api_client.put_data(thread_path, {'remove_tags': ['foo']}) api_client.put_data(thread_path, {'remove_tags': ['bar']}) tag_names = get_tag_names(api_client.get_data(thread_path)) assert 'foo' not in tag_names assert 'bar' not in tag_names
def test_update_metadata(db, folder): """Check that threads are updated correctly when a label that we haven't seen before is added to multiple threads -- previously, this would fail with an IntegrityError because autoflush was disabled.""" first_thread = add_fake_thread(db.session, NAMESPACE_ID) second_thread = add_fake_thread(db.session, NAMESPACE_ID) uids = [] first_thread_uids = (22222, 22223) for msg_uid in first_thread_uids: message = add_fake_message(db.session, NAMESPACE_ID, first_thread) uids.append(add_fake_imapuid(db.session, ACCOUNT_ID, message, folder, msg_uid)) second_thread_uids = (22224, 22226) for msg_uid in second_thread_uids: message = add_fake_message(db.session, NAMESPACE_ID, second_thread) uids.append(add_fake_imapuid(db.session, ACCOUNT_ID, message, folder, msg_uid)) db.session.add_all(uids) db.session.commit() msg_uids = first_thread_uids + second_thread_uids new_flags = {msg_uid: GmailFlags((), (u"\\some_new_label",)) for msg_uid in msg_uids} update_metadata(ACCOUNT_ID, db.session, folder.name, folder.id, msg_uids, new_flags) db.session.commit() assert "some_new_label" in [tag.name for tag in first_thread.tags] assert "some_new_label" in [tag.name for tag in second_thread.tags]
def test_data_deduplication(s3_db, raw_message): from inbox.models import Namespace default_namespace = s3_db.session.query(Namespace).get(1) thread = add_fake_thread(s3_db.session, default_namespace.id) msg = new_message_from_synced(s3_db, default_namespace.account, raw_message) msg.thread = thread s3_db.session.add(msg) s3_db.session.commit() account = add_fake_account(s3_db.session) thread = add_fake_thread(s3_db.session, account.namespace.id) duplicate_msg = new_message_from_synced(s3_db, account, raw_message) duplicate_msg.thread = thread s3_db.session.add(duplicate_msg) s3_db.session.commit() assert len(msg.parts) == len(duplicate_msg.parts) for i in range(len(msg.parts)): msg_block = msg.parts[i].block duplicate_msg_block = duplicate_msg.parts[i].block assert msg_block.namespace_id == msg.namespace_id assert duplicate_msg_block.namespace_id == duplicate_msg.namespace_id assert msg_block.size == duplicate_msg_block.size assert msg_block.data_sha256 == duplicate_msg_block.data_sha256 assert msg_block.data == duplicate_msg_block.data
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.client.get(api_client.full_path('/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_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_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_update_metadata(db, folder): """Check that threads are updated correctly when a label that we haven't seen before is added to multiple threads -- previously, this would fail with an IntegrityError because autoflush was disabled.""" first_thread = add_fake_thread(db.session, NAMESPACE_ID) second_thread = add_fake_thread(db.session, NAMESPACE_ID) uids = [] first_thread_uids = (22222, 22223) for msg_uid in first_thread_uids: message = add_fake_message(db.session, NAMESPACE_ID, first_thread) uids.append( add_fake_imapuid(db.session, ACCOUNT_ID, message, folder, msg_uid)) second_thread_uids = (22224, 22226) for msg_uid in second_thread_uids: message = add_fake_message(db.session, NAMESPACE_ID, second_thread) uids.append( add_fake_imapuid(db.session, ACCOUNT_ID, message, folder, msg_uid)) db.session.add_all(uids) db.session.commit() msg_uids = first_thread_uids + second_thread_uids new_flags = { msg_uid: GmailFlags((), (u'\\some_new_label', )) for msg_uid in msg_uids } update_metadata(ACCOUNT_ID, db.session, folder.name, folder.id, msg_uids, new_flags) db.session.commit() assert 'some_new_label' in [tag.name for tag in first_thread.tags] assert 'some_new_label' in [tag.name for tag in second_thread.tags]
def test_data_deduplication(db, default_namespace, raw_message): thread = add_fake_thread(db.session, default_namespace.id) msg = new_message_from_synced(db, default_namespace.account, raw_message) msg.thread = thread db.session.add(msg) db.session.commit() account = add_fake_account(db.session) thread = add_fake_thread(db.session, account.namespace.id) duplicate_msg = new_message_from_synced(db, account, raw_message) duplicate_msg.thread = thread db.session.add(duplicate_msg) db.session.commit() assert len(msg.parts) == len(duplicate_msg.parts) for i in range(len(msg.parts)): msg_block = msg.parts[i].block duplicate_msg_block = duplicate_msg.parts[i].block assert msg_block.namespace_id == msg.namespace_id assert duplicate_msg_block.namespace_id == duplicate_msg.namespace_id assert msg_block.size == duplicate_msg_block.size assert msg_block.data_sha256 == duplicate_msg_block.data_sha256 assert msg_block.data == duplicate_msg_block.data
def test_received_before_after(db, api_client, default_namespace): thread = add_fake_thread(db.session, default_namespace.id) message = add_fake_message(db.session, default_namespace.id, thread, to_addr=[('Bob', '*****@*****.**')], from_addr=[('Alice', '*****@*****.**')], received_date=datetime.datetime(year=1999, day=20, month=03), subject='some subject') thread2 = add_fake_thread(db.session, default_namespace.id) message2 = add_fake_message(db.session, default_namespace.id, thread, to_addr=[('Bob', '*****@*****.**')], from_addr=[('Alice', '*****@*****.**')], received_date=datetime.datetime(year=2000, day=20, month=03), subject='another subject') inbox = Category(namespace_id=message.namespace_id, name='inbox', display_name='Inbox', type_='label') message.categories.add(inbox) thread.subject = message.subject message2.categories.add(inbox) thread2.subject = message2.subject db.session.commit() received_date = message.received_date t_epoch = dt_to_timestamp(datetime.datetime(year=1998, month=2, day=3)) t_firstmsg = dt_to_timestamp(received_date) results = api_client.get_data('/messages?received_before={}' .format(t_epoch)) assert len(results) == 0 # received_before should be inclusive (i.e: match <=, not just <). results = api_client.get_data('/messages?received_before={}' .format(t_firstmsg)) assert len(results) == 1 t1 = dt_to_timestamp(received_date + datetime.timedelta(days=1)) results = api_client.get_data('/messages?received_after={}' .format(t1)) assert len(results) == 1 results = api_client.get_data( '/messages?received_before={}&received_after={}'.format(t1, t_firstmsg)) assert len(results) == 0 # bogus values results = api_client.get_data( '/messages?received_before={}&received_after={}'.format(t_epoch, t1)) assert len(results) == 0
def test_namespace_deletion(db, default_account): from inbox.models import (Account, Thread, Message, Block, Contact, Event, Transaction) 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_fake_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 # Delete namespace, verify data corresponding to this namespace /only/ # is deleted delete_namespace(account_id, namespace_id) db.session.commit() 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_namespace_deletion(db, default_account): from inbox.models import (Account, Thread, Message, Block, Contact, Event, Transaction) 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_fake_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 # Delete namespace, verify data corresponding to this namespace /only/ # is deleted delete_namespace(account_id, namespace_id) db.session.commit() 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_generic_grouping(db, generic_account): thread = add_fake_thread(db.session, NAMESPACE_ID) message = add_fake_message(db.session, NAMESPACE_ID, thread, subject="Golden Gate Park next Sat") imapuid = ImapUid(message=message, account_id=ACCOUNT_ID, msg_uid=2222) thread = add_fake_thread(db.session, generic_account.namespace.id) message = add_fake_message(db.session, NAMESPACE_ID + 1, thread, subject="Golden Gate Park next Sat") thread = fetch_corresponding_thread(db.session, generic_account.namespace.id, message) assert thread is None, ("fetch_similar_threads should " "heed namespace boundaries")
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_fake_message(db.session, default_namespace.id, first_thread, from_addr=[('', '*****@*****.**')], received_date=datetime.datetime.utcnow()) # 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_fake_message(db.session, default_namespace.id, second_thread, from_addr=[('', '*****@*****.**')], received_date=older_date) 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
def test_thread_insert_creates_transaction(db): with session_scope() as db_session: thr = add_fake_thread(db_session, NAMESPACE_ID) transaction = get_latest_transaction(db_session, 'thread', thr.id, NAMESPACE_ID) assert transaction.command == 'insert' assert transaction.snapshot
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 add_completely_fake_account(db, email="*****@*****.**"): fake_account = add_fake_gmail_account(db.session, email_address=email) calendar = add_fake_calendar(db.session, fake_account.namespace.id) for i in random_range(1, 10): add_fake_event( db.session, fake_account.namespace.id, calendar=calendar, title="%s" % i ) # Add fake Threads, Messages and ImapUids. folder = add_fake_folder(db.session, fake_account) for i in random_range(1, 4): th = add_fake_thread(db.session, fake_account.namespace.id) for j in random_range(1, 3): msg = add_fake_msg_with_calendar_part( db.session, fake_account, "fake part", thread=th ) db.session.add(msg) db.session.flush() for k in random_range(1, 2): add_fake_imapuid( db.session, fake_account.id, msg, folder, int("%s%s" % (msg.id, k)) ) # Add fake contacts for i in random_range(1, 5): add_fake_contact(db.session, fake_account.namespace.id, uid=str(i)) db.session.commit() return fake_account
def test_deleting_from_a_message_with_multiple_uids(db): # Now check that deleting a imapuid from a message with # multiple uids doesn't delete the message itself ACCOUNT_ID = 1 NAMESPACE_ID = 1 account = db.session.query(Account).get(ACCOUNT_ID) inbox_folder = account.inbox_folder sent_folder = account.sent_folder thread = add_fake_thread(db.session, NAMESPACE_ID,) message = add_fake_message(db.session, NAMESPACE_ID, thread) sent_uid = ImapUid(message=message, account=account, folder=sent_folder, msg_uid=1337) inbox_uid = ImapUid(message=message, account=account, folder=inbox_folder, msg_uid=2222) db.session.add(sent_uid) db.session.add(inbox_uid) db.session.commit() remove_messages(ACCOUNT_ID, db.session, [2222], inbox_folder.name) msg = db.session.query(Message).get(message.id) assert msg is not None, "the associated message should not have been deleted" assert len(msg.imapuids) == 1, "the message should have only one imapuid"
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): # 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 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
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_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_message_updates_create_transaction(db): with session_scope() as db_session: with db_session.no_autoflush: thr = add_fake_thread(db_session, NAMESPACE_ID) msg = add_fake_message(db_session, NAMESPACE_ID, thr) msg.is_read = True db_session.commit() transaction = get_latest_transaction(db_session, 'message', msg.id, NAMESPACE_ID) assert transaction.record_id == msg.id assert transaction.object_type == 'message' assert transaction.command == 'update' msg = add_fake_message(db_session, NAMESPACE_ID, thr) msg.state = 'sent' db_session.commit() transaction = get_latest_transaction(db_session, 'message', msg.id, NAMESPACE_ID) assert transaction.record_id == msg.id assert transaction.object_type == 'message' assert transaction.command == 'update' msg = add_fake_message(db_session, NAMESPACE_ID, thr) msg.is_draft = True db_session.commit() transaction = get_latest_transaction(db_session, 'message', msg.id, NAMESPACE_ID) assert transaction.record_id == msg.id assert transaction.object_type == 'message' assert transaction.command == 'update'
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_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_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_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_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_unread(db, default_namespace): from inbox.models import Thread thread = add_fake_thread(db.session, default_namespace.id) thread_id = thread.id message = add_fake_message(db.session, default_namespace.id, thread) unread_tag = default_namespace.tags['unread'] assert unread_tag in thread.tags assert message.is_read is False thread.remove_tag(unread_tag) db.session.commit() thread = db.session.query(Thread).get(thread_id) assert unread_tag not in thread.tags for m in thread.messages: assert m.is_read is True thread.apply_tag(unread_tag) db.session.commit() thread = db.session.query(Thread).get(thread_id) assert unread_tag in thread.tags for m in thread.messages: assert m.is_read is False
def test_file_transactions(db, default_namespace): from inbox.models.message import Message account = default_namespace.account thread = add_fake_thread(db.session, default_namespace.id) mime_msg = mime.create.multipart('mixed') mime_msg.append( mime.create.text('plain', 'This is a message with attachments'), mime.create.attachment('image/png', 'filler', 'attached_image.png', 'attachment'), mime.create.attachment('application/pdf', 'filler', 'attached_file.pdf', 'attachment')) msg = Message.create_from_synced(account, 22, '[Gmail]/All Mail', datetime.utcnow(), mime_msg.to_string()) msg.thread = thread db.session.add(msg) db.session.commit() assert len(msg.parts) == 2 assert all(part.content_disposition == 'attachment' for part in msg.parts) block_ids = [part.block.id for part in msg.parts] with db.session.no_autoflush: transaction = get_latest_transaction(db.session, 'file', block_ids[0], default_namespace.id) assert transaction.command == 'insert' transaction = get_latest_transaction(db.session, 'file', block_ids[1], default_namespace.id) assert transaction.command == 'insert'
def test_file_transactions(db, default_namespace): from inbox.models.message import Message account = default_namespace.account thread = add_fake_thread(db.session, default_namespace.id) mime_msg = mime.create.multipart("mixed") mime_msg.append( mime.create.text("plain", "This is a message with attachments"), mime.create.attachment("image/png", "filler", "attached_image.png", "attachment"), mime.create.attachment("application/pdf", "filler", "attached_file.pdf", "attachment"), ) msg = Message.create_from_synced(account, 22, "[Gmail]/All Mail", datetime.utcnow(), mime_msg.to_string()) msg.thread = thread db.session.add(msg) db.session.commit() assert len(msg.parts) == 2 assert all(part.content_disposition == "attachment" for part in msg.parts) block_ids = [part.block.id for part in msg.parts] with db.session.no_autoflush: transaction = get_latest_transaction(db.session, "file", block_ids[0], default_namespace.id) assert transaction.command == "insert" transaction = get_latest_transaction(db.session, "file", block_ids[1], default_namespace.id) assert transaction.command == "insert"
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_unread(db, default_namespace): from inbox.models import Thread thread = add_fake_thread(db.session, default_namespace.id) thread_id = thread.id message = add_fake_message(db.session, default_namespace.id, thread) db.session.commit() unread_tag = default_namespace.tags['unread'] if unread_tag in thread.tags: assert message.is_read is False thread.remove_tag(unread_tag) db.session.commit() thread = db.session.query(Thread).get(thread_id) assert unread_tag not in thread.tags for m in thread.messages: assert m.is_read is True thread.apply_tag(unread_tag) db.session.commit() thread = db.session.query(Thread).get(thread_id) assert unread_tag in thread.tags for m in thread.messages: assert m.is_read is False
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_accounttransactions(db, default_namespace): account = default_namespace.account transaction = get_latest_transaction(db.session, 'account', default_namespace.account.id, default_namespace.id) assert transaction.command == 'insert' transaction_id = transaction.id # Verify an AccountTransaction is created accounttransactions = db.session.query(AccountTransaction).filter( AccountTransaction.namespace_id == default_namespace.id).all() assert len(accounttransactions) == 1 accounttransaction = accounttransactions[0] assert accounttransaction.namespace_id == default_namespace.id assert accounttransaction.command == 'insert' assert accounttransaction.object_type == 'account' assert accounttransaction.record_id == default_namespace.account.id accounttransaction_id = accounttransaction.id with db.session.no_autoflush: # No Transaction or AccountTransaction records created account.last_synced_events = datetime.utcnow() db.session.commit() transaction = get_latest_transaction(db.session, 'account', default_namespace.account.id, default_namespace.id) assert transaction.id == transaction_id accounttransactions = db.session.query(AccountTransaction).filter( AccountTransaction.namespace_id == default_namespace.id).all() assert len(accounttransactions) == 1 assert accounttransactions[0].id == accounttransaction_id # Only Transaction record created thread = add_fake_thread(db.session, default_namespace.id) transaction = get_latest_transaction(db.session, 'thread', thread.id, default_namespace.id) assert transaction.id > transaction_id accounttransactions = db.session.query(AccountTransaction).filter( AccountTransaction.namespace_id == default_namespace.id).all() assert len(accounttransactions) == 1 assert accounttransactions[0].id == accounttransaction_id # Both Transaction or AccountTransaction records created account.sync_state = 'invalid' db.session.commit() transaction = get_latest_transaction(db.session, 'account', default_namespace.account.id, default_namespace.id) assert transaction.id > transaction_id assert transaction.command == 'update' accounttransactions = db.session.query(AccountTransaction).filter( AccountTransaction.namespace_id == default_namespace.id).all() assert len(accounttransactions) == 2 assert accounttransactions[1].id != accounttransaction_id assert accounttransactions[1].command == 'update'
def test_gmail_pagination(db, default_account, patch_crispin_client, patch_handler_from_provider, folder): for i in range(10): thread = add_fake_thread(db.session, default_account.namespace.id) message = add_fake_message(db.session, default_account.namespace.id, thread=thread, from_addr=[{ 'name': '', 'email': '{}@test.com'.format(str(i)) }], subject='hi', g_msgid=i, received_date=datetime.datetime( 2000 + i, 1, 1, 1, 0, 0)) add_fake_imapuid(db.session, default_account.id, message, folder, i) first_ten_messages_db = db.session.query(Message)\ .filter(Message.namespace_id == default_account.namespace.id). \ order_by(desc(Message.received_date)). \ limit(10).all() api_client = new_api_client(db, default_account.namespace) first_ten_messages_api = api_client.get_data('/messages/search?q=hi' '&limit=10') assert len(first_ten_messages_api) == len(first_ten_messages_db) for db_message, api_message in zip(first_ten_messages_db, first_ten_messages_api): assert db_message.public_id == api_message['id'] imap_uids = db.session.query(ImapUid).join(Message) \ .filter( ImapUid.message_id == Message.id, Message.g_msgid != None).all() uids = [uid.msg_uid for uid in imap_uids] first_ten_threads_db = db.session.query(Thread) \ .join(Message) \ .join(ImapUid) \ .filter(ImapUid.account_id == default_account.id, ImapUid.msg_uid.in_(uids), Thread.id == Message.thread_id)\ .order_by(desc(Message.received_date)) \ .limit(10).all() first_ten_threads_api = api_client.get_data('/threads/search?q=hi' '&limit=10') assert len(first_ten_threads_api) == len(first_ten_threads_db) for db_thread, api_thread in zip(first_ten_threads_db, first_ten_threads_api): assert db_thread.public_id == api_thread['id']
def test_folders_labels_delete(db, api_client, generic_account, gmail_account): api_client = new_api_client(db, generic_account.namespace) # Generic IMAP threads, messages have a 'folders' field generic_thread = add_fake_thread(db.session, generic_account.namespace.id) generic_message = add_fake_message(db.session, generic_account.namespace.id, generic_thread) resp = api_client.post_data('/folders/', {"display_name": "Test_Folder"}) assert resp.status_code == 200 generic_folder = json.loads(resp.data) data = {"folder_id": generic_folder['id']} # Add message to folder api_client.put_data('/messages/{}'.format(generic_message.public_id), data) # try deleting folder that contains a message delete_data = api_client.delete('/folders/{}'.format(generic_folder['id'])) assert delete_data.status_code == 403 resp = api_client.post_data('/folders/', {"display_name": "Test_Folder2"}) empty_folder = json.loads(resp.data) # try deleting folder that contains a message delete_data = api_client.delete('/folders/{}'.format(empty_folder['id'])) assert delete_data.status_code == 200 # Because we're using the generic_account namespace api_client = new_api_client(db, gmail_account.namespace) # Gmail threads, messages have a 'labels' field gmail_thread = add_fake_thread(db.session, gmail_account.namespace.id) gmail_message = add_fake_message(db.session, gmail_account.namespace.id, gmail_thread) resp = api_client.post_data('/labels/', {"display_name": "Test_Labels"}) assert resp.status_code == 200 gmail_label = json.loads(resp.data) data = {"folder_id": gmail_label['id']} # Add label to message api_client.put_data('/messages/{}'.format(gmail_message.public_id), data) # try deleting label delete_data = api_client.delete('/labels/{}'.format(gmail_label['id'])) assert delete_data.status_code == 200
def stub_message_from_raw(db, new_message_from_synced): NAMESPACE_ID = default_namespace(db).id new_msg = new_message_from_synced fake_thread = add_fake_thread(db.session, NAMESPACE_ID) new_msg.thread = fake_thread db.session.add_all([new_msg, fake_thread]) db.session.commit() return new_msg
def test_folders_labels(db, api_client, generic_account, gmail_account): # Generic IMAP threads, messages have a 'folders' field generic_thread = add_fake_thread(db.session, generic_account.namespace.id) generic_message = add_fake_message(db.session, generic_account.namespace.id, generic_thread) # Because we're using the generic_account namespace api_client = new_api_client(db, generic_account.namespace) resp_data = api_client.get_data( '/threads/{}'.format(generic_thread.public_id)) assert resp_data['id'] == generic_thread.public_id assert resp_data['object'] == 'thread' assert 'folders' in resp_data and 'labels' not in resp_data resp_data = api_client.get_data( '/messages/{}'.format(generic_message.public_id)) assert resp_data['id'] == generic_message.public_id assert resp_data['object'] == 'message' assert 'folder' in resp_data and 'labels' not in resp_data # Because we're using the generic_account namespace api_client = new_api_client(db, gmail_account.namespace) # Gmail threads, messages have a 'labels' field gmail_thread = add_fake_thread(db.session, gmail_account.namespace.id) gmail_message = add_fake_message(db.session, gmail_account.namespace.id, gmail_thread) resp_data = api_client.get_data( '/threads/{}'.format(gmail_thread.public_id)) assert resp_data['id'] == gmail_thread.public_id assert resp_data['object'] == 'thread' assert 'labels' in resp_data and 'folders' not in resp_data resp_data = api_client.get_data( '/messages/{}'.format(gmail_message.public_id)) assert resp_data['id'] == gmail_message.public_id assert resp_data['object'] == 'message' assert 'labels' in resp_data and 'folders' not in resp_data
def test_folders_labels(db, api_client, generic_account, gmail_account): # Generic IMAP threads, messages have a 'folders' field generic_thread = add_fake_thread(db.session, generic_account.namespace.id) generic_message = add_fake_message(db.session, generic_account.namespace.id, generic_thread) # Because we're using the generic_account namespace api_client = new_api_client(db, generic_account.namespace) resp_data = api_client.get_data('/threads/{}'.format( generic_thread.public_id)) assert resp_data['id'] == generic_thread.public_id assert resp_data['object'] == 'thread' assert 'folders' in resp_data and 'labels' not in resp_data resp_data = api_client.get_data('/messages/{}'.format( generic_message.public_id)) assert resp_data['id'] == generic_message.public_id assert resp_data['object'] == 'message' assert 'folder' in resp_data and 'labels' not in resp_data # Because we're using the generic_account namespace api_client = new_api_client(db, gmail_account.namespace) # Gmail threads, messages have a 'labels' field gmail_thread = add_fake_thread(db.session, gmail_account.namespace.id) gmail_message = add_fake_message(db.session, gmail_account.namespace.id, gmail_thread) resp_data = api_client.get_data('/threads/{}'.format( gmail_thread.public_id)) assert resp_data['id'] == gmail_thread.public_id assert resp_data['object'] == 'thread' assert 'labels' in resp_data and 'folders' not in resp_data resp_data = api_client.get_data('/messages/{}'.format( gmail_message.public_id)) assert resp_data['id'] == gmail_message.public_id assert resp_data['object'] == 'message' assert 'labels' in resp_data and 'folders' not in resp_data
def create_from_synced(db, account, raw_message): thread = add_fake_thread(db.session, account.namespace.id) received_date = datetime.datetime.utcnow() m = Message.create_from_synced(account, 22, "[Gmail]/All Mail", received_date, raw_message) m.thread = thread db.session.add(m) db.session.commit() return m
def test_generic_foldersyncengine(db, folder_sync_engine): thread = add_fake_thread(db.session, NAMESPACE_ID) message = add_fake_message(db.session, NAMESPACE_ID, thread, subject="Golden Gate Park next Sat") imapuid = ImapUid(message=message, account_id=ACCOUNT_ID, msg_uid=2222) messages = folder_sync_engine.fetch_similar_threads(db.session, imapuid) assert messages == [], ("fetch_similar_threads should " "heed namespace boundaries")
def stub_message_from_raw(db, raw_message): namespace_id = default_namespace(db).id new_msg = new_message_from_synced(db, default_namespace(db).account, raw_message) fake_thread = add_fake_thread(db.session, namespace_id) new_msg.thread = fake_thread db.session.add_all([new_msg, fake_thread]) db.session.commit() return new_msg
def create_from_synced(db, account, raw_message): thread = add_fake_thread(db.session, account.namespace.id) received_date = datetime.datetime.utcnow() m = Message.create_from_synced(account, 22, '[Gmail]/All Mail', received_date, raw_message) m.thread = thread db.session.add(m) db.session.commit() return m
def test_gmail_pagination(db, default_account, patch_crispin_client, patch_handler_from_provider, folder): for i in range(10): thread = add_fake_thread(db.session, default_account.namespace.id) message = add_fake_message(db.session, default_account.namespace.id, thread=thread, from_addr=[{'name': '', 'email': '{}@test.com'.format(str(i))}], subject='hi', g_msgid=i, received_date=datetime. datetime(2000 + i, 1, 1, 1, 0, 0)) add_fake_imapuid(db.session, default_account.id, message, folder, i) first_ten_messages_db = db.session.query(Message)\ .filter(Message.namespace_id == default_account.namespace.id). \ order_by(desc(Message.received_date)). \ limit(10).all() api_client = new_api_client(db, default_account.namespace) first_ten_messages_api = api_client.get_data('/messages/search?q=hi' '&limit=10') assert len(first_ten_messages_api) == len(first_ten_messages_db) for db_message, api_message in zip(first_ten_messages_db, first_ten_messages_api): assert db_message.public_id == api_message['id'] imap_uids = db.session.query(ImapUid).join(Message) \ .filter( ImapUid.message_id == Message.id, Message.g_msgid != None).all() uids = [uid.msg_uid for uid in imap_uids] first_ten_threads_db = db.session.query(Thread) \ .join(Message) \ .join(ImapUid) \ .filter(ImapUid.account_id == default_account.id, ImapUid.msg_uid.in_(uids), Thread.id == Message.thread_id)\ .order_by(desc(Message.received_date)) \ .limit(10).all() first_ten_threads_api = api_client.get_data('/threads/search?q=hi' '&limit=10') assert len(first_ten_threads_api) == len(first_ten_threads_db) for db_thread, api_thread in zip(first_ten_threads_db, first_ten_threads_api): assert db_thread.public_id == api_thread['id']
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")