def test_unread_and_draft_tags_applied(db, thread, message, folder, imapuid): """Test that the unread and draft tags are added/removed from a thread after UID flag changes.""" msg_uid = imapuid.msg_uid update_metadata(ACCOUNT_ID, db.session, folder.name, folder.id, [msg_uid], {msg_uid: GmailFlags((u'\\Seen', ), (u'\\Draft', ))}) assert 'unread' not in [t.name for t in thread.tags] assert 'drafts' in [t.name for t in thread.tags] assert message.is_read update_metadata(ACCOUNT_ID, db.session, folder.name, folder.id, [msg_uid], {msg_uid: GmailFlags((), ())}) assert 'unread' in [t.name for t in thread.tags] assert 'drafts' not in [t.name for t in thread.tags] assert not message.is_read
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_gmail_drafts_flag_constrained_by_folder( db, default_account, message, imapuid, folder ): new_flags = {imapuid.msg_uid: GmailFlags((), (u"\\Draft",), None)} update_metadata(default_account.id, folder.id, "all", new_flags, db.session) assert message.is_draft update_metadata(default_account.id, folder.id, "trash", new_flags, db.session) assert not message.is_draft
def test_gmail_flags(gmail_client, constants): expected_resp = '{seq} (FLAGS {flags} X-GM-LABELS {g_labels} ' \ 'UID {uid} MODSEQ ({modseq}))'.format(**constants) unsolicited_resp = '1198 (UID 1731 MODSEQ (95244) FLAGS (\\Seen))' patch_imap4(gmail_client, [expected_resp, unsolicited_resp]) uid = constants['uid'] flags = constants['flags'] g_labels = constants['g_labels'] assert gmail_client.flags([uid]) == {uid: GmailFlags(flags, g_labels)}
def test_messages_deleted_asynchronously(db, default_account, thread, message, imapuid, folder): msg_uid = imapuid.msg_uid update_metadata(default_account.id, folder.id, {msg_uid: GmailFlags((), ('label', ))}, db.session) assert 'label' in [cat.display_name for cat in message.categories] remove_deleted_uids(default_account.id, folder.id, [msg_uid], db.session) assert abs((message.deleted_at - datetime.utcnow()).total_seconds()) < 2 # Check that message categories do get updated synchronously. assert 'label' not in [cat.display_name for cat in message.categories]
def test_only_uids_deleted_synchronously(db, default_account, default_namespace, thread, message, imapuid, folder): msg_uid = imapuid.msg_uid update_metadata(default_account.id, db.session, folder.name, folder.id, [msg_uid], {msg_uid: GmailFlags((), ('label', ))}) assert 'label' in [t.name for t in thread.tags] remove_deleted_uids(default_account.id, db.session, [msg_uid], folder.id) assert abs((message.deleted_at - datetime.utcnow()).total_seconds()) < 1 # Check that thread tags do get updated synchronously. assert 'label' not in [t.name for t in thread.tags]
def test_gmail_flags(gmail_client, constants): expected_resp = ( "{seq} (FLAGS {flags} X-GM-LABELS {raw_g_labels} " "UID {uid} MODSEQ ({modseq}))".format(**constants) ) unsolicited_resp = "1198 (UID 1731 MODSEQ (95244) FLAGS (\\Seen))" patch_imap4(gmail_client, [expected_resp, unsolicited_resp]) uid = constants["uid"] flags = constants["flags"] modseq = constants["modseq"] g_labels = constants["unicode_g_labels"] assert gmail_client.flags([uid]) == {uid: GmailFlags(flags, g_labels, modseq)}
def test_gmail_label_sync(db, default_account, message, folder, imapuid, default_namespace): # Note that IMAPClient parses numeric labels into integer types. We have to # correctly handle those too. new_flags = { imapuid.msg_uid: GmailFlags((), (u'\\Important', u'\\Starred', u'foo', 42), None) } update_metadata(default_namespace.account.id, folder.id, folder.canonical_name, new_flags, db.session) category_canonical_names = {c.name for c in message.categories} category_display_names = {c.display_name for c in message.categories} assert 'important' in category_canonical_names assert {'foo', '42'}.issubset(category_display_names)
def test_renamed_label_refresh(db, default_account, thread, message, imapuid, folder, mock_imapclient, monkeypatch): # Check that imapuids see their labels refreshed after running # the LabelRenameHandler. msg_uid = imapuid.msg_uid uid_dict = {msg_uid: GmailFlags((), ('stale label', ), ('23', ))} update_metadata(default_account.id, folder.id, folder.canonical_name, uid_dict, db.session) new_flags = { msg_uid: { 'FLAGS': ('\\Seen', ), 'X-GM-LABELS': ('new label', ), 'MODSEQ': ('23', ) } } mock_imapclient._data['[Gmail]/All mail'] = new_flags mock_imapclient.add_folder_data(folder.name, new_flags) monkeypatch.setattr(MockIMAPClient, 'search', lambda x, y: [msg_uid]) semaphore = Semaphore(value=1) rename_handler = LabelRenameHandler(default_account.id, default_account.namespace.id, 'new label', semaphore) # Acquire the semaphore to check that LabelRenameHandlers block if # the semaphore is in-use. semaphore.acquire() rename_handler.start() # Wait 10 secs and check that the data hasn't changed. gevent.sleep(10) labels = list(imapuid.labels) assert len(labels) == 1 assert labels[0].name == 'stale label' semaphore.release() rename_handler.join() db.session.refresh(imapuid) # Now check that the label got updated. labels = list(imapuid.labels) assert len(labels) == 1 assert labels[0].name == 'new label'
def test_gmail_label_sync(db, default_account, message, thread, folder, imapuid): if default_account.important_folder is not None: db.session.delete(default_account.important_folder) msg_uid = imapuid.msg_uid # Note that IMAPClient parses numeric labels into integer types. We have to # correctly handle those too. new_flags = { msg_uid: GmailFlags((), (u'\\Important', u'\\Starred', u'foo', 42)) } update_metadata(ACCOUNT_ID, db.session, folder.name, folder.id, [msg_uid], new_flags) thread_tag_names = {tag.name for tag in thread.tags} assert {'important', 'starred', 'foo'}.issubset(thread_tag_names)
def test_messages_deleted_asynchronously(db, default_account, thread, message, imapuid, folder): msg_uid = imapuid.msg_uid update_metadata( default_account.id, folder.id, folder.canonical_name, {msg_uid: GmailFlags((), ("label", ), None)}, db.session, ) assert "label" in [cat.display_name for cat in message.categories] remove_deleted_uids(default_account.id, folder.id, [msg_uid]) db.session.expire_all() assert abs((message.deleted_at - datetime.utcnow()).total_seconds()) < 2 # Check that message categories do get updated synchronously. assert "label" not in [cat.display_name for cat in message.categories]
def test_renamed_label_refresh(db, default_account, thread, message, imapuid, folder, mock_imapclient, monkeypatch): # Check that imapuids see their labels refreshed after running # the LabelRenameHandler. msg_uid = imapuid.msg_uid uid_dict = {msg_uid: GmailFlags((), ("stale label", ), ("23", ))} update_metadata(default_account.id, folder.id, folder.canonical_name, uid_dict, db.session) new_flags = { msg_uid: { b"FLAGS": (b"\\Seen", ), b"X-GM-LABELS": (b"new label", ), b"MODSEQ": (23, ), } } mock_imapclient._data["[Gmail]/All mail"] = new_flags mock_imapclient.add_folder_data(folder.name, new_flags) monkeypatch.setattr(MockIMAPClient, "search", lambda x, y: [msg_uid]) semaphore = Semaphore(value=1) rename_handler = LabelRenameHandler(default_account.id, default_account.namespace.id, "new label", semaphore) # Acquire the semaphore to check that LabelRenameHandlers block if # the semaphore is in-use. semaphore.acquire() rename_handler.start() gevent.sleep(0) # yield to the handler labels = list(imapuid.labels) assert len(labels) == 1 assert labels[0].name == "stale label" semaphore.release() rename_handler.join() db.session.refresh(imapuid) # Now check that the label got updated. labels = list(imapuid.labels) assert len(labels) == 1 assert labels[0].name == "new label"
def test_deleted_labels_get_gced(empty_db, default_account, thread, message, imapuid, folder): # Check that only the labels without messages attached to them # get deleted. default_namespace = default_account.namespace # Create a label w/ no messages attached. label = Label.find_or_create(empty_db.session, default_account, "dangling label") label.deleted_at = datetime.utcnow() label.category.deleted_at = datetime.utcnow() label_id = label.id empty_db.session.commit() # Create a label with attached messages. msg_uid = imapuid.msg_uid update_metadata( default_account.id, folder.id, folder.canonical_name, {msg_uid: GmailFlags((), ("label", ), None)}, empty_db.session, ) label_ids = [] for cat in message.categories: for l in cat.labels: label_ids.append(l.id) 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, ) handler.gc_deleted_categories() empty_db.session.commit() # Check that the first label got gc'ed marked_deleted = empty_db.session.query(Label).get(label_id) assert marked_deleted is None # Check that the other labels didn't. for label_id in label_ids: assert empty_db.session.query(Label).get(label_id) is not None
def test_update_metadata(db): """Check that threads are updated correctly when a label that we haven't seen before is added to multiple threads -- previously, this would with an IntegrityError because autoflush was disabled.""" first_thread = db.session.query(Thread).get(1) second_thread = db.session.query(Thread).get(2) folder = db.session.query(Folder).filter( Folder.account_id == ACCOUNT_ID, Folder.name == '[Gmail]/All Mail').one() 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( ImapUid(account_id=ACCOUNT_ID, message=message, msg_uid=msg_uid, folder=folder)) second_thread_uids = (22224, 22226) for msg_uid in second_thread_uids: message = add_fake_message(db.session, NAMESPACE_ID, second_thread) uids.append( ImapUid(account_id=ACCOUNT_ID, message=message, msg_uid=msg_uid, folder=folder)) 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_gmail_label_sync(db): folder = db.session.query(Folder).filter( Folder.account_id == ACCOUNT_ID, Folder.name == '[Gmail]/All Mail').one() account = db.session.query(Account).get(ACCOUNT_ID) if account.important_folder is not None: db.session.delete(account.important_folder) thread = db.session.query(Thread).get(1) message = add_fake_message(db.session, NAMESPACE_ID, thread) db.session.add( ImapUid(account_id=ACCOUNT_ID, message=message, msg_uid=22222, folder=folder)) db.session.commit() new_flags = {22222: GmailFlags((), (u'\\Important', u'\\Starred', u'foo'))} update_metadata(ACCOUNT_ID, db.session, folder.name, folder.id, [22222], new_flags) thread_tag_names = {tag.name for tag in thread.tags} assert {'important', 'starred', 'foo'}.issubset(thread_tag_names)