Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/aleph/model/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ async def get_merged_posts(filters, sort=None, limit=100, skip=0, amend_limit=1)
}
}
},
{"$project": {"amends": 0}},
{"$project": {"_id": 0, "amends": 0}},
{"$replaceRoot": {"newRoot": {"$mergeObjects": ["$$ROOT", "$content"]}}},
]

Expand Down
4 changes: 2 additions & 2 deletions src/aleph/web/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ def init_sio(app: web.Application) -> socketio.AsyncServer:
return sio


def create_app() -> web.Application:
app = web.Application(client_max_size=1024 ** 2 * 64)
def create_app(debug: bool = False) -> web.Application:
app = web.Application(client_max_size=1024**2 * 64, debug=debug)

tpl_path = pkg_resources.resource_filename("aleph.web", "templates")
jinja_loader = jinja2.ChoiceLoader(
Expand Down
5 changes: 1 addition & 4 deletions src/aleph/web/controllers/posts.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,7 @@ async def view_posts_list(request):
context = {"posts": posts}

if pagination_per_page is not None:
total_msgs = await Message.collection.count_documents(
filter=find_filters,
projection={"_id": 0},
)
total_msgs = await Message.collection.count_documents(filter=find_filters)

pagination = Pagination(
pagination_page,
Expand Down
Empty file added tests/api/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions tests/api/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import json
from pathlib import Path
import pytest_asyncio
from aleph.model.messages import Message


@pytest_asyncio.fixture
async def fixture_messages(test_db):
fixtures_dir = Path(__file__).parent / "fixtures"
fixtures_file = fixtures_dir / "fixture_messages.json"

with fixtures_file.open() as f:
messages = json.load(f)

await Message.collection.insert_many(messages)
return messages
Empty file.
23 changes: 2 additions & 21 deletions tests/api/test_messages.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import itertools
import json
from pathlib import Path
from typing import Dict, Iterable, List
from typing import Dict, Iterable

import pytest
import pytest_asyncio

from aleph.model.messages import Message
from .utils import get_messages_by_keys

MESSAGES_URI = "/api/v0/messages.json"


def get_messages_by_keys(messages: Iterable[Dict], **keys) -> List[Dict]:
return [msg for msg in messages if all(msg[k] == v for k, v in keys.items())]


def check_message_fields(messages: Iterable[Dict]):
"""
Basic checks on fields. For example, check that we do not expose internal data
Expand All @@ -38,18 +31,6 @@ def assert_messages_equal(messages: Iterable[Dict], expected_messages: Iterable[
assert message["signature"] == expected_message["signature"]


@pytest_asyncio.fixture
async def fixture_messages(test_db):
fixtures_dir = Path(__file__).parent / "fixtures"
fixtures_file = fixtures_dir / "fixture_messages.json"

with fixtures_file.open() as f:
messages = json.load(f)

await Message.collection.insert_many(messages)
return messages


@pytest.mark.asyncio
async def test_get_messages(fixture_messages, ccn_api_client):
response = await ccn_api_client.get(MESSAGES_URI)
Expand Down
59 changes: 59 additions & 0 deletions tests/api/test_posts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import Dict, Iterable

import aiohttp
import pytest
from aleph_message.models import MessageType

from .utils import get_messages_by_keys

POSTS_URI = "/api/v0/posts.json"


def assert_posts_equal(posts: Iterable[Dict], expected_messages: Iterable[Dict]):
posts_by_hash = {post["item_hash"]: post for post in posts}

for expected_message in expected_messages:
post = posts_by_hash[expected_message["item_hash"]]
assert "_id" not in post

assert post["chain"] == expected_message["chain"]
assert post["channel"] == expected_message["channel"]
assert post["sender"] == expected_message["sender"]
assert post["signature"] == expected_message["signature"]

if expected_message.get("forgotten_by", []):
assert post["content"] is None
continue

if "content" not in expected_message["content"]:
# TODO: there is a problem with the spec of posts: they can be specified
# without an internal "content" field, which does not break the
# endpoint but returns the content of message["content"] instead.
# We skip the issue for now.
continue

assert post["content"] == expected_message["content"]["content"]


async def get_posts(api_client, **params) -> aiohttp.ClientResponse:
return await api_client.get(POSTS_URI, params=params)


async def get_posts_expect_success(api_client, **params):
response = await get_posts(api_client, **params)
assert response.status == 200, await response.text()
data = await response.json()
return data["posts"]


@pytest.mark.asyncio
async def test_get_posts(fixture_messages, ccn_api_client):
# The POST messages in the fixtures file do not amend one another, so we should have
# 1 POST = 1 message.
post_messages = get_messages_by_keys(
fixture_messages,
type=MessageType.post,
)
posts = await get_posts_expect_success(ccn_api_client)

assert_posts_equal(posts, post_messages)
27 changes: 27 additions & 0 deletions tests/api/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from typing import Dict, Iterable, List, Callable


def get_messages_by_predicate(
messages: Iterable[Dict], predicate: Callable[[Dict], bool]
) -> List[Dict]:
"""
Filters messages based on a user-provided predicate
(=a function/lambda operating on a single message).
"""

return [msg for msg in messages if predicate(msg)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this function really useful ?
It introduces the uncommon term predicate and only contains a trivial one line of code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use it a ton in another PR, just thought I'd introduce it here so that it's already in. I can rename 'predicate' to 'cond', that works as well.



def get_messages_by_keys(messages: Iterable[Dict], **keys) -> List[Dict]:
"""
Filters messages based on user-provided keys.

Example:
>>> filtered_messages = get_messages_by_keys(
>>> message_list, item_hash="some-hash", channel="MY-CHANNEL"
>>> )

"""
return get_messages_by_predicate(
messages, lambda msg: all(msg[k] == v for k, v in keys.items())
)
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async def ccn_api_client(aiohttp_client, mock_config):
event_loop = asyncio.get_event_loop()
event_loop.set_debug(True)

app = create_app()
app = create_app(debug=True)
app["config"] = mock_config
client = await aiohttp_client(app)

Expand Down