コード例 #1
0
def test_write_endpoints(db, setup_account, api_client, default_account):
    # Write operations (create, update, delete) succeed.
    r = api_client.post_data(
        "/drafts",
        data={"body": "<html><body><h2>Sea, birds and sand.</h2></body></html>"},
    )
    assert r.status_code == 200
    draft_id = json.loads(r.data)["id"]

    endpoint = "/messages/{}".format(setup_account["message"])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 200

    endpoint = "/events/{}".format(setup_account["event"])
    r = api_client.delete(endpoint)
    assert r.status_code == 200

    default_account.sync_state = "invalid"
    db.session.commit()

    # Write operations fail with an HTTP 403.
    r = api_client.post_data("/labels", data={"display_name": "Neu!"})
    assert r.status_code == 403

    endpoint = "/threads/{}".format(setup_account["thread"])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 403

    endpoint = "/drafts/{}".format(draft_id)
    r = api_client.delete(endpoint)
    assert r.status_code == 403
コード例 #2
0
ファイル: test_drafts.py プロジェクト: thomasst/sync-engine
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
コード例 #3
0
def test_write_endpoints(db, setup_account, api_client, default_account):
    # Write operations (create, update, delete) succeed.
    r = api_client.post_data(
        '/drafts',
        data={
            'body': '<html><body><h2>Sea, birds and sand.</h2></body></html>'
        })
    assert r.status_code == 200
    draft_id = json.loads(r.data)['id']

    endpoint = '/messages/{}'.format(setup_account['message'])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 200

    endpoint = '/events/{}'.format(setup_account['event'])
    r = api_client.delete(endpoint)
    assert r.status_code == 200

    default_account.sync_state = 'invalid'
    db.session.commit()

    # Write operations fail with an HTTP 403.
    r = api_client.post_data('/labels', data={"display_name": "Neu!"})
    assert r.status_code == 403

    endpoint = '/threads/{}'.format(setup_account['thread'])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 403

    endpoint = '/drafts/{}'.format(draft_id)
    r = api_client.delete(endpoint)
    assert r.status_code == 403
コード例 #4
0
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
コード例 #5
0
ファイル: test_drafts.py プロジェクト: brandoncc/sync-engine
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
コード例 #6
0
def test_write_endpoints(db, setup_account, api_client, default_account):
    # Write operations (create, update, delete) succeed.
    r = api_client.post_data(
        '/drafts',
        data={
            'body': '<html><body><h2>Sea, birds and sand.</h2></body></html>'
        })
    assert r.status_code == 200
    draft_id = json.loads(r.data)['id']

    endpoint = '/messages/{}'.format(setup_account['message'])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 200

    endpoint = '/events/{}'.format(setup_account['event'])
    r = api_client.delete(endpoint)
    assert r.status_code == 200

    default_account.sync_state = 'invalid'
    db.session.commit()

    # Write operations fail with an HTTP 403.
    r = api_client.post_data('/labels', data={"display_name": "Neu!"})
    assert r.status_code == 403

    endpoint = '/threads/{}'.format(setup_account['thread'])
    r = api_client.put_data(endpoint, data={"starred": True})
    assert r.status_code == 403

    endpoint = '/drafts/{}'.format(draft_id)
    r = api_client.delete(endpoint)
    assert r.status_code == 403
