def test_delete_from_readonly_calendar(db, default_namespace, api_client): add_fake_event(db.session, default_namespace.id, calendar=db.session.query(Calendar).filter( Calendar.namespace_id == default_namespace.id, Calendar.read_only == True).first(), # noqa read_only=True) calendar_list = api_client.get_data('/calendars') read_only_calendar = None for c in calendar_list: if c['read_only']: read_only_calendar = c break events = api_client.get_data('/events?calendar_id={}'.format( read_only_calendar['id'])) for event in events: if event['read_only']: read_only_event = event break assert read_only_calendar assert read_only_event e_id = read_only_event['id'] resp = api_client.delete('/events/{}'.format(e_id)) assert resp.status_code == 400
def test_api_get(contacts_provider, contact_sync, db, api_client, default_namespace): contacts_provider.supply_contact('Contact One', '*****@*****.**') contacts_provider.supply_contact('Contact Two', '*****@*****.**') contact_sync.provider = contacts_provider contact_sync.sync() ns_id = default_namespace.public_id contact_list = api_client.get_data('/contacts', ns_id) contact_ids = [contact['id'] for contact in contact_list] c1found = False c2found = False for c_id in contact_ids: contact = api_client.get_data('/contacts/' + c_id, ns_id) if contact['name'] == 'Contact One': c1found = True if contact['name'] == 'Contact Two': c2found = True assert c1found assert c2found
def test_api_get(db, api_client, calendar): e_data = {'title': 'subj', 'when': {'time': 1}, 'calendar_id': calendar.public_id, 'location': 'InboxHQ'} e_data2 = {'title': 'subj2', 'when': {'time': 1}, 'calendar_id': calendar.public_id, 'location': 'InboxHQ'} api_client.post_data('/events', e_data) api_client.post_data('/events', e_data2) event_list = api_client.get_data('/events') event_ids = [event['id'] for event in event_list] c1found = False c2found = False for c_id in event_ids: event = api_client.get_data('/events/' + c_id) if event['title'] == 'subj': c1found = True if event['title'] == 'subj2': c2found = True assert c1found assert c2found
def test_contacts_updated(api_client): """Tests that draft-contact associations are properly created and updated.""" draft = { 'to': [{'email': '*****@*****.**'}, {'email': '*****@*****.**'}] } r = api_client.post_data('/drafts', draft) assert r.status_code == 200 draft_id = json.loads(r.data)['id'] draft_version = json.loads(r.data)['version'] r = api_client.get_data('/[email protected]') assert len(r) == 1 updated_draft = { 'to': [{'email': '*****@*****.**'}, {'email': '*****@*****.**'}], 'version': draft_version } r = api_client.put_data('/drafts/{}'.format(draft_id), updated_draft) assert r.status_code == 200 r = api_client.get_data('/[email protected]') assert len(r) == 1 r = api_client.get_data('/[email protected]') assert len(r) == 0 r = api_client.get_data('/[email protected]') assert len(r) == 1
def test_create_draft_with_attachments(api_client, attachments, example_draft): attachment_ids = [] upload_path = api_client.full_path('/files') for filename, path in attachments: data = {'file': (open(path, 'rb'), filename)} r = api_client.client.post(upload_path, data=data) assert r.status_code == 200 attachment_id = json.loads(r.data)[0]['id'] attachment_ids.append(attachment_id) first_attachment = attachment_ids.pop() example_draft['file_ids'] = [first_attachment] r = api_client.post_data('/drafts', example_draft) assert r.status_code == 200 returned_draft = json.loads(r.data) draft_public_id = returned_draft['id'] assert returned_draft['version'] == 0 example_draft['version'] = returned_draft['version'] assert len(returned_draft['files']) == 1 attachment_ids.append(first_attachment) example_draft['file_ids'] = attachment_ids r = api_client.put_data('/drafts/{}'.format(draft_public_id), example_draft) assert r.status_code == 200 returned_draft = json.loads(r.data) assert len(returned_draft['files']) == 3 assert returned_draft['version'] == 1 example_draft['version'] = returned_draft['version'] # Make sure we can't delete the files now for file_id in attachment_ids: r = api_client.delete('/files/{}'.format(file_id)) assert r.status_code == 400 # Now remove the attachment example_draft['file_ids'] = [first_attachment] r = api_client.put_data('/drafts/{}'.format(draft_public_id), example_draft) draft_data = api_client.get_data('/drafts/{}'.format(draft_public_id)) assert len(draft_data['files']) == 1 assert draft_data['version'] == 2 example_draft['version'] = draft_data['version'] example_draft['file_ids'] = [] r = api_client.put_data('/drafts/{}'.format(draft_public_id), example_draft) draft_data = api_client.get_data('/drafts/{}'.format(draft_public_id)) assert r.status_code == 200 assert len(draft_data['files']) == 0 assert draft_data['version'] == 3 # now that they're not attached, we should be able to delete them for file_id in attachment_ids: r = api_client.delete('/files/{}'.format(file_id)) assert r.status_code == 200
def test_get_with_id(api_client, uploaded_file_ids, filename): # See comment in uploaded_file_ids() if filename == 'piece-jointe.jpg': filename = u'pièce-jointe.jpg' elif filename == 'andra-moi-ennepe.txt': filename = u'ἄνδρα μοι ἔννεπε' in_file = api_client.get_data(u'/files?filename={}'.format(filename))[0] data = api_client.get_data('/files/{}'.format(in_file['id'])) assert data['filename'] == filename
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_get_invalid(api_client, uploaded_file_ids): data = api_client.get_data('/files/0000000000000000000000000') assert data['message'].startswith("Couldn't find file") data = api_client.get_data('/files/!') assert data['message'].startswith("Invalid id") data = api_client.get_data('/files/0000000000000000000000000/download') assert data['message'].startswith("Couldn't find file") data = api_client.get_data('/files/!/download') assert data['message'].startswith("Invalid id") r = api_client.delete('/files/0000000000000000000000000') assert r.status_code == 404 r = api_client.delete('/files/!') assert r.status_code == 400
def test_api_list(db, api_client, calendar): e_data = {'title': 'subj', 'description': 'body1', 'calendar_id': calendar.public_id, 'when': {'time': 1}, 'location': 'InboxHQ'} e_data2 = {'title': 'subj2', 'description': 'body2', 'calendar_id': calendar.public_id, 'when': {'time': 1}, 'location': 'InboxHQ'} api_client.post_data('/events', e_data) api_client.post_data('/events', e_data2) event_list = api_client.get_data('/events') event_titles = [event['title'] for event in event_list] assert 'subj' in event_titles assert 'subj2' in event_titles event_descriptions = [event['description'] for event in event_list] assert 'body1' in event_descriptions assert 'body2' in event_descriptions event_ids = [event['id'] for event in event_list] for e_id in event_ids: ev = db.session.query(Event).filter_by(public_id=e_id).one() db.session.delete(ev) db.session.commit()
def test_conflicting_updates(api_client): original_draft = { 'subject': 'parent draft', 'body': 'parent draft' } r = api_client.post_data('/drafts', original_draft) original_public_id = json.loads(r.data)['id'] version = json.loads(r.data)['version'] updated_draft = { 'subject': 'updated draft', 'body': 'updated draft', 'version': version } r = api_client.put_data('/drafts/{}'.format(original_public_id), updated_draft) assert r.status_code == 200 updated_public_id = json.loads(r.data)['id'] updated_version = json.loads(r.data)['version'] assert updated_version != version conflicting_draft = { 'subject': 'conflicting draft', 'body': 'conflicting draft', 'version': version } r = api_client.put_data('/drafts/{}'.format(original_public_id), conflicting_draft) assert r.status_code == 409 drafts = api_client.get_data('/drafts') assert len(drafts) == 1 assert drafts[0]['id'] == updated_public_id
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_resource_views(resource_name, db, api_client, message, thread, event, folder, label, contact): """Exercises various tests for views, mostly related to filtering. Note: this only tests views, it assumes the resources are working as expected.""" elements = api_client.get_data('/{}'.format(resource_name)) count = api_client.get_data('/{}?view=count'.format(resource_name)) assert count["count"] == len(elements) ids = api_client.get_data('/{}?view=ids'.format(resource_name)) for i, elem in enumerate(elements): assert isinstance(ids[i], basestring), \ "&views=ids should return string" assert elem["id"] == ids[i], "view=ids should preserve order"
def test_api_override_serialization(db, api_client, default_namespace, recurring_event): event = recurring_event override = Event(original_start_time=event.start, master_event_uid=event.uid, namespace_id=default_namespace.id, calendar_id=event.calendar_id) override.update(event) override.uid = event.uid + "_" + event.start.strftime("%Y%m%dT%H%M%SZ") override.master = event override.master_event_uid = event.uid override.cancelled = True db.session.add(override) db.session.commit() filter = 'starts_after={}&ends_before={}'.format( urlsafe(event.start.replace(hours=-1)), urlsafe(event.start.replace(weeks=+1))) events = api_client.get_data('/events?' + filter) # We should have the base event and the override back, but no extras; # this allows clients to do their own expansion, should they ever desire # to experience the joy that is RFC 2445 section 4.8.5.4. assert len(events) == 2 assert events[0].get('object') == 'event' assert events[0].get('recurrence') is not None assert events[1].get('object') == 'event' assert events[1].get('status') == 'cancelled'
def test_api_create(db, api_client, calendar): e_data = { 'title': 'Friday Office Party', 'when': {'time': 1407542195}, 'calendar_id': calendar.public_id, 'participants': [{ 'name': 'alyssa p. hacker', 'email': '*****@*****.**' }] } e_resp = api_client.post_data('/events', e_data) e_resp_data = json.loads(e_resp.data) assert len(e_resp_data['participants']) == 1 participant = e_resp_data['participants'][0] assert participant['name'] == e_data['participants'][0]['name'] assert participant['email'] == e_data['participants'][0]['email'] assert participant['status'] == 'noreply' e_resp_data = api_client.get_data('/events/' + e_resp_data['id']) assert len(e_resp_data['participants']) == 1 participant = e_resp_data['participants'][0] assert participant['name'] == e_data['participants'][0]['name'] assert participant['email'] == e_data['participants'][0]['email'] assert participant['status'] == 'noreply'
def test_namespace(api_client, generic_account, gmail_account): resp_data = api_client.get_data('', generic_account.namespace.public_id) assert resp_data['id'] == generic_account.namespace.public_id assert resp_data['object'] == 'namespace' assert resp_data['namespace_id'] == generic_account.namespace.public_id assert resp_data['account_id'] == generic_account.public_id assert resp_data['email_address'] == generic_account.email_address assert resp_data['name'] == generic_account.name assert resp_data['organization_unit'] == 'folder' resp_data = api_client.get_data('', gmail_account.namespace.public_id) assert resp_data['id'] == gmail_account.namespace.public_id assert resp_data['provider'] == 'gmail' assert resp_data['organization_unit'] == 'label'
def test_delete_remote_draft(db, api_client, message): message.is_draft = True db.session.commit() drafts = api_client.get_data('/drafts') assert len(drafts) == 1 public_id = drafts[0]['id'] version = drafts[0]['version'] assert public_id == message.public_id and version == message.version api_client.delete('/drafts/{}'.format(public_id), {'version': version}) # Check that drafts were deleted drafts = api_client.get_data('/drafts') assert not drafts
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_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) resp_data = api_client.get_data( '/threads/{}'.format(generic_thread.public_id), generic_account.namespace.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), generic_account.namespace.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 # 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), gmail_account.namespace.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), gmail_account.namespace.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_delete(api_client, uploaded_file_ids, draft): non_attachment_id = uploaded_file_ids.pop() attachment_id = uploaded_file_ids.pop() draft['file_ids'] = [attachment_id] r = api_client.post_data('/drafts', draft) assert r.status_code == 200 # Test that we can delete a non-attachment r = api_client.delete('/files/{}'.format(non_attachment_id)) assert r.status_code == 200 data = api_client.get_data('/files/{}'.format(non_attachment_id)) assert data['message'].startswith("Couldn't find file") # Make sure that we cannot delete attachments r = api_client.delete('/files/{}'.format(attachment_id)) assert r.status_code == 400 data = api_client.get_data('/files/{}'.format(attachment_id)) assert data['id'] == attachment_id
def test_gmail_message_search(api_client, default_account, patch_crispin_client, patch_handler_from_provider, sorted_gmail_messages): search_client = get_search_client(default_account) assert search_client.__class__.__name__ == 'GmailSearchClient' messages = api_client.get_data('/messages/search?q=blah%20blah%20blah') for sorted_message, result_message in zip(sorted_gmail_messages, messages): assert sorted_message.public_id == result_message['id']
def test_create_draft_replying_to_message(api_client, message): message = api_client.get_data('/messages')[0] reply_draft = { 'subject': 'test reply', 'body': 'test reply', 'reply_to_message_id': message['id'] } r = api_client.post_data('/drafts', reply_draft) data = json.loads(r.data) assert data['reply_to_message_id'] == message['id'] assert data['thread_id'] == message['thread_id']
def test_gmail_thread_search(api_client, test_gmail_thread, default_account, patch_token_manager, patch_gmail_search_response, sorted_gmail_threads): search_client = get_search_client(default_account) assert isinstance(search_client, GmailSearchClient) threads = api_client.get_data('/threads/search?q=blah%20blah%20blah') for sorted_thread, result_thread in zip(sorted_gmail_threads, threads): assert sorted_thread.public_id == result_thread['id']
def test_gmail_thread_search(api_client, test_gmail_thread, default_account, patch_crispin_client, patch_handler_from_provider, sorted_gmail_threads): search_client = get_search_client(default_account) assert search_client.__class__.__name__ == 'GmailSearchClient' threads = api_client.get_data('/threads/search?q=blah%20blah%20blah') for sorted_thread, result_thread in zip(sorted_gmail_threads, threads): assert sorted_thread.public_id == result_thread['id']
def test_update_to_nonexistent_draft(api_client): updated_draft = { 'subject': 'updated draft', 'body': 'updated draft', 'version': 22 } r = api_client.put_data('/drafts/{}'.format('notarealid'), updated_draft) assert r.status_code == 404 drafts = api_client.get_data('/drafts') assert len(drafts) == 0
def test_gmail_message_search(api_client, default_account, patch_token_manager, patch_gmail_search_response, sorted_gmail_messages): search_client = get_search_client(default_account) assert isinstance(search_client, GmailSearchClient) messages = api_client.get_data('/messages/search?q=blah%20blah%20blah') for sorted_message, result_message in zip(sorted_gmail_messages, messages): assert sorted_message.public_id == result_message['id']
def test_sent_messages_shown_in_delta(patch_smtp, api_client, example_draft): ts = int(time.time()) r = api_client.post_data('/delta/generate_cursor', {'start': ts}) cursor = json.loads(r.data)['cursor'] r = api_client.post_data('/send', example_draft) message_id = json.loads(r.data)['id'] deltas = api_client.get_data('/delta?cursor={}'.format(cursor))['deltas'] message_delta = next((d for d in deltas if d['id'] == message_id), None) assert message_delta is not None assert message_delta['object'] == 'message' assert message_delta['event'] == 'create'
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_gmail_search_unicode(db, api_client, test_gmail_thread, default_account, patch_crispin_client, patch_handler_from_provider, sorted_gmail_threads): Folder.find_or_create(db.session, default_account, '存档', '存档') search_client = get_search_client(default_account) assert search_client.__class__.__name__ == 'GmailSearchClient' threads = api_client.get_data('/threads/search?q=存档') for sorted_thread, result_thread in zip(sorted_gmail_threads, threads): assert sorted_thread.public_id == result_thread['id']
def test_reply_headers_set(db, patch_smtp, api_client, example_draft, thread, message): message.message_id_header = '<*****@*****.**>' db.session.commit() thread_id = api_client.get_data('/threads')[0]['id'] api_client.post_data('/send', {'to': [{'email': '*****@*****.**'}], 'thread_id': thread_id}) _, msg = patch_smtp[-1] parsed = mime.from_string(msg) assert 'In-Reply-To' in parsed.headers assert 'References' in parsed.headers
def test_create_draft_replying_to_thread(api_client, thread, message): thread = api_client.get_data('/threads')[0] thread_id = thread['id'] latest_message_id = thread['message_ids'][-1] reply_draft = { 'subject': 'test reply', 'body': 'test reply', 'thread_id': thread_id } r = api_client.post_data('/drafts', reply_draft) draft_id = json.loads(r.data)['id'] drafts = api_client.get_data('/drafts') assert len(drafts) == 1 assert thread_id == drafts[0]['thread_id'] assert drafts[0]['reply_to_message_id'] == latest_message_id thread_data = api_client.get_data('/threads/{}'.format(thread_id)) assert draft_id in thread_data['draft_ids']
def test_drafts_filter(api_client, example_draft): r = api_client.post_data('/drafts', example_draft) thread_id = json.loads(r.data)['thread_id'] reply_draft = { 'subject': 'test reply', 'body': 'test reply', 'thread_id': thread_id } r = api_client.post_data('/drafts', reply_draft) _filter = '?thread_id=0000000000000000000000000' results = api_client.get_data('/drafts' + _filter) assert len(results) == 0 results = api_client.get_data('/drafts?thread_id={}'.format(thread_id)) assert len(results) == 2 results = api_client.get_data('/drafts?offset={}&thread_id={}'.format( 1, thread_id)) assert len(results) == 1
def test_send_existing_draft(patch_smtp, api_client, example_draft): r = api_client.post_data('/drafts', example_draft) draft_public_id = json.loads(r.data)['id'] version = json.loads(r.data)['version'] r = api_client.post_data('/send', {'draft_id': draft_public_id, 'version': version}) assert r.status_code == 200 # Test that the sent draft can't be sent again. r = api_client.post_data('/send', {'draft_id': draft_public_id, 'version': version}) assert r.status_code == 400 drafts = api_client.get_data('/drafts') assert not drafts message = api_client.get_data('/messages/{}'.format(draft_public_id)) assert message['object'] == 'message'
def test_contacts_updated(api_client): """Tests that draft-contact associations are properly created and updated.""" draft = { 'to': [{ 'email': '*****@*****.**' }, { 'email': '*****@*****.**' }] } r = api_client.post_data('/drafts', draft) assert r.status_code == 200 draft_id = json.loads(r.data)['id'] draft_version = json.loads(r.data)['version'] r = api_client.get_data('/[email protected]') assert len(r) == 1 updated_draft = { 'to': [{ 'email': '*****@*****.**' }, { 'email': '*****@*****.**' }], 'version': draft_version } r = api_client.put_data('/drafts/{}'.format(draft_id), updated_draft) assert r.status_code == 200 r = api_client.get_data('/[email protected]') assert len(r) == 1 r = api_client.get_data('/[email protected]') assert len(r) == 0 r = api_client.get_data('/[email protected]') assert len(r) == 1
def test_create_and_get_draft(api_client, example_draft): r = api_client.post_data('/drafts', example_draft) assert r.status_code == 200 public_id = json.loads(r.data)['id'] version = json.loads(r.data)['version'] assert version == 0 r = api_client.get_data('/drafts') matching_saved_drafts = [draft for draft in r if draft['id'] == public_id] assert len(matching_saved_drafts) == 1 saved_draft = matching_saved_drafts[0] assert all(saved_draft[k] == v for k, v in example_draft.iteritems())
def test_get_all_drafts(api_client, example_draft): r = api_client.post_data('/drafts', example_draft) first_public_id = json.loads(r.data)['id'] r = api_client.post_data('/drafts', example_draft) second_public_id = json.loads(r.data)['id'] drafts = api_client.get_data('/drafts') assert len(drafts) == 2 assert first_public_id != second_public_id assert {first_public_id, second_public_id} == {draft['id'] for draft in drafts} assert all(item['object'] == 'draft' for item in drafts)
def test_api_list(contacts_provider, contact_sync, db, api_client, default_namespace): contacts_provider.supply_contact('Contact One', '*****@*****.**') contacts_provider.supply_contact('Contact Two', '*****@*****.**') contact_sync.provider = contacts_provider contact_sync.sync() ns_id = default_namespace.public_id contact_list = api_client.get_data('/contacts', ns_id) contact_names = [contact['name'] for contact in contact_list] assert 'Contact One' in contact_names assert 'Contact Two' in contact_names contact_emails = [contact['email'] for contact in contact_list] assert '*****@*****.**' in contact_emails assert '*****@*****.**' in contact_emails contact_count = api_client.get_data('/contacts?view=count') assert contact_count['count'] == db.session.query(Contact). \ filter(Contact.namespace_id == default_namespace.id).count()
def test_send_existing_draft(patch_smtp, api_client, example_draft): r = api_client.post_data('/drafts', example_draft) draft_public_id = json.loads(r.data)['id'] version = json.loads(r.data)['version'] r = api_client.post_data('/send', { 'draft_id': draft_public_id, 'version': version }) assert r.status_code == 200 # Test that the sent draft can't be sent again. r = api_client.post_data('/send', { 'draft_id': draft_public_id, 'version': version }) assert r.status_code == 400 drafts = api_client.get_data('/drafts') assert not drafts message = api_client.get_data('/messages/{}'.format(draft_public_id)) assert message['object'] == 'message'
def test_api_get(db, api_client, calendar): e_data = { 'title': 'subj', 'when': { 'time': 1 }, 'calendar_id': calendar.public_id, 'location': 'InboxHQ' } e_data2 = { 'title': 'subj2', 'when': { 'time': 1 }, 'calendar_id': calendar.public_id, 'location': 'InboxHQ' } api_client.post_data('/events', e_data) api_client.post_data('/events', e_data2) event_list = api_client.get_data('/events') event_ids = [event['id'] for event in event_list] c1found = False c2found = False for c_id in event_ids: event = api_client.get_data('/events/' + c_id) if event['title'] == 'subj': c1found = True if event['title'] == 'subj2': c2found = True assert c1found assert c2found
def test_get_calendar(db, default_namespace, api_client): cal = Calendar(namespace_id=default_namespace.id, uid='uid', provider_name='WTF', name='Holidays') db.session.add(cal) db.session.commit() cal_id = cal.public_id calendar_item = api_client.get_data('/calendars/{}'.format(cal_id)) assert calendar_item['namespace_id'] == default_namespace.public_id assert calendar_item['name'] == 'Holidays' assert calendar_item['description'] is None assert calendar_item['read_only'] is False assert calendar_item['object'] == 'calendar'
def test_api_expand_recurring_before_after(db, api_client, recurring_event): event = recurring_event starts_after = event.start.replace(weeks=+15) ends_before = starts_after.replace(days=+1) recur = 'expand_recurring=true&starts_after={}&ends_before={}'.format( urlsafe(starts_after), urlsafe(ends_before)) all_events = api_client.get_data('/events?' + recur) assert len(all_events) == 1 recur = 'expand_recurring=true&starts_after={}&starts_before={}'.format( urlsafe(starts_after), urlsafe(ends_before)) all_events = api_client.get_data('/events?' + recur) assert len(all_events) == 1 recur = 'expand_recurring=true&ends_after={}&starts_before={}'.format( urlsafe(starts_after), urlsafe(ends_before)) all_events = api_client.get_data('/events?' + recur) assert len(all_events) == 1 recur = 'expand_recurring=true&ends_after={}&ends_before={}'.format( urlsafe(starts_after), urlsafe(ends_before)) all_events = api_client.get_data('/events?' + recur) assert len(all_events) == 1
def test_reply_headers_set(db, patch_smtp, api_client, example_draft, thread, message): message.message_id_header = '<*****@*****.**>' db.session.commit() thread_id = api_client.get_data('/threads')[0]['id'] api_client.post_data('/send', { 'to': [{ 'email': '*****@*****.**' }], 'thread_id': thread_id }) _, msg = patch_smtp[-1] parsed = mime.from_string(msg) assert 'In-Reply-To' in parsed.headers assert 'References' in parsed.headers
def test_download(api_client, uploaded_file_ids, filename): # See comment in uploaded_file_ids() original_filename = filename if filename == 'piece-jointe.jpg': filename = u'pièce-jointe.jpg' elif filename == 'andra-moi-ennepe.txt': filename = u'ἄνδρα μοι ἔννεπε' in_file = api_client.get_data(u'/files?filename={}'.format(filename))[0] data = api_client.get_raw('/files/{}/download'.format(in_file['id'])).data path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'data', original_filename.encode('utf-8')) local_data = open(path, 'rb').read() local_md5 = md5.new(local_data).digest() dl_md5 = md5.new(data).digest() assert local_md5 == dl_md5
def test_api_update_read_only(db, api_client, calendar, default_namespace): add_fake_event(db.session, default_namespace.id, calendar=calendar, read_only=True) event_list = api_client.get_data('/events') read_only_event = None for e in event_list: if e['read_only']: read_only_event = e break assert read_only_event e_id = read_only_event['id'] e_update_data = {'title': 'new title'} e_put_resp = api_client.put_data('/events/' + e_id, e_update_data) assert e_put_resp.status_code != 200
def test_file_filtering(api_client, uploaded_file_ids, draft): # Attach the files to a draft and search there draft['file_ids'] = uploaded_file_ids r = api_client.post_data('/drafts', draft) assert r.status_code == 200 draft_resp = json.loads(r.data) assert len(draft_resp['files']) == 4 d_id = draft_resp['id'] results = api_client.get_data('/files?message_id={}' .format(d_id)) assert all([d_id in f['message_ids'] for f in results]) assert len(results) == 4 results = api_client.get_data('/files?message_id={}&limit=1' .format(d_id)) assert len(results) == 1 results = api_client.get_data('/files?message_id={}&offset=2' .format(d_id)) assert len(results) == 2 results = api_client.get_data('/files?filename=LetMeSendYouEmail.wav') assert len(results) == 1 results = api_client.get_data('/files?content_type=audio%2Fx-wav') assert len(results) == 1 results = api_client.get_data('/files?content_type=image%2Fjpeg') assert len(results) == 2 results = api_client.get_data( '/files?content_type=image%2Fjpeg&view=count') assert results["count"] == 2 results = api_client.get_data('/files?content_type=image%2Fjpeg&view=ids') assert len(results) == 2
def test_add_to_read_only_calendar(db, api_client): cal_list = api_client.get_data('/calendars') ro_cal = None for c in cal_list: if c['read_only']: ro_cal = c assert ro_cal e_data = { 'calendar_id': ro_cal['id'], 'title': 'subj', 'description': 'body1', 'when': { 'time': 1 }, 'location': 'InboxHQ' } resp = api_client.post_data('/events', e_data) assert resp.status_code == 400
def test_api_delete(db, api_client, calendar, default_account): e_data = { 'title': '', 'calendar_id': calendar.public_id, 'when': { 'time': 1407542195 }, } e_resp = api_client.post_data('/events', e_data) e_resp_data = json.loads(e_resp.data) assert e_resp_data['object'] == 'event' assert e_resp_data['title'] == e_data['title'] assert e_resp_data['when']['time'] == e_data['when']['time'] assert 'id' in e_resp_data e_id = e_resp_data['id'] e_delete_resp = api_client.delete('/events/' + e_id) assert e_delete_resp.status_code == 200 e_resp = api_client.get_data('/events/' + e_id) assert e_resp['status'] == 'cancelled'
def test_delete_draft(api_client, thread, message): original_draft = {'subject': 'parent draft', 'body': 'parent draft'} r = api_client.post_data('/drafts', original_draft) draft_public_id = json.loads(r.data)['id'] version = json.loads(r.data)['version'] updated_draft = { 'subject': 'updated draft', 'body': 'updated draft', 'version': version } r = api_client.put_data('/drafts/{}'.format(draft_public_id), updated_draft) updated_public_id = json.loads(r.data)['id'] updated_version = json.loads(r.data)['version'] r = api_client.delete('/drafts/{}'.format(updated_public_id), {'version': updated_version}) # Check that drafts were deleted drafts = api_client.get_data('/drafts') assert not drafts # Check that no orphaned threads are around threads = api_client.get_data('/threads?subject=parent%20draft') assert not threads threads = api_client.get_data('/threads?subject=updated%20draft') assert not threads # And check that threads aren't deleted if they still have messages. thread_public_id = api_client.get_data('/threads')[0]['id'] reply_draft = { 'subject': 'test reply', 'body': 'test reply', 'thread_id': thread_public_id } r = api_client.post_data('/drafts', reply_draft) public_id = json.loads(r.data)['id'] version = json.loads(r.data)['version'] thread = api_client.get_data('/threads/{}'.format(thread_public_id)) assert len(thread['draft_ids']) > 0 api_client.delete('/drafts/{}'.format(public_id), {'version': version}) thread = api_client.get_data('/threads/{}'.format(thread_public_id)) assert thread assert len(thread['draft_ids']) == 0
def test_api_expand_recurring(db, api_client, recurring_event): event = recurring_event events = api_client.get_data('/events?expand_recurring=false') assert len(events) == 1 # Make sure the recurrence info is on the recurring event for e in events: if e['title'] == 'recurring-weekly': assert e.get('recurrence') is not None thirty_weeks = event.start.replace(weeks=+30).isoformat() starts_after = event.start.replace(days=-1).isoformat() recur = 'expand_recurring=true&starts_after={}&ends_before={}'.format( urllib.quote_plus(starts_after), urllib.quote_plus(thirty_weeks)) all_events = api_client.get_data('/events?' + recur) if not event.all_day: assert len(all_events) == 28 # the ordering should be correct prev = all_events[0]['when']['start_time'] for e in all_events[1:]: assert e['when']['start_time'] > prev prev = e['when']['start_time'] events = api_client.get_data('/events?' + recur + '&view=count') assert events.get('count') == 28 else: # Since an all-day event starts at 00:00 we're returning one # more event. assert len(all_events) == 29 # the ordering should be correct prev = all_events[0]['when']['date'] for e in all_events[1:]: assert e['when']['date'] > prev prev = e['when']['date'] events = api_client.get_data('/events?' + recur + '&view=count') assert events.get('count') == 29 events = api_client.get_data('/events?' + recur + '&limit=5') assert len(events) == 5 events = api_client.get_data('/events?' + recur + '&offset=5') assert events[0]['id'] == all_events[5]['id']
def test_add_to_specific_calendar(db, default_namespace, api_client): cal = Calendar(namespace_id=default_namespace.id, uid='uid', provider_name='WTF', name='Custom') db.session.add(cal) db.session.commit() cal_id = cal.public_id e_data = { 'calendar_id': cal_id, 'title': 'subj', 'description': 'body1', 'when': { 'time': 1 }, 'location': 'InboxHQ' } r = api_client.post_data('/events', e_data) assert r.status_code == 200 events = api_client.get_data('/events?calendar_id={}'.format(cal_id)) assert len(events) == 1
def test_api_list(db, api_client, calendar): e_data = { 'title': 'subj', 'description': 'body1', 'calendar_id': calendar.public_id, 'when': { 'time': 1 }, 'location': 'InboxHQ' } e_data2 = { 'title': 'subj2', 'description': 'body2', 'calendar_id': calendar.public_id, 'when': { 'time': 1 }, 'location': 'InboxHQ' } api_client.post_data('/events', e_data) api_client.post_data('/events', e_data2) event_list = api_client.get_data('/events') event_titles = [event['title'] for event in event_list] assert 'subj' in event_titles assert 'subj2' in event_titles event_descriptions = [event['description'] for event in event_list] assert 'body1' in event_descriptions assert 'body2' in event_descriptions event_ids = [event['id'] for event in event_list] for e_id in event_ids: ev = db.session.query(Event).filter_by(public_id=e_id).one() db.session.delete(ev) db.session.commit()
def _verify_create(ns_id, api_client, e_data): e_resp = api_client.post_data('/events', e_data, ns_id) if e_resp.status_code != 200: raise CreateError() e_resp_data = json.loads(e_resp.data) assert e_resp_data['object'] == 'event' assert e_resp_data['namespace_id'] == ns_id assert e_resp_data['title'] == e_data['title'] assert e_resp_data['location'] == e_data['location'] for k, v in e_data['when'].iteritems(): assert arrow.get(e_resp_data['when'][k]) == arrow.get(v) assert 'id' in e_resp_data e_id = e_resp_data['id'] e_get_resp = api_client.get_data('/events/' + e_id, ns_id) assert e_get_resp['object'] == 'event' assert e_get_resp['namespace_id'] == ns_id assert e_get_resp['id'] == e_id assert e_get_resp['title'] == e_data['title'] for k, v in e_data['when'].iteritems(): assert arrow.get(e_get_resp['when'][k]) == arrow.get(v) return e_resp_data
def test_api_create_no_title(db, api_client, calendar, default_account): e_data = { 'title': '', 'calendar_id': calendar.public_id, 'when': { 'time': 1407542195 }, } e_resp = api_client.post_data('/events', e_data) e_resp_data = json.loads(e_resp.data) assert e_resp_data['object'] == 'event' assert e_resp_data['namespace_id'] == default_account.namespace.public_id assert e_resp_data['title'] == e_data['title'] assert e_resp_data['when']['time'] == e_data['when']['time'] assert 'id' in e_resp_data e_id = e_resp_data['id'] e_get_resp = api_client.get_data('/events/' + e_id) assert e_get_resp['object'] == 'event' assert e_get_resp['namespace_id'] == default_account.namespace.public_id assert e_get_resp['id'] == e_id assert e_get_resp['title'] == e_data['title'] assert e_get_resp['when']['time'] == e_data['when']['time']
def test_filtering(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', '*****@*****.**')], subject='some subject') message.categories.add( Category(namespace_id=message.namespace_id, name='inbox', display_name='Inbox', type_='label')) thread.subject = message.subject db.session.commit() t_start = dt_to_timestamp(thread.subjectdate) t_lastmsg = dt_to_timestamp(thread.recentdate) subject = message.subject to_addr = message.to_addr[0][1] from_addr = message.from_addr[0][1] received_date = message.received_date unread = not message.is_read starred = message.is_starred results = api_client.get_data('/threads?thread_id={}'.format( thread.public_id)) assert len(results) == 1 results = api_client.get_data('/messages?thread_id={}'.format( thread.public_id)) assert len(results) == 1 results = api_client.get_data('/threads?cc={}'.format(message.cc_addr)) assert len(results) == 0 results = api_client.get_data('/messages?cc={}'.format(message.cc_addr)) assert len(results) == 0 results = api_client.get_data('/threads?bcc={}'.format(message.bcc_addr)) assert len(results) == 0 results = api_client.get_data('/messages?bcc={}'.format(message.bcc_addr)) assert len(results) == 0 results = api_client.get_data('/threads?filename=test') assert len(results) == 0 results = api_client.get_data('/messages?filename=test') assert len(results) == 0 results = api_client.get_data('/threads?started_after={}'.format(t_start - 1)) assert len(results) == 1 results = api_client.get_data('/messages?started_after={}'.format(t_start - 1)) assert len(results) == 1 results = api_client.get_data( '/messages?last_message_before={}&limit=1'.format(t_lastmsg + 1)) assert len(results) == 1 results = api_client.get_data( '/threads?last_message_before={}&limit=1'.format(t_lastmsg + 1)) assert len(results) == 1 results = api_client.get_data('/threads?in=inbox&limit=1') assert len(results) == 1 results = api_client.get_data('/messages?in=inbox&limit=1') assert len(results) == 1 results = api_client.get_data('/messages?in=banana%20rama') assert len(results) == 0 results = api_client.get_data('/threads?subject={}'.format(subject)) assert len(results) == 1 results = api_client.get_data('/messages?subject={}'.format(subject)) assert len(results) == 1 results = api_client.get_data('/threads?unread={}'.format(unread)) assert len(results) == 1 results = api_client.get_data('/messages?unread={}'.format((not unread))) assert len(results) == 0 results = api_client.get_data('/threads?starred={}'.format((not starred))) assert len(results) == 0 results = api_client.get_data('/messages?starred={}'.format(starred)) assert len(results) == 1 for _ in range(3): add_fake_message(db.session, default_namespace.id, to_addr=[('', '*****@*****.**')], thread=add_fake_thread(db.session, default_namespace.id)) results = api_client.get_data( '/messages?any_email={}'.format('*****@*****.**')) assert len(results) > 1 results = api_client.get_data( '/threads?any_email={}'.format('*****@*****.**')) assert len(results) > 1 # Check that we canonicalize when searching. alternate_results = api_client.get_data( '/threads?any_email={}'.format('*****@*****.**')) assert len(alternate_results) == len(results) results = api_client.get_data('/messages?from={}'.format(from_addr)) assert len(results) == 1 results = api_client.get_data('/threads?from={}'.format(from_addr)) assert len(results) == 1 early_time = received_date - datetime.timedelta(seconds=1) late_time = received_date + datetime.timedelta(seconds=1) early_ts = calendar.timegm(early_time.utctimetuple()) late_ts = calendar.timegm(late_time.utctimetuple()) results = api_client.get_data( '/messages?subject={}&started_before={}'.format(subject, early_ts)) assert len(results) == 0 results = api_client.get_data( '/threads?subject={}&started_before={}'.format(subject, early_ts)) assert len(results) == 0 results = api_client.get_data( '/messages?subject={}&started_before={}'.format(subject, late_ts)) assert len(results) == 1 results = api_client.get_data( '/threads?subject={}&started_before={}'.format(subject, late_ts)) assert len(results) == 1 results = api_client.get_data( '/messages?subject={}&last_message_after={}'.format(subject, early_ts)) assert len(results) == 1 results = api_client.get_data( '/threads?subject={}&last_message_after={}'.format(subject, early_ts)) assert len(results) == 1 results = api_client.get_data( '/messages?subject={}&last_message_after={}'.format(subject, late_ts)) assert len(results) == 0 results = api_client.get_data( '/threads?subject={}&last_message_after={}'.format(subject, late_ts)) assert len(results) == 0 results = api_client.get_data( '/messages?subject={}&started_before={}'.format(subject, early_ts)) assert len(results) == 0 results = api_client.get_data( '/threads?subject={}&started_before={}'.format(subject, early_ts)) assert len(results) == 0 results = api_client.get_data( '/messages?subject={}&started_before={}'.format(subject, late_ts)) assert len(results) == 1 results = api_client.get_data( '/threads?subject={}&started_before={}'.format(subject, late_ts)) assert len(results) == 1 results = api_client.get_data('/messages?from={}&to={}'.format( from_addr, to_addr)) assert len(results) == 1 results = api_client.get_data('/threads?from={}&to={}'.format( from_addr, to_addr)) assert len(results) == 1 results = api_client.get_data('/messages?to={}&limit={}&offset={}'.format( '*****@*****.**', 2, 1)) assert len(results) == 2 results = api_client.get_data('/threads?to={}&limit={}'.format( '*****@*****.**', 3)) assert len(results) == 3 results = api_client.get_data('/threads?view=count') assert results['count'] == 4 results = api_client.get_data('/threads?view=ids&to={}&limit=3'.format( '*****@*****.**', 3)) assert len(results) == 3 assert all(isinstance(r, basestring) for r in results), "Returns a list of string"
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_api_filter(db, api_client, calendar): # Events in database: # description: data1 # read_only: True # namespace_id: 3q4vzllntcsea53vxz4erbnxr # object: event # when: {u'start_time': 1, u'object': u'timespan', u'end_time': # 2678401} # participants: [] # location: InboxHeadquarters # calendar_id: 167wjlgf89za2cdhy17p9bsu8 # id: 6n5fi3kwousrq3m6wl89tidx9 # title: desc1 # description: data2 # read_only: True # namespace_id: 3q4vzllntcsea53vxz4erbnxr # object: event # when: {u'object': u'time', u'time': 1} # participants: [] # location: InboxHeadquarters # calendar_id: 167wjlgf89za2bz6fytbzn0zk # id: crezzdqaizqv2gt7uomkzu9l6 # title: desc2 # description: data3 # read_only: False # namespace_id: 3q4vzllntcsea53vxz4erbnxr # object: event # when: {u'start_time': 2678401, u'object': u'timespan', # u'end_time': 5097601} # participants: [] # location: InboxHeadquarters # calendar_id: 167wjlgf89za2cdhy17p9bsu8 # id: crezzdqaizqv2gk4tabx3ddze # title: desc5 events = api_client.get_data('/events?offset=%s' % '1') assert len(events) == 2 events = api_client.get_data('/events?limit=%s' % '1') assert len(events) == 1 events = api_client.get_data('/events?description=%s' % 'data') assert len(events) == 3 events = api_client.get_data('/events?description=%s' % 'data1') assert len(events) == 1 events = api_client.get_data('/events?description=%s' % 'bad') assert len(events) == 0 events = api_client.get_data('/events?title=%s' % 'desc') assert len(events) == 3 events = api_client.get_data('/events?title=%s' % 'desc5') assert len(events) == 1 events = api_client.get_data('/events?title=%s' % 'bad') assert len(events) == 0 events = api_client.get_data('/events?location=%s' % 'Inbox') assert len(events) == 3 events = api_client.get_data('/events?location=%s' % 'bad') assert len(events) == 0 _filter = 'event_id=%s' % 'crezzdqaizqv2gk4tabx3ddze' events = api_client.get_data('/events?' + _filter) assert len(events) == 1 _filter = 'starts_before=2' events = api_client.get_data('/events?' + _filter) assert len(events) == 2 _filter = 'starts_after=2' events = api_client.get_data('/events?' + _filter) assert len(events) == 1 _filter = 'ends_before=2700000' events = api_client.get_data('/events?' + _filter) assert len(events) == 2 _filter = 'ends_after=2700000' events = api_client.get_data('/events?' + _filter) assert len(events) == 1 _filter = 'calendar_id=167wjlgf89za2cdhy17p9bsu8' events = api_client.get_data('/events?' + _filter) assert len(events) == 2 _filter = 'calendar_id=0000000000000000000000000' events = api_client.get_data('/events?' + _filter) assert len(events) == 0