コード例 #7
0
ファイル: test_drafts.py プロジェクト: brandoncc/sync-engine
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = '/files'
    for filename, path in attachments:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.post_raw(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
コード例 #8
0
ファイル: test_drafts.py プロジェクト: thomasst/sync-engine
def test_create_draft_with_attachments(api_client, attachments, example_draft):
    attachment_ids = []
    upload_path = '/files'
    for filename, path in attachments:
        data = {'file': (open(path, 'rb'), filename)}
        r = api_client.post_raw(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
コード例 #9
0
ファイル: test_messages.py プロジェクト: busseyl/sync-engine
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'] == []
コード例 #10
0
def test_api_remove_participant(db, api_client, calendar):
    e_data = {
        'title': 'Friday Office Party',
        'when': {'time': 1407542195},
        'calendar_id': calendar.public_id,
        'participants': [{'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'}]
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)
    assert len(e_resp_data['participants']) == 5
    for i, p in enumerate(e_resp_data['participants']):
        res = [e for e in e_resp_data['participants']
               if e['email'] == p['email']]
        assert len(res) == 1
        assert res[0]['name'] is None

    event_id = e_resp_data['id']
    e_data['participants'].pop()
    e_resp = api_client.put_data('/events/' + event_id, e_data)
    e_resp_data = json.loads(e_resp.data)
    assert len(e_resp_data['participants']) == 4
    for i, p in enumerate(e_resp_data['participants']):
        res = [e for e in e_resp_data['participants']
               if e['email'] == p['email']]
        assert len(res) == 1
        assert p['name'] is None
コード例 #11
0
ファイル: test_drafts.py プロジェクト: rskumar/sync-engine
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
コード例 #12
0
ファイル: test_drafts.py プロジェクト: busseyl/sync-engine
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

    # Check that contacts aren't created for garbage recipients.
    r = api_client.post_data("/drafts", {"to": [{"name": "who", "email": "nope"}]})
    assert r.status_code == 200
    r = api_client.get_data("/threads?to=nope")
    assert len(r) == 0
    r = api_client.get_data("/contacts?filter=nope")
    assert len(r) == 0
コード例 #13
0
def test_adding_a_custom_label_preserves_other_labels(
    db, api_client, default_account, folder_and_message_maps, label
):
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data("/messages/{}".format(message.public_id))
    labels = resp_data["labels"]
    assert len(labels) == 1
    assert labels[0]["name"] == label
    existing_label = labels[0]["id"]

    custom_label = add_fake_label(db.session, default_account, "<3", None)
    db.session.commit()

    # Adding only a custom label does not move a message to a different folder
    # i.e. does not change its 'all'/ 'trash'/ 'spam' labels.
    response = api_client.put_data(
        "/messages/{}".format(message.public_id),
        {"label_ids": [custom_label.category.public_id, existing_label]},
    )
    labels = json.loads(response.data)["labels"]
    assert len(labels) == 2
    assert set([l["name"] for l in labels]) == set([label, None])
    assert "<3" in [l["display_name"] for l in labels]
コード例 #14
0
def test_adding_a_mutually_exclusive_label_does_not_affect_custom_labels(
    db, api_client, default_account, folder_and_message_maps, label
):
    folder_map, message_map = folder_and_message_maps
    label_to_add = folder_map[label]

    for key in message_map:
        if key == label:
            continue

        message = message_map[key]
        add_custom_label(db, default_account, message)
        resp_data = api_client.get_data("/messages/{}".format(message.public_id))
        labels = resp_data["labels"]
        assert len(labels) == 2
        assert key in [l["name"] for l in labels]
        assert "<3" in [l["display_name"] for l in labels]

        # Adding only 'all'/ 'trash'/ 'spam' does not change custom labels.
        response = api_client.put_data(
            "/messages/{}".format(message.public_id),
            {
                "label_ids": [label_to_add.category.public_id]
                + [l["id"] for l in labels]
            },
        )
        labels = json.loads(response.data)["labels"]
        assert len(labels) == 2
        assert label in [l["name"] for l in labels]
        assert "<3" in [l["display_name"] for l in labels]
コード例 #15
0
ファイル: test_drafts.py プロジェクト: busseyl/sync-engine
def test_update_draft(api_client):
    with freeze_time(datetime.now()) as freezer:
        original_draft = {"subject": "original 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"]
        assert version == 0

        freezer.tick()

        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"]

        assert updated_public_id == draft_public_id
        assert updated_version > 0

        drafts = api_client.get_data("/drafts")
        assert len(drafts) == 1
        assert drafts[0]["id"] == updated_public_id

        # Check that the thread is updated too.
        thread = api_client.get_data("/threads/{}".format(drafts[0]["thread_id"]))
        assert thread["subject"] == "updated draft"
        assert thread["first_message_timestamp"] == drafts[0]["date"]
        assert thread["last_message_timestamp"] == drafts[0]["date"]
コード例 #16
0
def test_adding_a_mutually_exclusive_label_replaces_the_other(
    db, api_client, default_account, folder_and_message_maps, label
):
    # Verify a Gmail message can only have ONE of the 'all', 'trash', 'spam'
    # labels at a time. We specifically test that adding 'all'/ 'trash'/ 'spam'
    # to a message in one of the other two folders *replaces*
    # the existing label with the label being added.
    folder_map, message_map = folder_and_message_maps
    label_to_add = folder_map[label]

    for key in message_map:
        if key == label:
            continue

        message = message_map[key]
        resp_data = api_client.get_data("/messages/{}".format(message.public_id))
        labels = resp_data["labels"]
        assert len(labels) == 1
        assert labels[0]["name"] == key
        existing_label = labels[0]["id"]

        # Adding 'all'/ 'trash'/ 'spam' removes the existing one,
        # irrespective of whether it's provided in the request or not.
        response = api_client.put_data(
            "/messages/{}".format(message.public_id),
            {"label_ids": [label_to_add.category.public_id, existing_label]},
        )
        labels = json.loads(response.data)["labels"]
        assert len(labels) == 1
        assert labels[0]["name"] == label
コード例 #17
0
def test_adding_trash_or_spam_removes_inbox(
    db, api_client, default_account, folder_and_message_maps, label
):
    # Verify a Gmail message in 'trash', 'spam' cannot have 'inbox'.
    # We specifically test that adding 'trash'/ 'spam' to a message with 'inbox'
    # removes it.
    folder_map, message_map = folder_and_message_maps

    message = message_map["all"]
    add_inbox_label(db, default_account, message)
    resp_data = api_client.get_data("/messages/{}".format(message.public_id))
    labels = resp_data["labels"]
    assert len(labels) == 2
    assert set([l["name"] for l in labels]) == set(["all", "inbox"])

    # Adding 'trash'/ 'spam' removes 'inbox' (and 'all'),
    # irrespective of whether it's provided in the request or not.
    label_to_add = folder_map[label]
    response = api_client.put_data(
        "/messages/{}".format(message.public_id),
        {"label_ids": [label_to_add.category.public_id] + [l["id"] for l in labels]},
    )
    labels = json.loads(response.data)["labels"]
    assert len(labels) == 1
    assert labels[0]["name"] == label
コード例 #18
0
ファイル: test_drafts.py プロジェクト: busseyl/sync-engine
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
コード例 #19
0
def test_adding_inbox_adds_all_and_removes_trash_spam(
    db, api_client, default_account, folder_and_message_maps, label
):
    # Verify a Gmail message in 'trash', 'spam' cannot have 'inbox'.
    # This time we test that adding 'inbox' to a message in the 'trash'/ 'spam'
    # moves it to 'all' in addition to adding 'inbox'.
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data("/messages/{}".format(message.public_id))
    labels = resp_data["labels"]
    assert len(labels) == 1
    assert labels[0]["name"] == label
    existing_label = labels[0]["id"]

    inbox_label = add_fake_label(db.session, default_account, "Inbox", "inbox")
    db.session.commit()

    # Adding 'inbox' adds 'all', replacing 'trash'/ 'spam' if needed.
    response = api_client.put_data(
        "/messages/{}".format(message.public_id),
        {"label_ids": [inbox_label.category.public_id, existing_label]},
    )
    db.session.commit()
    labels = json.loads(response.data)["labels"]
    assert len(labels) == 2
    assert set([l["name"] for l in labels]) == set(["all", "inbox"])
コード例 #20
0
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'] == []
コード例 #21
0
def test_api_pessimistic_update(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,
                                  headers={"Api-Version": API_VERSIONS[1]})

    e_resp_data = json.loads(e_resp.data)
    assert e_resp_data["object"] == "event"
    assert e_resp_data["account_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_update_data = {"title": "new title"}
    e_put_resp = api_client.put_data("/events/" + e_id,
                                     e_update_data,
                                     headers={"Api-Version": API_VERSIONS[1]})

    e_put_data = json.loads(e_put_resp.data)

    assert e_put_data["object"] == "event"
    assert e_put_data["account_id"] == default_account.namespace.public_id
    assert e_put_data["id"] == e_id
    assert e_put_data["title"] == ""
    assert e_put_data["when"]["object"] == "time"
    assert e_put_data["when"]["time"] == e_data["when"]["time"]
コード例 #22
0
def test_update_draft(api_client):
    with freeze_time(datetime.now()) as freezer:
        original_draft = {"subject": "original 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"]
        assert version == 0

        freezer.tick()

        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"]

        assert updated_public_id == draft_public_id
        assert updated_version > 0

        drafts = api_client.get_data("/drafts")
        assert len(drafts) == 1
        assert drafts[0]["id"] == updated_public_id

        # Check that the thread is updated too.
        thread = api_client.get_data("/threads/{}".format(
            drafts[0]["thread_id"]))
        assert thread["subject"] == "updated draft"
        assert thread["first_message_timestamp"] == drafts[0]["date"]
        assert thread["last_message_timestamp"] == drafts[0]["date"]
コード例 #23
0
def test_api_update_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['account_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_update_data = {'title': 'new title'}
    e_put_resp = api_client.put_data('/events/' + e_id, e_update_data)
    e_put_data = json.loads(e_put_resp.data)

    assert e_put_data['object'] == 'event'
    assert e_put_data['account_id'] == default_account.namespace.public_id
    assert e_put_data['id'] == e_id
    assert e_put_data['title'] == 'new title'
    assert e_put_data['when']['object'] == 'time'
    assert e_put_data['when']['time'] == e_data['when']['time']
コード例 #24
0
ファイル: test_drafts.py プロジェクト: thomasst/sync-engine
def test_update_draft(api_client):
    original_draft = {'subject': 'original 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']
    assert version == 0

    # Sleep so that timestamp on updated draft is different.
    gevent.sleep(1)

    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']

    assert updated_public_id == draft_public_id
    assert updated_version > 0

    drafts = api_client.get_data('/drafts')
    assert len(drafts) == 1
    assert drafts[0]['id'] == updated_public_id

    # Check that the thread is updated too.
    thread = api_client.get_data('/threads/{}'.format(drafts[0]['thread_id']))
    assert thread['subject'] == 'updated draft'
    assert thread['first_message_timestamp'] == drafts[0]['date']
    assert thread['last_message_timestamp'] == drafts[0]['date']
コード例 #25
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_adding_inbox_adds_all_and_removes_trash_spam(
        db, api_client, default_account, folder_and_message_maps, label):
    # Verify a Gmail message in 'trash', 'spam' cannot have 'inbox'.
    # This time we test that adding 'inbox' to a message in the 'trash'/ 'spam'
    # moves it to 'all' in addition to adding 'inbox'.
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
    labels = resp_data['labels']
    assert len(labels) == 1
    assert labels[0]['name'] == label
    existing_label = labels[0]['id']

    inbox_label = add_fake_label(db.session, default_account, 'Inbox', 'inbox')
    db.session.commit()

    # Adding 'inbox' adds 'all', replacing 'trash'/ 'spam' if needed.
    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': [inbox_label.category.public_id, existing_label]})
    db.session.commit()
    labels = json.loads(response.data)['labels']
    assert len(labels) == 2
    assert set([l['name'] for l in labels]) == set(['all', 'inbox'])
コード例 #26
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_adding_a_mutually_exclusive_label_replaces_the_other(
        db, api_client, default_account, folder_and_message_maps, label):
    # Verify a Gmail message can only have ONE of the 'all', 'trash', 'spam'
    # labels at a time. We specifically test that adding 'all'/ 'trash'/ 'spam'
    # to a message in one of the other two folders *replaces*
    # the existing label with the label being added.
    folder_map, message_map = folder_and_message_maps
    label_to_add = folder_map[label]

    for key in message_map:
        if key == label:
            continue

        message = message_map[key]
        resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
        labels = resp_data['labels']
        assert len(labels) == 1
        assert labels[0]['name'] == key
        existing_label = labels[0]['id']

        # Adding 'all'/ 'trash'/ 'spam' removes the existing one,
        # irrespective of whether it's provided in the request or not.
        response = api_client.put_data(
            '/messages/{}'.format(message.public_id),
            {'label_ids': [label_to_add.category.public_id,
                           existing_label]})
        labels = json.loads(response.data)['labels']
        assert len(labels) == 1
        assert labels[0]['name'] == label
コード例 #27
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_adding_a_mutually_exclusive_label_does_not_affect_custom_labels(
        db, api_client, default_account, folder_and_message_maps, label):
    folder_map, message_map = folder_and_message_maps
    label_to_add = folder_map[label]

    for key in message_map:
        if key == label:
            continue

        message = message_map[key]
        add_custom_label(db, default_account, message)
        resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
        labels = resp_data['labels']
        assert len(labels) == 2
        assert key in [l['name'] for l in labels]
        assert '<3' in [l['display_name'] for l in labels]

        # Adding only 'all'/ 'trash'/ 'spam' does not change custom labels.
        response = api_client.put_data(
            '/messages/{}'.format(message.public_id),
            {'label_ids': [label_to_add.category.public_id] +
                [l['id'] for l in labels]})
        labels = json.loads(response.data)['labels']
        assert len(labels) == 2
        assert label in [l['name'] for l in labels]
        assert '<3' in [l['display_name'] for l in labels]
コード例 #28
0
ファイル: test_messages.py プロジェクト: yodiyo/sync-engine
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
コード例 #29
0
ファイル: test_messages.py プロジェクト: toke/sync-engine
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
コード例 #30
0
def test_validation(db, api_client, default_account, folder_and_message_maps, label):
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data("/messages/{}".format(message.public_id))
    labels = resp_data["labels"]
    assert len(labels) == 1
    assert labels[0]["name"] == label
    existing_label = labels[0]["id"]

    # Adding more than one mutually exclusive label is not allowed.
    # For example, adding 'trash' and 'spam'.
    # (Adding one is okay because it's simply replaced).
    labels_to_add = []
    for key in message_map:
        if key == label:
            continue
        labels_to_add += [folder_map[key].category.public_id]

    response = api_client.put_data(
        "/messages/{}".format(message.public_id), {"label_ids": labels_to_add}
    )
    resp_data = json.loads(response.data)
    assert response.status_code == 400
    assert resp_data.get("type") == "invalid_request_error"

    response = api_client.put_data(
        "/messages/{}".format(message.public_id),
        {"label_ids": labels_to_add + [existing_label]},
    )
    resp_data = json.loads(response.data)
    assert response.status_code == 400
    assert resp_data.get("type") == "invalid_request_error"

    # Removing all labels is not allowed, because this will remove
    # the required label (one of 'all'/ 'trash'/ 'spam') too.
    response = api_client.put_data(
        "/messages/{}".format(message.public_id), {"label_ids": []}
    )
    resp_data = json.loads(response.data)
    assert response.status_code == 400
    assert resp_data.get("type") == "invalid_request_error"
コード例 #31
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_validation(db, api_client, default_account, folder_and_message_maps,
                    label):
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
    labels = resp_data['labels']
    assert len(labels) == 1
    assert labels[0]['name'] == label
    existing_label = labels[0]['id']

    # Adding more than one mutually exclusive label is not allowed.
    # For example, adding 'trash' and 'spam'.
    # (Adding one is okay because it's simply replaced).
    labels_to_add = []
    for key in message_map:
        if key == label:
            continue
        labels_to_add += [folder_map[key].category.public_id]

    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': labels_to_add})
    resp_data = json.loads(response.data)
    assert response.status_code == 400
    assert resp_data.get('type') == 'invalid_request_error'

    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': labels_to_add + [existing_label]})
    resp_data = json.loads(response.data)
    assert response.status_code == 400
    assert resp_data.get('type') == 'invalid_request_error'

    # Removing all labels is not allowed, because this will remove
    # the required label (one of 'all'/ 'trash'/ 'spam') too.
    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': []})
    resp_data = json.loads(response.data)
    assert response.status_code == 400
    assert resp_data.get('type') == 'invalid_request_error'
コード例 #32
0
ファイル: test_drafts.py プロジェクト: thomasst/sync-engine
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
コード例 #33
0
ファイル: test_drafts.py プロジェクト: brandoncc/sync-engine
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
コード例 #34
0
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
コード例 #35
0
ファイル: test_drafts.py プロジェクト: busseyl/sync-engine
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
コード例 #36
0
def test_events_are_condensed(api_client, message):
    """
    Test that multiple revisions of the same object are rolled up in the
    delta response.

    """
    ts = int(time.time() + 22)
    cursor = get_cursor(api_client, ts)

    # Modify a message, then modify it again
    message_id = api_client.get_data('/messages/')[0]['id']
    message_path = '/messages/{}'.format(message_id)
    api_client.put_data(message_path, {'unread': True})
    api_client.put_data(message_path, {'unread': False})
    api_client.put_data(message_path, {'unread': True})

    # Check that successive modifies are condensed.
    sync_data = api_client.get_data('/delta?cursor={}'.format(cursor))
    deltas = sync_data['deltas']
    # A message modify propagates to its thread
    message_deltas = [d for d in deltas if d['object'] == 'message']
    assert len(message_deltas) == 1

    delta = message_deltas[0]
    assert delta['object'] == 'message' and delta['event'] == 'modify'
    assert delta['attributes']['unread'] is True
コード例 #37
0
ファイル: test_delta_sync.py プロジェクト: nkhuyu/sync-engine
def test_events_are_condensed(api_client, message):
    """
    Test that multiple revisions of the same object are rolled up in the
    delta response.

    """
    ts = int(time.time() + 22)
    cursor = get_cursor(api_client, ts)

    # Modify a message, then modify it again
    message_id = api_client.get_data('/messages/')[0]['id']
    message_path = '/messages/{}'.format(message_id)
    api_client.put_data(message_path, {'unread': True})
    api_client.put_data(message_path, {'unread': False})
    api_client.put_data(message_path, {'unread': True})

    # Check that successive modifies are condensed.
    sync_data = api_client.get_data('/delta?cursor={}'.format(cursor))
    deltas = sync_data['deltas']
    # A message modify propagates to its thread
    message_deltas = [d for d in deltas if d['object'] == 'message']
    assert len(message_deltas) == 1

    delta = message_deltas[0]
    assert delta['object'] == 'message' and delta['event'] == 'modify'
    assert delta['attributes']['unread'] is True
コード例 #38
0
def test_events_are_condensed(api_client, message):
    """
    Test that multiple revisions of the same object are rolled up in the
    delta response.

    """
    ts = int(time.time() + 22)
    cursor = get_cursor(api_client, ts)

    # Modify a message, then modify it again
    message_id = api_client.get_data("/messages/")[0]["id"]
    message_path = "/messages/{}".format(message_id)
    api_client.put_data(message_path, {"unread": True})
    api_client.put_data(message_path, {"unread": False})
    api_client.put_data(message_path, {"unread": True})

    # Check that successive modifies are condensed.
    sync_data = api_client.get_data("/delta?cursor={}".format(cursor))
    deltas = sync_data["deltas"]
    # A message modify propagates to its thread
    message_deltas = [d for d in deltas if d["object"] == "message"]
    assert len(message_deltas) == 1

    delta = message_deltas[0]
    assert delta["object"] == "message" and delta["event"] == "modify"
    assert delta["attributes"]["unread"] is True
コード例 #39
0
ファイル: test_drafts.py プロジェクト: thomasst/sync-engine
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

    # Check that contacts aren't created for garbage recipients.
    r = api_client.post_data('/drafts',
                             {'to': [{
                                 'name': 'who',
                                 'email': 'nope'
                             }]})
    assert r.status_code == 200
    r = api_client.get_data('/threads?to=nope')
    assert len(r) == 0
    r = api_client.get_data('/contacts?filter=nope')
    assert len(r) == 0
コード例 #40
0
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

    # Check that contacts aren't created for garbage recipients.
    r = api_client.post_data("/drafts",
                             {"to": [{
                                 "name": "who",
                                 "email": "nope"
                             }]})
    assert r.status_code == 200
    r = api_client.get_data("/threads?to=nope")
    assert len(r) == 0
    r = api_client.get_data("/contacts?filter=nope")
    assert len(r) == 0
コード例 #41
0
ファイル: test_drafts.py プロジェクト: brandoncc/sync-engine
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
コード例 #42
0
def test_message_events_are_propagated_to_thread(api_client, message):
    """
    Test that a revision to a message's `propagated_attributes` returns a delta
    for the message and for its thread.

    """
    ts = int(time.time() + 22)
    cursor = get_cursor(api_client, ts)

    message = api_client.get_data('/messages/')[0]
    message_id = message['id']
    assert message['unread'] is True

    thread = api_client.get_data('/threads/{}'.format(message['thread_id']))
    assert thread['unread'] is True

    # Modify a `propagated_attribute` of the message
    message_path = '/messages/{}'.format(message_id)
    api_client.put_data(message_path, {'unread': False})

    # Verify that a `message` and a `thread` modify delta is returned
    sync_data = api_client.get_data('/delta?cursor={}'.format(cursor))
    deltas = sync_data['deltas']
    assert len(deltas) == 2

    message_deltas = [d for d in deltas if d['object'] == 'message']
    assert len(message_deltas) == 1
    delta = message_deltas[0]
    assert delta['object'] == 'message' and delta['event'] == 'modify'
    assert delta['attributes']['unread'] is False

    thread_deltas = [d for d in deltas if d['object'] == 'thread']
    assert len(thread_deltas) == 1
    delta = thread_deltas[0]
    assert delta['object'] == 'thread' and delta['event'] == 'modify'
    assert delta['attributes']['unread'] is False
    assert delta['attributes']['version'] == thread['version'] + 1
コード例 #43
0
def test_message_events_are_propagated_to_thread(api_client, message):
    """
    Test that a revision to a message's `propagated_attributes` returns a delta
    for the message and for its thread.

    """
    ts = int(time.time() + 22)
    cursor = get_cursor(api_client, ts)

    message = api_client.get_data("/messages/")[0]
    message_id = message["id"]
    assert message["unread"] is True

    thread = api_client.get_data("/threads/{}".format(message["thread_id"]))
    assert thread["unread"] is True

    # Modify a `propagated_attribute` of the message
    message_path = "/messages/{}".format(message_id)
    api_client.put_data(message_path, {"unread": False})

    # Verify that a `message` and a `thread` modify delta is returned
    sync_data = api_client.get_data("/delta?cursor={}".format(cursor))
    deltas = sync_data["deltas"]
    assert len(deltas) == 2

    message_deltas = [d for d in deltas if d["object"] == "message"]
    assert len(message_deltas) == 1
    delta = message_deltas[0]
    assert delta["object"] == "message" and delta["event"] == "modify"
    assert delta["attributes"]["unread"] is False

    thread_deltas = [d for d in deltas if d["object"] == "thread"]
    assert len(thread_deltas) == 1
    delta = thread_deltas[0]
    assert delta["object"] == "thread" and delta["event"] == "modify"
    assert delta["attributes"]["unread"] is False
    assert delta["attributes"]["version"] == thread["version"] + 1
コード例 #44
0
ファイル: test_delta_sync.py プロジェクト: nkhuyu/sync-engine
def test_message_events_are_propagated_to_thread(api_client, message):
    """
    Test that a revision to a message's `propagated_attributes` returns a delta
    for the message and for its thread.

    """
    ts = int(time.time() + 22)
    cursor = get_cursor(api_client, ts)

    message = api_client.get_data('/messages/')[0]
    message_id = message['id']
    assert message['unread'] is True

    thread = api_client.get_data('/threads/{}'.format(message['thread_id']))
    assert thread['unread'] is True

    # Modify a `propagated_attribute` of the message
    message_path = '/messages/{}'.format(message_id)
    api_client.put_data(message_path, {'unread': False})

    # Verify that a `message` and a `thread` modify delta is returned
    sync_data = api_client.get_data('/delta?cursor={}'.format(cursor))
    deltas = sync_data['deltas']
    assert len(deltas) == 2

    message_deltas = [d for d in deltas if d['object'] == 'message']
    assert len(message_deltas) == 1
    delta = message_deltas[0]
    assert delta['object'] == 'message' and delta['event'] == 'modify'
    assert delta['attributes']['unread'] is False

    thread_deltas = [d for d in deltas if d['object'] == 'thread']
    assert len(thread_deltas) == 1
    delta = thread_deltas[0]
    assert delta['object'] == 'thread' and delta['event'] == 'modify'
    assert delta['attributes']['unread'] is False
    assert delta['attributes']['version'] == thread['version'] + 1
コード例 #45
0
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
コード例 #46
0
def test_api_update_participant_status(db, api_client, calendar):
    e_data = {
        'title': 'Friday Office Party',
        'when': {'time': 1407542195},
        'calendar_id': calendar.public_id,
        'participants': [{'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'}]
    }

    e_resp = api_client.post_data('/events', e_data)
    e_resp_data = json.loads(e_resp.data)
    assert len(e_resp_data['participants']) == 5
    for i, p in enumerate(e_resp_data['participants']):
        res = [e for e in e_data['participants'] if e['email'] == p['email']]
        assert len(res) == 1
        assert p['name'] is None

    event_id = e_resp_data['id']

    update_data = {
        'calendar_id': calendar.public_id,
        'participants': [{'email': '*****@*****.**',
                          'status': 'yes'},
                         {'email': '*****@*****.**',
                          'status': 'no'},
                         {'email': '*****@*****.**',
                          'status': 'maybe'},
                         {'email': '*****@*****.**'},
                         {'email': '*****@*****.**'}]
    }

    e_resp = api_client.put_data('/events/' + event_id, update_data)
    e_resp_data = json.loads(e_resp.data)

    # Make sure that nothing changed that we didn't specify
    assert e_resp_data['title'] == 'Friday Office Party'
    assert e_resp_data['when']['time'] == 1407542195

    assert len(e_resp_data['participants']) == 5
    for i, p in enumerate(e_resp_data['participants']):
        res = [e for e in e_data['participants'] if e['email'] == p['email']]
        assert len(res) == 1
        assert p['name'] is None
コード例 #47
0
ファイル: test_drafts.py プロジェクト: thomasst/sync-engine
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
コード例 #48
0
def test_api_event_when_update(db, api_client, calendar, default_namespace):
    e_data = {
        'title': 'Friday Office Party',
        'location': 'home',
        'calendar_id': calendar.public_id,
    }

    e_data['when'] = {'time': 0}
    e_resp_data = _verify_create(default_namespace.public_id, api_client,
                                 e_data)
    e_id = e_resp_data['id']

    e_update_data = {'when': {'time': 1}}
    e_put_resp = api_client.put_data('/events/' + e_id, e_update_data)
    e_put_data = json.loads(e_put_resp.data)
    assert e_put_data['when']['object'] == 'time'
    assert e_put_data['when']['time'] == e_update_data['when']['time']
コード例 #49
0
def test_api_event_when_update(db, api_client, calendar, default_namespace):
    e_data = {
        'title': 'Friday Office Party',
        'location': 'home',
        'calendar_id': calendar.public_id,
    }

    e_data['when'] = {'time': 0}
    e_resp_data = _verify_create(default_namespace.public_id, api_client,
                                 e_data)
    e_id = e_resp_data['id']

    e_update_data = {'when': {'time': 1}}
    e_put_resp = api_client.put_data('/events/' + e_id, e_update_data)
    e_put_data = json.loads(e_put_resp.data)
    assert e_put_data['when']['object'] == 'time'
    assert e_put_data['when']['time'] == e_update_data['when']['time']
コード例 #50
0
def test_api_event_when_update(db, api_client, calendar, default_namespace):
    e_data = {
        "title": "Friday Office Party",
        "location": "home",
        "calendar_id": calendar.public_id,
    }

    e_data["when"] = {"time": 0}
    e_resp_data = _verify_create(default_namespace.public_id, api_client,
                                 e_data)
    e_id = e_resp_data["id"]

    e_update_data = {"when": {"time": 1}}
    e_put_resp = api_client.put_data("/events/" + e_id, e_update_data)
    e_put_data = json.loads(e_put_resp.data)
    assert e_put_data["when"]["object"] == "time"
    assert e_put_data["when"]["time"] == e_update_data["when"]["time"]
コード例 #51
0
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
コード例 #52
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_removing_a_mutually_exclusive_label_does_not_orphan_a_message(
        db, api_client, default_account, folder_and_message_maps, label):
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
    labels = resp_data['labels']
    assert len(labels) == 1
    assert labels[0]['name'] == label

    custom_label = add_fake_label(db.session, default_account, '<3', None)
    db.session.commit()

    # Removing a message's ONLY folder "label" does not remove it.
    # Gmail messages MUST belong to one of 'all'/ 'trash'/ 'spam'.
    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': [custom_label.category.public_id]})
    labels = json.loads(response.data)['labels']
    assert len(labels) == 2
    assert set([l['name'] for l in labels]) == set([label, None])
    assert '<3' in [l['display_name'] for l in labels]
コード例 #53
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_adding_a_custom_label_preserves_other_labels(
        db, api_client, default_account, folder_and_message_maps, label):
    folder_map, message_map = folder_and_message_maps

    message = message_map[label]
    resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
    labels = resp_data['labels']
    assert len(labels) == 1
    assert labels[0]['name'] == label
    existing_label = labels[0]['id']

    custom_label = add_fake_label(db.session, default_account, '<3', None)
    db.session.commit()

    # Adding only a custom label does not move a message to a different folder
    # i.e. does not change its 'all'/ 'trash'/ 'spam' labels.
    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': [custom_label.category.public_id, existing_label]})
    labels = json.loads(response.data)['labels']
    assert len(labels) == 2
    assert set([l['name'] for l in labels]) == set([label, None])
    assert '<3' in [l['display_name'] for l in labels]
コード例 #54
0
ファイル: test_drafts.py プロジェクト: busseyl/sync-engine
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
コード例 #55
0
ファイル: test_labels.py プロジェクト: DrMoriarty/sync-engine
def test_adding_trash_or_spam_removes_inbox(
        db, api_client, default_account, folder_and_message_maps, label):
    # Verify a Gmail message in 'trash', 'spam' cannot have 'inbox'.
    # We specifically test that adding 'trash'/ 'spam' to a message with 'inbox'
    # removes it.
    folder_map, message_map = folder_and_message_maps

    message = message_map['all']
    add_inbox_label(db, default_account, message)
    resp_data = api_client.get_data('/messages/{}'.format(message.public_id))
    labels = resp_data['labels']
    assert len(labels) == 2
    assert set([l['name'] for l in labels]) == set(['all', 'inbox'])

    # Adding 'trash'/ 'spam' removes 'inbox' (and 'all'),
    # irrespective of whether it's provided in the request or not.
    label_to_add = folder_map[label]
    response = api_client.put_data(
        '/messages/{}'.format(message.public_id),
        {'label_ids': [label_to_add.category.public_id] +
            [l['id'] for l in labels]})
    labels = json.loads(response.data)['labels']
    assert len(labels) == 1
    assert labels[0]['name'] == label
コード例 #56
0
ファイル: test_drafts.py プロジェクト: brandoncc/sync-engine
def test_update_draft(api_client):
    with freeze_time(datetime.now()) as freezer:
        original_draft = {
            'subject': 'original 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']
        assert version == 0

        freezer.tick()

        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']

        assert updated_public_id == draft_public_id
        assert updated_version > 0

        drafts = api_client.get_data('/drafts')
        assert len(drafts) == 1
        assert drafts[0]['id'] == updated_public_id

        # Check that the thread is updated too.
        thread = api_client.get_data('/threads/{}'.format(drafts[0]['thread_id']))
        assert thread['subject'] == 'updated draft'
        assert thread['first_message_timestamp'] == drafts[0]['date']
        assert thread['last_message_timestamp'] == drafts[0]['date']
コード例 #57
0
ファイル: test_events.py プロジェクト: yodiyo/sync-engine
def test_api_update_invalid(db, api_client, calendar):
    e_update_data = {'title': 'new title'}
    e_id = generate_public_id()
    e_put_resp = api_client.put_data('/events/' + e_id, e_update_data)
    assert e_put_resp.status_code != 200