1
0
Fork 0

Merge branch 'main' into image-absolute-url-getter

This commit is contained in:
Mouse Reeve 2021-10-20 15:12:06 -07:00 committed by GitHub
commit 9d4e0851a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
537 changed files with 34775 additions and 18490 deletions

View file

@ -1,6 +1,4 @@
import datetime
from unittest.mock import patch
"""test author serializer"""
from django.test import TestCase
from bookwyrm import models

View file

@ -19,17 +19,24 @@ from bookwyrm.activitypub import ActivitySerializerError
from bookwyrm import models
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.suggested_users.rerank_user_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class BaseActivity(TestCase):
"""the super class for model-linked activitypub dataclasses"""
def setUp(self):
"""we're probably going to re-use this so why copy/paste"""
self.user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
self.user.remote_id = "http://example.com/a/b"
self.user.save(broadcast=False)
self.user.save(broadcast=False, update_fields=["remote_id"])
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
self.userdata = json.loads(datafile.read_bytes())
@ -44,24 +51,24 @@ class BaseActivity(TestCase):
image.save(output, format=image.format)
self.image_data = output.getvalue()
def test_init(self, _):
def test_init(self, *_):
"""simple successfuly init"""
instance = ActivityObject(id="a", type="b")
self.assertTrue(hasattr(instance, "id"))
self.assertTrue(hasattr(instance, "type"))
def test_init_missing(self, _):
def test_init_missing(self, *_):
"""init with missing required params"""
with self.assertRaises(ActivitySerializerError):
ActivityObject()
def test_init_extra_fields(self, _):
def test_init_extra_fields(self, *_):
"""init ignoring additional fields"""
instance = ActivityObject(id="a", type="b", fish="c")
self.assertTrue(hasattr(instance, "id"))
self.assertTrue(hasattr(instance, "type"))
def test_init_default_field(self, _):
def test_init_default_field(self, *_):
"""replace an existing required field with a default field"""
@dataclass(init=False)
@ -74,7 +81,7 @@ class BaseActivity(TestCase):
self.assertEqual(instance.id, "a")
self.assertEqual(instance.type, "TestObject")
def test_serialize(self, _):
def test_serialize(self, *_):
"""simple function for converting dataclass to dict"""
instance = ActivityObject(id="a", type="b")
serialized = instance.serialize()
@ -83,7 +90,7 @@ class BaseActivity(TestCase):
self.assertEqual(serialized["type"], "b")
@responses.activate
def test_resolve_remote_id(self, _):
def test_resolve_remote_id(self, *_):
"""look up or load remote data"""
# existing item
result = resolve_remote_id("http://example.com/a/b", model=models.User)
@ -105,14 +112,14 @@ class BaseActivity(TestCase):
self.assertEqual(result.remote_id, "https://example.com/user/mouse")
self.assertEqual(result.name, "MOUSE?? MOUSE!!")
def test_to_model_invalid_model(self, _):
def test_to_model_invalid_model(self, *_):
"""catch mismatch between activity type and model type"""
instance = ActivityObject(id="a", type="b")
with self.assertRaises(ActivitySerializerError):
instance.to_model(model=models.User)
@responses.activate
def test_to_model_image(self, _):
def test_to_model_image(self, *_):
"""update an image field"""
activity = activitypub.Person(
id=self.user.remote_id,
@ -145,7 +152,7 @@ class BaseActivity(TestCase):
self.assertEqual(self.user.name, "New Name")
self.assertEqual(self.user.key_pair.public_key, "hi")
def test_to_model_many_to_many(self, _):
def test_to_model_many_to_many(self, *_):
"""annoying that these all need special handling"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(
@ -176,7 +183,7 @@ class BaseActivity(TestCase):
self.assertEqual(status.mention_books.first(), book)
@responses.activate
def test_to_model_one_to_many(self, _):
def test_to_model_one_to_many(self, *_):
"""these are reversed relationships, where the secondary object
keys the primary object but not vice versa"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
@ -215,7 +222,7 @@ class BaseActivity(TestCase):
self.assertIsNone(status.attachments.first())
@responses.activate
def test_set_related_field(self, _):
def test_set_related_field(self, *_):
"""celery task to add back-references to created objects"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(

View file

@ -25,3 +25,4 @@ class Person(TestCase):
self.assertEqual(user.username, "mouse@example.com")
self.assertEqual(user.remote_id, "https://example.com/user/mouse")
self.assertFalse(user.local)
self.assertEqual(user.followers_url, "https://example.com/user/mouse/followers")

View file

@ -0,0 +1 @@
from . import *

View file

@ -5,22 +5,28 @@ from bookwyrm import activitystreams, models
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class Activitystreams(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -31,7 +37,8 @@ class Activitystreams(TestCase):
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
self.book = models.Edition.objects.create(title="test book")
work = models.Work.objects.create(title="test work")
self.book = models.Edition.objects.create(title="test book", parent_work=work)
class TestStream(activitystreams.ActivityStream):
"""test stream, don't have to do anything here"""
@ -136,73 +143,3 @@ class Activitystreams(TestCase):
self.assertFalse(self.local_user in users)
self.assertFalse(self.another_user in users)
self.assertFalse(self.remote_user in users)
def test_homestream_get_audience(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.HomeStream().get_audience(status)
self.assertFalse(users.exists())
def test_homestream_get_audience_with_mentions(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
status.mention_users.add(self.local_user)
users = activitystreams.HomeStream().get_audience(status)
self.assertFalse(self.local_user in users)
self.assertFalse(self.another_user in users)
def test_homestream_get_audience_with_relationship(self, *_):
"""get a list of users that should see a status"""
self.remote_user.followers.add(self.local_user)
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.HomeStream().get_audience(status)
self.assertTrue(self.local_user in users)
self.assertFalse(self.another_user in users)
def test_localstream_get_audience_remote_status(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.LocalStream().get_audience(status)
self.assertEqual(users, [])
def test_localstream_get_audience_local_status(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="public"
)
users = activitystreams.LocalStream().get_audience(status)
self.assertTrue(self.local_user in users)
self.assertTrue(self.another_user in users)
def test_localstream_get_audience_unlisted(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="unlisted"
)
users = activitystreams.LocalStream().get_audience(status)
self.assertEqual(users, [])
def test_federatedstream_get_audience(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.FederatedStream().get_audience(status)
self.assertTrue(self.local_user in users)
self.assertTrue(self.another_user in users)
def test_federatedstream_get_audience_unlisted(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="unlisted"
)
users = activitystreams.FederatedStream().get_audience(status)
self.assertEqual(users, [])

View file

@ -0,0 +1,54 @@
""" testing activitystreams """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import activitystreams, models
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class Activitystreams(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
work = models.Work.objects.create(title="test work")
self.book = models.Edition.objects.create(title="test book", parent_work=work)
def test_get_statuses_for_user_books(self, *_):
"""create a stream for a user"""
alt_book = models.Edition.objects.create(
title="hi", parent_work=self.book.parent_work
)
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="public"
)
status = models.Comment.objects.create(
user=self.remote_user, content="hi", privacy="public", book=alt_book
)
models.ShelfBook.objects.create(
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
book=self.book,
)
# yes book, yes audience
result = activitystreams.BooksStream().get_statuses_for_user(self.local_user)
self.assertEqual(list(result), [status])

View file

@ -0,0 +1,67 @@
""" testing activitystreams """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import activitystreams, models
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class Activitystreams(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
def test_homestream_get_audience(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.HomeStream().get_audience(status)
self.assertFalse(users.exists())
def test_homestream_get_audience_with_mentions(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
status.mention_users.add(self.local_user)
users = activitystreams.HomeStream().get_audience(status)
self.assertFalse(self.local_user in users)
self.assertFalse(self.another_user in users)
def test_homestream_get_audience_with_relationship(self, *_):
"""get a list of users that should see a status"""
self.remote_user.followers.add(self.local_user)
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.HomeStream().get_audience(status)
self.assertTrue(self.local_user in users)
self.assertFalse(self.another_user in users)

View file

@ -0,0 +1,139 @@
""" testing activitystreams """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import activitystreams, models
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class Activitystreams(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
work = models.Work.objects.create(title="test work")
self.book = models.Edition.objects.create(title="test book", parent_work=work)
def test_localstream_get_audience_remote_status(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
users = activitystreams.LocalStream().get_audience(status)
self.assertEqual(users, [])
def test_localstream_get_audience_local_status(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="public"
)
users = activitystreams.LocalStream().get_audience(status)
self.assertTrue(self.local_user in users)
self.assertTrue(self.another_user in users)
def test_localstream_get_audience_unlisted(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="unlisted"
)
users = activitystreams.LocalStream().get_audience(status)
self.assertEqual(users, [])
def test_localstream_get_audience_books_no_book(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="public"
)
audience = activitystreams.BooksStream().get_audience(status)
# no books, no audience
self.assertEqual(audience, [])
def test_localstream_get_audience_books_mention_books(self, *_):
"""get a list of users that should see a status"""
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="public"
)
status.mention_books.add(self.book)
status.save(broadcast=False)
models.ShelfBook.objects.create(
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
book=self.book,
)
# yes book, yes audience
audience = activitystreams.BooksStream().get_audience(status)
self.assertTrue(self.local_user in audience)
def test_localstream_get_audience_books_book_field(self, *_):
"""get a list of users that should see a status"""
status = models.Comment.objects.create(
user=self.local_user, content="hi", privacy="public", book=self.book
)
models.ShelfBook.objects.create(
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
book=self.book,
)
# yes book, yes audience
audience = activitystreams.BooksStream().get_audience(status)
self.assertTrue(self.local_user in audience)
def test_localstream_get_audience_books_alternate_edition(self, *_):
"""get a list of users that should see a status"""
alt_book = models.Edition.objects.create(
title="hi", parent_work=self.book.parent_work
)
status = models.Comment.objects.create(
user=self.remote_user, content="hi", privacy="public", book=alt_book
)
models.ShelfBook.objects.create(
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
book=self.book,
)
# yes book, yes audience
audience = activitystreams.BooksStream().get_audience(status)
self.assertTrue(self.local_user in audience)
def test_localstream_get_audience_books_non_public(self, *_):
"""get a list of users that should see a status"""
alt_book = models.Edition.objects.create(
title="hi", parent_work=self.book.parent_work
)
status = models.Comment.objects.create(
user=self.remote_user, content="hi", privacy="unlisted", book=alt_book
)
models.ShelfBook.objects.create(
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
book=self.book,
)
# yes book, yes audience
audience = activitystreams.BooksStream().get_audience(status)
self.assertEqual(audience, [])

View file

@ -0,0 +1,117 @@
""" testing activitystreams """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import activitystreams, models
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class ActivitystreamsSignals(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"fish", "fish@fish.fish", "password", local=True, localname="fish"
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
work = models.Work.objects.create(title="test work")
self.book = models.Edition.objects.create(title="test book", parent_work=work)
def test_add_status_on_create_ignore(self, _):
"""a new statuses has entered"""
activitystreams.add_status_on_create(models.User, self.local_user, False)
def test_add_status_on_create_deleted(self, _):
"""a new statuses has entered"""
with patch("bookwyrm.activitystreams.remove_status_task.delay"):
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public", deleted=True
)
with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock:
activitystreams.add_status_on_create(models.Status, status, False)
self.assertEqual(mock.call_count, 1)
args = mock.call_args[0]
self.assertEqual(args[0], status.id)
def test_add_status_on_create_created(self, _):
"""a new statuses has entered"""
status = models.Status.objects.create(
user=self.remote_user, content="hi", privacy="public"
)
with patch("bookwyrm.activitystreams.add_status_task.delay") as mock:
activitystreams.add_status_on_create_command(models.Status, status, False)
self.assertEqual(mock.call_count, 1)
args = mock.call_args[0]
self.assertEqual(args[0], status.id)
def test_populate_streams_on_account_create(self, _):
"""create streams for a user"""
with patch("bookwyrm.activitystreams.populate_stream_task.delay") as mock:
activitystreams.populate_streams_on_account_create(
models.User, self.local_user, True
)
self.assertEqual(mock.call_count, 3)
args = mock.call_args[0]
self.assertEqual(args[0], "books")
self.assertEqual(args[1], self.local_user.id)
def test_remove_statuses_on_block(self, _):
"""don't show statuses from blocked users"""
with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay") as mock:
models.UserBlocks.objects.create(
user_subject=self.local_user,
user_object=self.remote_user,
)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user.id)
self.assertEqual(args[1], self.remote_user.id)
def test_add_statuses_on_unblock(self, _):
"""re-add statuses on unblock"""
with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"):
block = models.UserBlocks.objects.create(
user_subject=self.local_user,
user_object=self.remote_user,
)
with patch("bookwyrm.activitystreams.add_user_statuses_task.delay") as mock:
block.delete()
args = mock.call_args[0]
kwargs = mock.call_args.kwargs
self.assertEqual(args[0], self.local_user.id)
self.assertEqual(args[1], self.remote_user.id)
self.assertEqual(kwargs["stream_list"], ["local", "books"])
def test_add_statuses_on_unblock_reciprocal_block(self, _):
"""re-add statuses on unblock"""
with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"):
block = models.UserBlocks.objects.create(
user_subject=self.local_user,
user_object=self.remote_user,
)
block = models.UserBlocks.objects.create(
user_subject=self.remote_user,
user_object=self.local_user,
)
with patch("bookwyrm.activitystreams.add_user_statuses_task.delay") as mock:
block.delete()
self.assertEqual(mock.call_count, 0)

View file

@ -0,0 +1,218 @@
""" testing activitystreams """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import activitystreams, models
class Activitystreams(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
work = models.Work.objects.create(title="test work")
self.book = models.Edition.objects.create(title="test book", parent_work=work)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.status = models.Status.objects.create(
content="hi", user=self.local_user
)
def test_add_book_statuses_task(self):
"""statuses related to a book"""
with patch("bookwyrm.activitystreams.BooksStream.add_book_statuses") as mock:
activitystreams.add_book_statuses_task(self.local_user.id, self.book.id)
self.assertTrue(mock.called)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
self.assertEqual(args[1], self.book)
def test_remove_book_statuses_task(self):
"""remove stauses related to a book"""
with patch("bookwyrm.activitystreams.BooksStream.remove_book_statuses") as mock:
activitystreams.remove_book_statuses_task(self.local_user.id, self.book.id)
self.assertTrue(mock.called)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
self.assertEqual(args[1], self.book)
def test_populate_stream_task(self):
"""populate a given stream"""
with patch("bookwyrm.activitystreams.BooksStream.populate_streams") as mock:
activitystreams.populate_stream_task("books", self.local_user.id)
self.assertTrue(mock.called)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
with patch("bookwyrm.activitystreams.HomeStream.populate_streams") as mock:
activitystreams.populate_stream_task("home", self.local_user.id)
self.assertTrue(mock.called)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
def test_remove_status_task(self):
"""remove a status from all streams"""
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as mock:
activitystreams.remove_status_task(self.status.id)
self.assertEqual(mock.call_count, 3)
args = mock.call_args[0]
self.assertEqual(args[0], self.status)
def test_add_status_task(self):
"""add a status to all streams"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as mock:
activitystreams.add_status_task(self.status.id)
self.assertEqual(mock.call_count, 3)
args = mock.call_args[0]
self.assertEqual(args[0], self.status)
def test_remove_user_statuses_task(self):
"""remove all statuses by a user from another users' feeds"""
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_user_statuses"
) as mock:
activitystreams.remove_user_statuses_task(
self.local_user.id, self.another_user.id
)
self.assertEqual(mock.call_count, 3)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
self.assertEqual(args[1], self.another_user)
with patch("bookwyrm.activitystreams.HomeStream.remove_user_statuses") as mock:
activitystreams.remove_user_statuses_task(
self.local_user.id, self.another_user.id, stream_list=["home"]
)
self.assertEqual(mock.call_count, 1)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
self.assertEqual(args[1], self.another_user)
def test_add_user_statuses_task(self):
"""add a user's statuses to another users feeds"""
with patch("bookwyrm.activitystreams.ActivityStream.add_user_statuses") as mock:
activitystreams.add_user_statuses_task(
self.local_user.id, self.another_user.id
)
self.assertEqual(mock.call_count, 3)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
self.assertEqual(args[1], self.another_user)
with patch("bookwyrm.activitystreams.HomeStream.add_user_statuses") as mock:
activitystreams.add_user_statuses_task(
self.local_user.id, self.another_user.id, stream_list=["home"]
)
self.assertEqual(mock.call_count, 1)
args = mock.call_args[0]
self.assertEqual(args[0], self.local_user)
self.assertEqual(args[1], self.another_user)
@patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_boost_to_another_timeline(self, *_):
"""boost from a non-follower doesn't remove original status from feed"""
status = models.Status.objects.create(user=self.local_user, content="hi")
with patch("bookwyrm.activitystreams.handle_boost_task.delay"):
boost = models.Boost.objects.create(
boosted_status=status,
user=self.another_user,
)
with patch(
"bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores"
) as mock:
activitystreams.handle_boost_task(boost.id)
self.assertTrue(mock.called)
self.assertEqual(mock.call_count, 1)
call_args = mock.call_args
self.assertEqual(call_args[0][0], status)
self.assertEqual(call_args[1]["stores"], [f"{self.another_user.id}-home"])
@patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_boost_to_another_timeline_remote(self, *_):
"""boost from a remote non-follower doesn't remove original status from feed"""
status = models.Status.objects.create(user=self.local_user, content="hi")
with patch("bookwyrm.activitystreams.handle_boost_task.delay"):
boost = models.Boost.objects.create(
boosted_status=status,
user=self.remote_user,
)
with patch(
"bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores"
) as mock:
activitystreams.handle_boost_task(boost.id)
self.assertTrue(mock.called)
self.assertEqual(mock.call_count, 1)
call_args = mock.call_args
self.assertEqual(call_args[0][0], status)
self.assertEqual(call_args[1]["stores"], [])
@patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_boost_to_following_timeline(self, *_):
"""add a boost and deduplicate the boosted status on the timeline"""
self.local_user.following.add(self.another_user)
status = models.Status.objects.create(user=self.local_user, content="hi")
with patch("bookwyrm.activitystreams.handle_boost_task.delay"):
boost = models.Boost.objects.create(
boosted_status=status,
user=self.another_user,
)
with patch(
"bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores"
) as mock:
activitystreams.handle_boost_task(boost.id)
self.assertTrue(mock.called)
call_args = mock.call_args
self.assertEqual(call_args[0][0], status)
self.assertTrue(f"{self.another_user.id}-home" in call_args[1]["stores"])
self.assertTrue(f"{self.local_user.id}-home" in call_args[1]["stores"])
@patch("bookwyrm.activitystreams.LocalStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.BooksStream.remove_object_from_related_stores")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_boost_to_same_timeline(self, *_):
"""add a boost and deduplicate the boosted status on the timeline"""
status = models.Status.objects.create(user=self.local_user, content="hi")
with patch("bookwyrm.activitystreams.handle_boost_task.delay"):
boost = models.Boost.objects.create(
boosted_status=status,
user=self.local_user,
)
with patch(
"bookwyrm.activitystreams.HomeStream.remove_object_from_related_stores"
) as mock:
activitystreams.handle_boost_task(boost.id)
self.assertTrue(mock.called)
call_args = mock.call_args
self.assertEqual(call_args[0][0], status)
self.assertEqual(call_args[1]["stores"], [f"{self.local_user.id}-home"])

View file

@ -119,7 +119,7 @@ class AbstractConnector(TestCase):
@responses.activate
def test_get_or_create_author(self):
"""load an author"""
self.connector.author_mappings = [
self.connector.author_mappings = [ # pylint: disable=attribute-defined-outside-init # pylint: disable=attribute-defined-outside-init
Mapping("id"),
Mapping("name"),
]

View file

@ -4,7 +4,7 @@ import responses
from bookwyrm import models
from bookwyrm.connectors import abstract_connector
from bookwyrm.connectors.abstract_connector import Mapping, SearchResult
from bookwyrm.connectors.abstract_connector import Mapping
class AbstractConnector(TestCase):
@ -53,7 +53,6 @@ class AbstractConnector(TestCase):
self.assertEqual(connector.isbn_search_url, "https://example.com/isbn?q=")
self.assertIsNone(connector.name)
self.assertEqual(connector.identifier, "example.com")
self.assertFalse(connector.local)
@responses.activate
def test_search(self):
@ -94,19 +93,6 @@ class AbstractConnector(TestCase):
results = self.test_connector.isbn_search("123456")
self.assertEqual(len(results), 10)
def test_search_result(self):
"""a class that stores info about a search result"""
result = SearchResult(
title="Title",
key="https://example.com/book/1",
author="Author Name",
year="1850",
connector=self.test_connector,
)
# there's really not much to test here, it's just a dataclass
self.assertEqual(result.confidence, 1)
self.assertEqual(result.title, "Title")
def test_create_mapping(self):
"""maps remote fields for book data to bookwyrm activitypub fields"""
mapping = Mapping("isbn")

View file

@ -4,8 +4,8 @@ import pathlib
from django.test import TestCase
from bookwyrm import models
from bookwyrm.book_search import SearchResult
from bookwyrm.connectors.bookwyrm_connector import Connector
from bookwyrm.connectors.abstract_connector import SearchResult
class BookWyrmConnector(TestCase):

View file

@ -5,7 +5,6 @@ import responses
from bookwyrm import models
from bookwyrm.connectors import connector_manager
from bookwyrm.connectors.bookwyrm_connector import Connector as BookWyrmConnector
from bookwyrm.connectors.self_connector import Connector as SelfConnector
class ConnectorManager(TestCase):
@ -15,28 +14,16 @@ class ConnectorManager(TestCase):
"""we'll need some books and a connector info entry"""
self.work = models.Work.objects.create(title="Example Work")
self.edition = models.Edition.objects.create(
models.Edition.objects.create(
title="Example Edition", parent_work=self.work, isbn_10="0000000000"
)
self.edition = models.Edition.objects.create(
title="Another Edition", parent_work=self.work, isbn_10="1111111111"
)
self.connector = models.Connector.objects.create(
identifier="test_connector",
priority=1,
local=True,
connector_file="self_connector",
base_url="http://test.com/",
books_url="http://test.com/",
covers_url="http://test.com/",
isbn_search_url="http://test.com/isbn/",
)
self.remote_connector = models.Connector.objects.create(
identifier="test_connector_remote",
priority=1,
local=False,
connector_file="bookwyrm_connector",
base_url="http://fake.ciom/",
books_url="http://fake.ciom/",
@ -59,23 +46,22 @@ class ConnectorManager(TestCase):
def test_get_connectors(self):
"""load all connectors"""
connectors = list(connector_manager.get_connectors())
self.assertEqual(len(connectors), 2)
self.assertIsInstance(connectors[0], SelfConnector)
self.assertIsInstance(connectors[1], BookWyrmConnector)
self.assertEqual(len(connectors), 1)
self.assertIsInstance(connectors[0], BookWyrmConnector)
@responses.activate
def test_search(self):
def test_search_plaintext(self):
"""search all connectors"""
responses.add(
responses.GET,
"http://fake.ciom/search/Example?min_confidence=0.1",
json={},
json=[{"title": "Hello", "key": "https://www.example.com/search/1"}],
)
results = connector_manager.search("Example")
self.assertEqual(len(results), 1)
self.assertIsInstance(results[0]["connector"], SelfConnector)
self.assertEqual(len(results[0]["results"]), 1)
self.assertEqual(results[0]["results"][0].title, "Example Edition")
self.assertEqual(results[0]["connector"].identifier, "test_connector_remote")
self.assertEqual(results[0]["results"][0].title, "Hello")
def test_search_empty_query(self):
"""don't panic on empty queries"""
@ -88,19 +74,13 @@ class ConnectorManager(TestCase):
responses.add(
responses.GET,
"http://fake.ciom/isbn/0000000000",
json={},
json=[{"title": "Hello", "key": "https://www.example.com/search/1"}],
)
results = connector_manager.search("0000000000")
self.assertEqual(len(results), 1)
self.assertIsInstance(results[0]["connector"], SelfConnector)
self.assertEqual(len(results[0]["results"]), 1)
self.assertEqual(results[0]["results"][0].title, "Example Edition")
def test_local_search(self):
"""search only the local database"""
results = connector_manager.local_search("Example")
self.assertEqual(len(results), 1)
self.assertEqual(results[0].title, "Example Edition")
self.assertEqual(results[0]["connector"].identifier, "test_connector_remote")
self.assertEqual(results[0]["results"][0].title, "Hello")
def test_first_search_result(self):
"""only get one search result"""
@ -125,6 +105,5 @@ class ConnectorManager(TestCase):
def test_load_connector(self):
"""load a connector object from the database entry"""
connector = connector_manager.load_connector(self.connector)
self.assertIsInstance(connector, SelfConnector)
self.assertEqual(connector.identifier, "test_connector")
connector = connector_manager.load_connector(self.remote_connector)
self.assertEqual(connector.identifier, "test_connector_remote")

View file

@ -171,3 +171,15 @@ class Inventaire(TestCase):
}
self.assertEqual(get_language_code(options), "there")
self.assertIsNone(get_language_code({}))
@responses.activate
def test_get_description(self):
"""extract a wikipedia excerpt"""
responses.add(
responses.GET,
"https://inventaire.io/api/data?action=wp-extract&lang=en&title=test_path",
json={"extract": "hi hi"},
)
extract = self.connector.get_description({"enwiki": "test_path"})
self.assertEqual(extract, "hi hi")

View file

@ -7,11 +7,11 @@ from django.test import TestCase
import responses
from bookwyrm import models
from bookwyrm.book_search import SearchResult
from bookwyrm.connectors.openlibrary import Connector
from bookwyrm.connectors.openlibrary import ignore_edition
from bookwyrm.connectors.openlibrary import get_languages, get_description
from bookwyrm.connectors.openlibrary import pick_default_edition, get_openlibrary_key
from bookwyrm.connectors.abstract_connector import SearchResult
from bookwyrm.connectors.connector_manager import ConnectorException

View file

@ -1,107 +0,0 @@
""" testing book data connectors """
import datetime
from django.test import TestCase
from django.utils import timezone
from bookwyrm import models
from bookwyrm.connectors.self_connector import Connector
from bookwyrm.settings import DOMAIN
class SelfConnector(TestCase):
"""just uses local data"""
def setUp(self):
"""creating the connector"""
models.Connector.objects.create(
identifier=DOMAIN,
name="Local",
local=True,
connector_file="self_connector",
base_url="https://%s" % DOMAIN,
books_url="https://%s/book" % DOMAIN,
covers_url="https://%s/images/covers" % DOMAIN,
search_url="https://%s/search?q=" % DOMAIN,
priority=1,
)
self.connector = Connector(DOMAIN)
def test_format_search_result(self):
"""create a SearchResult"""
author = models.Author.objects.create(name="Anonymous")
edition = models.Edition.objects.create(
title="Edition of Example Work",
published_date=datetime.datetime(1980, 5, 10, tzinfo=timezone.utc),
)
edition.authors.add(author)
result = self.connector.search("Edition of Example")[0]
self.assertEqual(result.title, "Edition of Example Work")
self.assertEqual(result.key, edition.remote_id)
self.assertEqual(result.author, "Anonymous")
self.assertEqual(result.year, 1980)
self.assertEqual(result.connector, self.connector)
def test_search_rank(self):
"""prioritize certain results"""
author = models.Author.objects.create(name="Anonymous")
edition = models.Edition.objects.create(
title="Edition of Example Work",
published_date=datetime.datetime(1980, 5, 10, tzinfo=timezone.utc),
parent_work=models.Work.objects.create(title=""),
)
# author text is rank B
edition.authors.add(author)
# series is rank D
models.Edition.objects.create(
title="Another Edition",
series="Anonymous",
parent_work=models.Work.objects.create(title=""),
)
# subtitle is rank B
models.Edition.objects.create(
title="More Editions",
subtitle="The Anonymous Edition",
parent_work=models.Work.objects.create(title=""),
)
# title is rank A
models.Edition.objects.create(title="Anonymous")
# doesn't rank in this search
models.Edition.objects.create(
title="An Edition", parent_work=models.Work.objects.create(title="")
)
results = self.connector.search("Anonymous")
self.assertEqual(len(results), 4)
self.assertEqual(results[0].title, "Anonymous")
self.assertEqual(results[1].title, "More Editions")
self.assertEqual(results[2].title, "Edition of Example Work")
self.assertEqual(results[3].title, "Another Edition")
def test_search_multiple_editions(self):
"""it should get rid of duplicate editions for the same work"""
work = models.Work.objects.create(title="Work Title")
edition_1 = models.Edition.objects.create(
title="Edition 1 Title", parent_work=work
)
edition_2 = models.Edition.objects.create(
title="Edition 2 Title",
parent_work=work,
isbn_13="123456789", # this is now the defualt edition
)
edition_3 = models.Edition.objects.create(title="Fish", parent_work=work)
# pick the best edition
results = self.connector.search("Edition 1 Title")
self.assertEqual(len(results), 1)
self.assertEqual(results[0].key, edition_1.remote_id)
# pick the default edition when no match is best
results = self.connector.search("Edition Title")
self.assertEqual(len(results), 1)
self.assertEqual(results[0].key, edition_2.remote_id)
# only matches one edition, so no deduplication takes place
results = self.connector.search("Fish")
self.assertEqual(len(results), 1)
self.assertEqual(results[0].key, edition_3.remote_id)

View file

@ -28,7 +28,7 @@
},
"bookwyrmUser": true,
"manuallyApprovesFollowers": false,
"discoverable": true,
"discoverable": false,
"devices": "https://friend.camp/users/tripofmice/collections/devices",
"tag": [],
"icon": {

View file

@ -12,13 +12,17 @@ import responses
from bookwyrm import models
from bookwyrm.importers import GoodreadsImporter
from bookwyrm.importers.importer import import_data, handle_imported_book
from bookwyrm.settings import DOMAIN
def make_date(*args):
"""helper function to easily generate a date obj"""
return datetime.datetime(*args, tzinfo=pytz.UTC)
# pylint: disable=consider-using-with
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
class GoodreadsImport(TestCase):
"""importing from goodreads csv"""
@ -27,21 +31,13 @@ class GoodreadsImport(TestCase):
self.importer = GoodreadsImporter()
datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
self.csv = open(datafile, "r", encoding=self.importer.encoding)
self.user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True
)
models.Connector.objects.create(
identifier=DOMAIN,
name="Local",
local=True,
connector_file="self_connector",
base_url="https://%s" % DOMAIN,
books_url="https://%s/book" % DOMAIN,
covers_url="https://%s/images/covers" % DOMAIN,
search_url="https://%s/search?q=" % DOMAIN,
priority=1,
)
work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
@ -49,7 +45,7 @@ class GoodreadsImport(TestCase):
parent_work=work,
)
def test_create_job(self):
def test_create_job(self, *_):
"""creates the import job entry and checks csv"""
import_job = self.importer.create_job(self.user, self.csv, False, "public")
self.assertEqual(import_job.user, self.user)
@ -65,7 +61,7 @@ class GoodreadsImport(TestCase):
self.assertEqual(import_items[2].index, 2)
self.assertEqual(import_items[2].data["Book Id"], "28694510")
def test_create_retry_job(self):
def test_create_retry_job(self, *_):
"""trying again with items that didn't import"""
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
import_items = models.ImportItem.objects.filter(job=import_job).all()[:2]
@ -83,7 +79,7 @@ class GoodreadsImport(TestCase):
self.assertEqual(retry_items[1].index, 1)
self.assertEqual(retry_items[1].data["Book Id"], "52691223")
def test_start_import(self):
def test_start_import(self, *_):
"""begin loading books"""
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
MockTask = namedtuple("Task", ("id"))
@ -95,7 +91,7 @@ class GoodreadsImport(TestCase):
self.assertEqual(import_job.task_id, "7")
@responses.activate
def test_import_data(self):
def test_import_data(self, *_):
"""resolve entry"""
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
book = models.Edition.objects.create(title="Test Book")
@ -110,14 +106,14 @@ class GoodreadsImport(TestCase):
import_item = models.ImportItem.objects.get(job=import_job, index=0)
self.assertEqual(import_item.book.id, book.id)
def test_handle_imported_book(self):
def test_handle_imported_book(self, *_):
"""goodreads import added a book, this adds related connections"""
shelf = self.user.shelf_set.filter(identifier="read").first()
self.assertIsNone(shelf.books.first())
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
csv_file = open(datafile, "r")
csv_file = open(datafile, "r") # pylint: disable=unspecified-encoding
for index, entry in enumerate(list(csv.DictReader(csv_file))):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
@ -141,7 +137,7 @@ class GoodreadsImport(TestCase):
self.assertEqual(readthrough.start_date, make_date(2020, 10, 21))
self.assertEqual(readthrough.finish_date, make_date(2020, 10, 25))
def test_handle_imported_book_already_shelved(self):
def test_handle_imported_book_already_shelved(self, *_):
"""goodreads import added a book, this adds related connections"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = self.user.shelf_set.filter(identifier="to-read").first()
@ -154,7 +150,7 @@ class GoodreadsImport(TestCase):
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
csv_file = open(datafile, "r")
csv_file = open(datafile, "r") # pylint: disable=unspecified-encoding
for index, entry in enumerate(list(csv.DictReader(csv_file))):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
@ -179,12 +175,12 @@ class GoodreadsImport(TestCase):
self.assertEqual(readthrough.start_date, make_date(2020, 10, 21))
self.assertEqual(readthrough.finish_date, make_date(2020, 10, 25))
def test_handle_import_twice(self):
def test_handle_import_twice(self, *_):
"""re-importing books"""
shelf = self.user.shelf_set.filter(identifier="read").first()
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
csv_file = open(datafile, "r")
csv_file = open(datafile, "r") # pylint: disable=unspecified-encoding
for index, entry in enumerate(list(csv.DictReader(csv_file))):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
@ -211,12 +207,12 @@ class GoodreadsImport(TestCase):
self.assertEqual(readthrough.start_date, make_date(2020, 10, 21))
self.assertEqual(readthrough.finish_date, make_date(2020, 10, 25))
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
def test_handle_imported_book_review(self, _):
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_handle_imported_book_review(self, *_):
"""goodreads review import"""
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
csv_file = open(datafile, "r")
csv_file = open(datafile, "r") # pylint: disable=unspecified-encoding
entry = list(csv.DictReader(csv_file))[2]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
@ -233,14 +229,14 @@ class GoodreadsImport(TestCase):
self.assertEqual(review.published_date, make_date(2019, 7, 8))
self.assertEqual(review.privacy, "unlisted")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
def test_handle_imported_book_rating(self, _):
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_handle_imported_book_rating(self, *_):
"""goodreads rating import"""
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath(
"../data/goodreads-rating.csv"
)
csv_file = open(datafile, "r")
csv_file = open(datafile, "r") # pylint: disable=unspecified-encoding
entry = list(csv.DictReader(csv_file))[2]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
@ -257,11 +253,11 @@ class GoodreadsImport(TestCase):
self.assertEqual(review.published_date, make_date(2019, 7, 8))
self.assertEqual(review.privacy, "unlisted")
def test_handle_imported_book_reviews_disabled(self):
def test_handle_imported_book_reviews_disabled(self, *_):
"""goodreads review import"""
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
csv_file = open(datafile, "r")
csv_file = open(datafile, "r") # pylint: disable=unspecified-encoding
entry = list(csv.DictReader(csv_file))[2]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(

View file

@ -11,7 +11,6 @@ import responses
from bookwyrm import models
from bookwyrm.importers import LibrarythingImporter
from bookwyrm.importers.importer import import_data, handle_imported_book
from bookwyrm.settings import DOMAIN
def make_date(*args):
@ -19,6 +18,10 @@ def make_date(*args):
return datetime.datetime(*args, tzinfo=pytz.UTC)
# pylint: disable=consider-using-with
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
class LibrarythingImport(TestCase):
"""importing from librarything tsv"""
@ -29,21 +32,12 @@ class LibrarythingImport(TestCase):
# Librarything generates latin encoded exports...
self.csv = open(datafile, "r", encoding=self.importer.encoding)
self.user = models.User.objects.create_user(
"mmai", "mmai@mmai.mmai", "password", local=True
)
models.Connector.objects.create(
identifier=DOMAIN,
name="Local",
local=True,
connector_file="self_connector",
base_url="https://%s" % DOMAIN,
books_url="https://%s/book" % DOMAIN,
covers_url="https://%s/images/covers" % DOMAIN,
search_url="https://%s/search?q=" % DOMAIN,
priority=1,
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"mmai", "mmai@mmai.mmai", "password", local=True
)
work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
@ -51,7 +45,7 @@ class LibrarythingImport(TestCase):
parent_work=work,
)
def test_create_job(self):
def test_create_job(self, *_):
"""creates the import job entry and checks csv"""
import_job = self.importer.create_job(self.user, self.csv, False, "public")
self.assertEqual(import_job.user, self.user)
@ -67,7 +61,7 @@ class LibrarythingImport(TestCase):
self.assertEqual(import_items[2].index, 2)
self.assertEqual(import_items[2].data["Book Id"], "5015399")
def test_create_retry_job(self):
def test_create_retry_job(self, *_):
"""trying again with items that didn't import"""
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
import_items = models.ImportItem.objects.filter(job=import_job).all()[:2]
@ -86,7 +80,7 @@ class LibrarythingImport(TestCase):
self.assertEqual(retry_items[1].data["Book Id"], "5015319")
@responses.activate
def test_import_data(self):
def test_import_data(self, *_):
"""resolve entry"""
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
book = models.Edition.objects.create(title="Test Book")
@ -101,7 +95,7 @@ class LibrarythingImport(TestCase):
import_item = models.ImportItem.objects.get(job=import_job, index=0)
self.assertEqual(import_item.book.id, book.id)
def test_handle_imported_book(self):
def test_handle_imported_book(self, *_):
"""librarything import added a book, this adds related connections"""
shelf = self.user.shelf_set.filter(identifier="read").first()
self.assertIsNone(shelf.books.first())
@ -131,7 +125,7 @@ class LibrarythingImport(TestCase):
self.assertEqual(readthrough.start_date, make_date(2007, 4, 16))
self.assertEqual(readthrough.finish_date, make_date(2007, 5, 8))
def test_handle_imported_book_already_shelved(self):
def test_handle_imported_book_already_shelved(self, *_):
"""librarything import added a book, this adds related connections"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = self.user.shelf_set.filter(identifier="to-read").first()
@ -163,7 +157,7 @@ class LibrarythingImport(TestCase):
self.assertEqual(readthrough.start_date, make_date(2007, 4, 16))
self.assertEqual(readthrough.finish_date, make_date(2007, 5, 8))
def test_handle_import_twice(self):
def test_handle_import_twice(self, *_):
"""re-importing books"""
shelf = self.user.shelf_set.filter(identifier="read").first()
import_job = models.ImportJob.objects.create(user=self.user)
@ -194,8 +188,8 @@ class LibrarythingImport(TestCase):
self.assertEqual(readthrough.start_date, make_date(2007, 4, 16))
self.assertEqual(readthrough.finish_date, make_date(2007, 5, 8))
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
def test_handle_imported_book_review(self, _):
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_handle_imported_book_review(self, *_):
"""librarything review import"""
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/librarything.tsv")
@ -216,7 +210,7 @@ class LibrarythingImport(TestCase):
self.assertEqual(review.published_date, make_date(2007, 5, 8))
self.assertEqual(review.privacy, "unlisted")
def test_handle_imported_book_reviews_disabled(self):
def test_handle_imported_book_reviews_disabled(self, *_):
"""librarything review import"""
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath("../data/librarything.tsv")

View file

@ -12,16 +12,19 @@ class Activitystreams(TestCase):
def setUp(self):
"""we need some stuff"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
self.another_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -36,13 +39,11 @@ class Activitystreams(TestCase):
def test_populate_streams(self, _):
"""make sure the function on the redis manager gets called"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
models.Comment.objects.create(
user=self.local_user, content="hi", book=self.book
)
with patch(
"bookwyrm.activitystreams.ActivityStream.populate_store"
) as redis_mock:
with patch("bookwyrm.activitystreams.populate_stream_task.delay") as redis_mock:
populate_streams()
self.assertEqual(redis_mock.call_count, 6) # 2 users x 3 streams

View file

@ -20,18 +20,21 @@ from bookwyrm.settings import PAGE_LENGTH
# pylint: disable=invalid-name
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class ActivitypubMixins(TestCase):
"""functionality shared across models"""
def setUp(self):
"""shared data"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
self.local_user.remote_id = "http://example.com/a/b"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -189,7 +192,7 @@ class ActivitypubMixins(TestCase):
def test_get_recipients_combine_inboxes(self, *_):
"""should combine users with the same shared_inbox"""
self.remote_user.shared_inbox = "http://example.com/inbox"
self.remote_user.save(broadcast=False)
self.remote_user.save(broadcast=False, update_fields=["shared_inbox"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
another_remote_user = models.User.objects.create_user(
"nutria",

View file

@ -1,5 +1,6 @@
""" testing models """
from unittest.mock import patch
from django.http import Http404
from django.test import TestCase
from bookwyrm import models
@ -13,9 +14,12 @@ class BaseModel(TestCase):
def setUp(self):
"""shared data"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -36,14 +40,14 @@ class BaseModel(TestCase):
"""these should be generated"""
self.test_model.id = 1
expected = self.test_model.get_remote_id()
self.assertEqual(expected, "https://%s/bookwyrmtestmodel/1" % DOMAIN)
self.assertEqual(expected, f"https://{DOMAIN}/bookwyrmtestmodel/1")
def test_remote_id_with_user(self):
"""format of remote id when there's a user object"""
self.test_model.user = self.local_user
self.test_model.id = 1
expected = self.test_model.get_remote_id()
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmtestmodel/1" % DOMAIN)
self.assertEqual(expected, f"https://{DOMAIN}/user/mouse/bookwyrmtestmodel/1")
def test_set_remote_id(self):
"""this function sets remote ids after creation"""
@ -52,74 +56,77 @@ class BaseModel(TestCase):
instance = models.Work.objects.create(title="work title")
instance.remote_id = None
base_model.set_remote_id(None, instance, True)
self.assertEqual(
instance.remote_id, "https://%s/book/%d" % (DOMAIN, instance.id)
)
self.assertEqual(instance.remote_id, f"https://{DOMAIN}/book/{instance.id}")
# shouldn't set remote_id if it's not created
instance.remote_id = None
base_model.set_remote_id(None, instance, False)
self.assertIsNone(instance.remote_id)
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_object_visible_to_user(self, _):
"""does a user have permission to view an object"""
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="public"
)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
obj = models.Shelf.objects.create(
name="test", user=self.remote_user, privacy="unlisted"
)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="followers"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
obj.mention_users.add(self.local_user)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_object_visible_to_user_follower(self, _):
"""what you can see if you follow a user"""
self.remote_user.followers.add(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="followers"
)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
obj.mention_users.add(self.local_user)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_object_visible_to_user_blocked(self, _):
"""you can't see it if they block you"""
self.remote_user.blocks.add(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="public"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Shelf.objects.create(
name="test", user=self.remote_user, privacy="unlisted"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)

View file

@ -25,10 +25,12 @@ from bookwyrm.models.activitypub_mixin import ActivitypubMixin
from bookwyrm.settings import DOMAIN
# pylint: disable=too-many-public-methods
class ActivitypubFields(TestCase):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class ModelFields(TestCase):
"""overwrites standard model feilds to work with activitypub"""
def test_validate_remote_id(self):
def test_validate_remote_id(self, *_):
"""should look like a url"""
self.assertIsNone(fields.validate_remote_id("http://www.example.com"))
self.assertIsNone(fields.validate_remote_id("https://www.example.com"))
@ -45,7 +47,7 @@ class ActivitypubFields(TestCase):
"http://www.example.com/dlfjg 23/x",
)
def test_activitypub_field_mixin(self):
def test_activitypub_field_mixin(self, *_):
"""generic mixin with super basic to and from functionality"""
instance = fields.ActivitypubFieldMixin()
self.assertEqual(instance.field_to_activity("fish"), "fish")
@ -63,7 +65,7 @@ class ActivitypubFields(TestCase):
instance.name = "snake_case_name"
self.assertEqual(instance.get_activitypub_field(), "snakeCaseName")
def test_set_field_from_activity(self):
def test_set_field_from_activity(self, *_):
"""setter from entire json blob"""
@dataclass
@ -82,7 +84,7 @@ class ActivitypubFields(TestCase):
instance.set_field_from_activity(mock_model, data)
self.assertEqual(mock_model.field_name, "hi")
def test_set_activity_from_field(self):
def test_set_activity_from_field(self, *_):
"""set json field given entire model"""
@dataclass
@ -100,7 +102,7 @@ class ActivitypubFields(TestCase):
instance.set_activity_from_field(data, mock_model)
self.assertEqual(data["fieldName"], "bip")
def test_remote_id_field(self):
def test_remote_id_field(self, *_):
"""just sets some defaults on charfield"""
instance = fields.RemoteIdField()
self.assertEqual(instance.max_length, 255)
@ -109,7 +111,7 @@ class ActivitypubFields(TestCase):
with self.assertRaises(ValidationError):
instance.run_validators("http://www.example.com/dlfjg 23/x")
def test_username_field(self):
def test_username_field(self, *_):
"""again, just setting defaults on username field"""
instance = fields.UsernameField()
self.assertEqual(instance.activitypub_field, "preferredUsername")
@ -130,7 +132,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(instance.field_to_activity("test@example.com"), "test")
def test_privacy_field_defaults(self):
def test_privacy_field_defaults(self, *_):
"""post privacy field's many default values"""
instance = fields.PrivacyField()
self.assertEqual(instance.max_length, 255)
@ -143,9 +145,18 @@ class ActivitypubFields(TestCase):
instance.public, "https://www.w3.org/ns/activitystreams#Public"
)
def test_privacy_field_set_field_from_activity(self):
def test_privacy_field_set_field_from_activity(self, *_):
"""translate between to/cc fields and privacy"""
with patch("bookwyrm.models.user.set_remote_server.delay"):
test_user = User.objects.create_user(
username="test_user@example.com",
local=False,
remote_id="https://example.com/test_user",
inbox="https://example.com/users/test_user/inbox",
followers_url="https://example.com/users/test_user/followers",
)
@dataclass(init=False)
class TestActivity(ActivityObject):
"""real simple mock"""
@ -154,6 +165,7 @@ class ActivitypubFields(TestCase):
cc: List[str]
id: str = "http://hi.com"
type: str = "Test"
attributedTo: str = test_user.remote_id
class TestPrivacyModel(ActivitypubMixin, BookWyrmModel):
"""real simple mock model because BookWyrmModel is abstract"""
@ -185,8 +197,18 @@ class ActivitypubFields(TestCase):
instance.set_field_from_activity(model_instance, data)
self.assertEqual(model_instance.privacy_field, "unlisted")
data.to = [test_user.followers_url]
data.cc = []
instance.set_field_from_activity(model_instance, data)
self.assertEqual(model_instance.privacy_field, "followers")
data.to = ["http://user_remote/followers"]
data.cc = ["http://mentioned_user/remote_id"]
instance.set_field_from_activity(model_instance, data)
self.assertEqual(model_instance.privacy_field, "followers")
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_privacy_field_set_activity_from_field(self, *_):
"""translate between to/cc fields and privacy"""
user = User.objects.create_user(
@ -231,7 +253,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(activity["to"], [user.remote_id])
self.assertEqual(activity["cc"], [])
def test_foreign_key(self):
def test_foreign_key(self, *_):
"""should be able to format a related model"""
instance = fields.ForeignKey("User", on_delete=models.CASCADE)
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
@ -240,7 +262,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(instance.field_to_activity(item), "https://e.b/c")
@responses.activate
def test_foreign_key_from_activity_str(self):
def test_foreign_key_from_activity_str(self, *_):
"""create a new object from a foreign key"""
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
@ -267,7 +289,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(value.remote_id, "https://example.com/user/mouse")
self.assertEqual(value.name, "MOUSE?? MOUSE!!")
def test_foreign_key_from_activity_dict(self):
def test_foreign_key_from_activity_dict(self, *_):
"""test recieving activity json"""
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
@ -287,7 +309,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(value.name, "MOUSE?? MOUSE!!")
# et cetera but we're not testing serializing user json
def test_foreign_key_from_activity_dict_existing(self):
def test_foreign_key_from_activity_dict_existing(self, *_):
"""test receiving a dict of an existing object in the db"""
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
@ -296,7 +318,7 @@ class ActivitypubFields(TestCase):
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
user.remote_id = "https://example.com/user/mouse"
user.save(broadcast=False)
user.save(broadcast=False, update_fields=["remote_id"])
User.objects.create_user(
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
@ -306,7 +328,7 @@ class ActivitypubFields(TestCase):
value = instance.field_from_activity(activitypub.Person(**userdata))
self.assertEqual(value, user)
def test_foreign_key_from_activity_str_existing(self):
def test_foreign_key_from_activity_str_existing(self, *_):
"""test receiving a remote id of an existing object in the db"""
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
user = User.objects.create_user(
@ -319,14 +341,14 @@ class ActivitypubFields(TestCase):
value = instance.field_from_activity(user.remote_id)
self.assertEqual(value, user)
def test_one_to_one_field(self):
def test_one_to_one_field(self, *_):
"""a gussied up foreign key"""
instance = fields.OneToOneField("User", on_delete=models.CASCADE)
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
item = Serializable(lambda: {"a": "b"}, "https://e.b/c")
self.assertEqual(instance.field_to_activity(item), {"a": "b"})
def test_many_to_many_field(self):
def test_many_to_many_field(self, *_):
"""lists!"""
instance = fields.ManyToManyField("User")
@ -344,7 +366,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(instance.field_to_activity(items), "example.com/snake_case")
@responses.activate
def test_many_to_many_field_from_activity(self):
def test_many_to_many_field_from_activity(self, *_):
"""resolve related fields for a list, takes a list of remote ids"""
instance = fields.ManyToManyField(User)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
@ -364,7 +386,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(len(value), 1)
self.assertIsInstance(value[0], User)
def test_tag_field(self):
def test_tag_field(self, *_):
"""a special type of many to many field"""
instance = fields.TagField("User")
@ -383,13 +405,14 @@ class ActivitypubFields(TestCase):
self.assertEqual(result[0].name, "Name")
self.assertEqual(result[0].type, "Serializable")
def test_tag_field_from_activity(self):
def test_tag_field_from_activity(self, *_):
"""loadin' a list of items from Links"""
# TODO
@responses.activate
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
def test_image_field(self, _):
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_image_field(self, *_):
"""storing images"""
user = User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
@ -424,7 +447,7 @@ class ActivitypubFields(TestCase):
self.assertIsInstance(loaded_image, list)
self.assertIsInstance(loaded_image[1], ContentFile)
def test_image_serialize(self):
def test_image_serialize(self, *_):
"""make sure we're creating sensible image paths"""
ValueMock = namedtuple("ValueMock", ("url"))
value_mock = ValueMock("https://your.domain.here/images/fish.jpg")
@ -433,7 +456,7 @@ class ActivitypubFields(TestCase):
self.assertEqual(result.url, "https://your.domain.here/images/fish.jpg")
self.assertEqual(result.name, "hello")
def test_datetime_field(self):
def test_datetime_field(self, *_):
"""this one is pretty simple, it just has to use isoformat"""
instance = fields.DateTimeField()
now = timezone.now()
@ -441,12 +464,12 @@ class ActivitypubFields(TestCase):
self.assertEqual(instance.field_from_activity(now.isoformat()), now)
self.assertEqual(instance.field_from_activity("bip"), None)
def test_array_field(self):
def test_array_field(self, *_):
"""idk why it makes them strings but probably for a good reason"""
instance = fields.ArrayField(fields.IntegerField)
self.assertEqual(instance.field_to_activity([0, 1]), ["0", "1"])
def test_html_field(self):
def test_html_field(self, *_):
"""sanitizes html, the sanitizer has its own tests"""
instance = fields.HtmlField()
self.assertEqual(

View file

@ -0,0 +1,135 @@
""" testing models """
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models, settings
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class Group(TestCase):
"""some activitypub oddness ahead"""
def setUp(self):
"""Set up for tests"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.owner_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.rat = models.User.objects.create_user(
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.badger = models.User.objects.create_user(
"badger",
"badger@badger.badger",
"badgerword",
local=True,
localname="badger",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.capybara = models.User.objects.create_user(
"capybara",
"capybara@capybara.capybara",
"capybaraword",
local=True,
localname="capybara",
)
self.public_group = models.Group.objects.create(
name="Public Group",
description="Initial description",
user=self.owner_user,
privacy="public",
)
self.private_group = models.Group.objects.create(
name="Private Group",
description="Top secret",
user=self.owner_user,
privacy="direct",
)
self.followers_only_group = models.Group.objects.create(
name="Followers Group",
description="No strangers",
user=self.owner_user,
privacy="followers",
)
models.GroupMember.objects.create(group=self.private_group, user=self.badger)
models.GroupMember.objects.create(
group=self.followers_only_group, user=self.badger
)
models.GroupMember.objects.create(group=self.public_group, user=self.capybara)
def test_group_members_can_see_followers_only_groups(self, _):
"""follower-only group should not be excluded from group listings for group members viewing"""
rat_groups = models.Group.privacy_filter(self.rat).all()
badger_groups = models.Group.privacy_filter(self.badger).all()
self.assertFalse(self.followers_only_group in rat_groups)
self.assertTrue(self.followers_only_group in badger_groups)
def test_group_members_can_see_private_groups(self, _):
"""direct privacy group should not be excluded from group listings for group members viewing"""
rat_groups = models.Group.privacy_filter(self.rat).all()
badger_groups = models.Group.privacy_filter(self.badger).all()
self.assertFalse(self.private_group in rat_groups)
self.assertTrue(self.private_group in badger_groups)
def test_group_members_can_see_followers_only_lists(self, _):
"""follower-only group booklists should not be excluded from group booklist listing for group members who do not follower list owner"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
followers_list = models.List.objects.create(
name="Followers List",
curation="group",
privacy="followers",
group=self.public_group,
user=self.owner_user,
)
rat_lists = models.List.privacy_filter(self.rat).all()
badger_lists = models.List.privacy_filter(self.badger).all()
capybara_lists = models.List.privacy_filter(self.capybara).all()
self.assertFalse(followers_list in rat_lists)
self.assertFalse(followers_list in badger_lists)
self.assertTrue(followers_list in capybara_lists)
def test_group_members_can_see_private_lists(self, _):
"""private group booklists should not be excluded from group booklist listing for group members"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
private_list = models.List.objects.create(
name="Private List",
privacy="direct",
curation="group",
group=self.public_group,
user=self.owner_user,
)
rat_lists = models.List.privacy_filter(self.rat).all()
badger_lists = models.List.privacy_filter(self.badger).all()
capybara_lists = models.List.privacy_filter(self.capybara).all()
self.assertFalse(private_list in rat_lists)
self.assertFalse(private_list in badger_lists)
self.assertTrue(private_list in capybara_lists)

View file

@ -9,8 +9,8 @@ from django.test import TestCase
import responses
from bookwyrm import models
from bookwyrm.book_search import SearchResult
from bookwyrm.connectors import connector_manager
from bookwyrm.connectors.abstract_connector import SearchResult
class ImportJob(TestCase):
@ -59,9 +59,12 @@ class ImportJob(TestCase):
unknown_read_data["Exclusive Shelf"] = "read"
unknown_read_data["Date Read"] = ""
user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
job = models.ImportJob.objects.create(user=user)
self.item_1 = models.ImportItem.objects.create(
job=job, index=1, data=currently_reading_data

View file

@ -11,9 +11,12 @@ class List(TestCase):
def setUp(self):
"""look, a list"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
work = models.Work.objects.create(title="hello")
self.book = models.Edition.objects.create(title="hi", parent_work=work)

View file

@ -1,6 +1,9 @@
""" testing models """
import datetime
from unittest.mock import patch
from django.test import TestCase
from django.core.exceptions import ValidationError
from django.utils import timezone
from bookwyrm import models
@ -10,36 +13,91 @@ class ReadThrough(TestCase):
def setUp(self):
"""look, a shelf"""
self.user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
self.work = models.Work.objects.create(title="Example Work")
self.edition = models.Edition.objects.create(
title="Example Edition", parent_work=self.work
)
self.readthrough = models.ReadThrough.objects.create(
user=self.user, book=self.edition
def test_valid_date(self):
"""can't finish a book before you start it"""
start = timezone.now()
finish = start + datetime.timedelta(days=1)
# just make sure there's no errors
models.ReadThrough.objects.create(
user=self.user,
book=self.edition,
start_date=start,
finish_date=finish,
)
def test_valid_date_null_start(self):
"""can't finish a book before you start it"""
start = timezone.now()
finish = start + datetime.timedelta(days=1)
# just make sure there's no errors
models.ReadThrough.objects.create(
user=self.user,
book=self.edition,
finish_date=finish,
)
def test_valid_date_null_finish(self):
"""can't finish a book before you start it"""
start = timezone.now()
# just make sure there's no errors
models.ReadThrough.objects.create(
user=self.user,
book=self.edition,
start_date=start,
)
def test_valid_date_null(self):
"""can't finish a book before you start it"""
# just make sure there's no errors
models.ReadThrough.objects.create(
user=self.user,
book=self.edition,
)
def test_valid_date_same(self):
"""can't finish a book before you start it"""
start = timezone.now()
# just make sure there's no errors
models.ReadThrough.objects.create(
user=self.user,
book=self.edition,
start_date=start,
finish_date=start,
)
def test_progress_update(self):
"""Test progress updates"""
self.readthrough.create_update() # No-op, no progress yet
self.readthrough.progress = 10
self.readthrough.create_update()
self.readthrough.progress = 20
self.readthrough.progress_mode = models.ProgressMode.PERCENT
self.readthrough.create_update()
readthrough = models.ReadThrough.objects.create(
user=self.user, book=self.edition
)
updates = self.readthrough.progressupdate_set.order_by("created_date").all()
readthrough.create_update() # No-op, no progress yet
readthrough.progress = 10
readthrough.create_update()
readthrough.progress = 20
readthrough.progress_mode = models.ProgressMode.PERCENT
readthrough.create_update()
updates = readthrough.progressupdate_set.order_by("created_date").all()
self.assertEqual(len(updates), 2)
self.assertEqual(updates[0].progress, 10)
self.assertEqual(updates[0].mode, models.ProgressMode.PAGE)
self.assertEqual(updates[1].progress, 20)
self.assertEqual(updates[1].mode, models.ProgressMode.PERCENT)
self.readthrough.progress = -10
self.assertRaises(ValidationError, self.readthrough.clean_fields)
update = self.readthrough.create_update()
readthrough.progress = -10
self.assertRaises(ValidationError, readthrough.clean_fields)
update = readthrough.create_update()
self.assertRaises(ValidationError, update.clean_fields)

View file

@ -1,10 +1,12 @@
""" testing models """
import json
from unittest.mock import patch
from django.test import TestCase
from bookwyrm import models
@patch("bookwyrm.activitystreams.add_user_statuses_task.delay")
class Relationship(TestCase):
"""following, blocking, stuff like that"""
@ -20,25 +22,23 @@ class Relationship(TestCase):
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
self.local_user.remote_id = "http://local.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
def test_user_follows_from_request(self):
def test_user_follows_from_request(self, _):
"""convert a follow request into a follow"""
real_broadcast = models.UserFollowRequest.broadcast
def mock_broadcast(_, activity, user):
"""introspect what's being sent out"""
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity["type"], "Follow")
models.UserFollowRequest.broadcast = mock_broadcast
request = models.UserFollowRequest.objects.create(
user_subject=self.local_user, user_object=self.remote_user
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
request = models.UserFollowRequest.objects.create(
user_subject=self.local_user, user_object=self.remote_user
)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Follow")
self.assertEqual(
request.remote_id, "http://local.com/user/mouse#follows/%d" % request.id
)
@ -51,9 +51,8 @@ class Relationship(TestCase):
self.assertEqual(rel.status, "follows")
self.assertEqual(rel.user_subject, self.local_user)
self.assertEqual(rel.user_object, self.remote_user)
models.UserFollowRequest.broadcast = real_broadcast
def test_user_follows_from_request_custom_remote_id(self):
def test_user_follows_from_request_custom_remote_id(self, _):
"""store a specific remote id for a relationship provided by remote"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
request = models.UserFollowRequest.objects.create(
@ -70,36 +69,26 @@ class Relationship(TestCase):
self.assertEqual(rel.user_subject, self.local_user)
self.assertEqual(rel.user_object, self.remote_user)
def test_follow_request_activity(self):
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_follow_request_activity(self, broadcast_mock, _):
"""accept a request and make it a relationship"""
real_broadcast = models.UserFollowRequest.broadcast
def mock_broadcast(_, activity, user):
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"], self.remote_user.remote_id)
self.assertEqual(activity["type"], "Follow")
models.UserFollowRequest.broadcast = mock_broadcast
models.UserFollowRequest.objects.create(
user_subject=self.local_user,
user_object=self.remote_user,
)
models.UserFollowRequest.broadcast = real_broadcast
activity = json.loads(broadcast_mock.call_args[0][1])
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"], self.remote_user.remote_id)
self.assertEqual(activity["type"], "Follow")
def test_follow_request_accept(self):
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_follow_request_accept(self, broadcast_mock, _):
"""accept a request and make it a relationship"""
real_broadcast = models.UserFollowRequest.broadcast
def mock_broadcast(_, activity, user):
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity["type"], "Accept")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], "https://www.hi.com/")
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
models.UserFollowRequest.broadcast = mock_broadcast
self.local_user.save(
broadcast=False, update_fields=["manually_approves_followers"]
)
request = models.UserFollowRequest.objects.create(
user_subject=self.remote_user,
user_object=self.local_user,
@ -107,32 +96,34 @@ class Relationship(TestCase):
)
request.accept()
activity = json.loads(broadcast_mock.call_args[0][1])
self.assertEqual(activity["type"], "Accept")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], "https://www.hi.com/")
self.assertFalse(models.UserFollowRequest.objects.exists())
self.assertTrue(models.UserFollows.objects.exists())
rel = models.UserFollows.objects.get()
self.assertEqual(rel.user_subject, self.remote_user)
self.assertEqual(rel.user_object, self.local_user)
models.UserFollowRequest.broadcast = real_broadcast
def test_follow_request_reject(self):
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
def test_follow_request_reject(self, broadcast_mock, _):
"""accept a request and make it a relationship"""
real_broadcast = models.UserFollowRequest.broadcast
def mock_reject(_, activity, user):
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity["type"], "Reject")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], request.remote_id)
models.UserFollowRequest.broadcast = mock_reject
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
self.local_user.save(
broadcast=False, update_fields=["manually_approves_followers"]
)
request = models.UserFollowRequest.objects.create(
user_subject=self.remote_user,
user_object=self.local_user,
)
request.reject()
activity = json.loads(broadcast_mock.call_args[0][1])
self.assertEqual(activity["type"], "Reject")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], request.remote_id)
self.assertFalse(models.UserFollowRequest.objects.exists())
self.assertFalse(models.UserFollows.objects.exists())
models.UserFollowRequest.broadcast = real_broadcast

View file

@ -7,18 +7,25 @@ from bookwyrm import models, settings
# pylint: disable=unused-argument
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
class Shelf(TestCase):
"""some activitypub oddness ahead"""
def setUp(self):
"""look, a shelf"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(title="test book", parent_work=work)
def test_remote_id(self):
def test_remote_id(self, *_):
"""shelves use custom remote ids"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = models.Shelf.objects.create(
@ -27,7 +34,7 @@ class Shelf(TestCase):
expected_id = "https://%s/user/mouse/books/test-shelf" % settings.DOMAIN
self.assertEqual(shelf.get_remote_id(), expected_id)
def test_to_activity(self):
def test_to_activity(self, *_):
"""jsonify it"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = models.Shelf.objects.create(
@ -41,7 +48,7 @@ class Shelf(TestCase):
self.assertEqual(activity_json["name"], "Test Shelf")
self.assertEqual(activity_json["owner"], self.local_user.remote_id)
def test_create_update_shelf(self):
def test_create_update_shelf(self, *_):
"""create and broadcast shelf creation"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
@ -62,7 +69,7 @@ class Shelf(TestCase):
self.assertEqual(activity["object"]["name"], "arthur russel")
self.assertEqual(shelf.name, "arthur russel")
def test_shelve(self):
def test_shelve(self, *_):
"""create and broadcast shelf creation"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = models.Shelf.objects.create(

View file

@ -0,0 +1,95 @@
""" testing models """
from datetime import timedelta
from unittest.mock import patch
from django.db import IntegrityError
from django.test import TestCase
from django.utils import timezone
from bookwyrm import models, settings
class SiteModels(TestCase):
"""tests for site models"""
def setUp(self):
"""we need basic test data and mocks"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
def test_site_settings_absent(self):
"""create and load site settings"""
self.assertFalse(models.SiteSettings.objects.exists())
result = models.SiteSettings.get()
self.assertTrue(models.SiteSettings.objects.exists())
self.assertEqual(result.id, 1)
self.assertEqual(result.name, "BookWyrm")
def test_site_settings_present(self):
"""load site settings"""
models.SiteSettings.objects.create(id=1, name="Fish Town")
result = models.SiteSettings.get()
self.assertEqual(result.id, 1)
self.assertEqual(result.name, "Fish Town")
self.assertEqual(models.SiteSettings.objects.all().count(), 1)
def test_site_invite(self):
"""default invite"""
invite = models.SiteInvite.objects.create(
user=self.local_user,
)
self.assertTrue(invite.valid())
def test_site_invite_with_limit(self):
"""with use limit"""
# valid
invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=1)
self.assertTrue(invite.valid())
# invalid
invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=0)
self.assertFalse(invite.valid())
invite = models.SiteInvite.objects.create(
user=self.local_user, use_limit=1, times_used=1
)
self.assertFalse(invite.valid())
def test_site_invite_with_expiry(self):
"""with expiration date"""
date = timezone.now() + timedelta(days=1)
invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
self.assertTrue(invite.valid())
date = timezone.now() - timedelta(days=1)
invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
self.assertFalse(invite.valid())
def test_site_invite_link(self):
"""invite link generator"""
invite = models.SiteInvite.objects.create(user=self.local_user, code="hello")
self.assertEqual(invite.link, f"https://{settings.DOMAIN}/invite/hello")
def test_invite_request(self):
"""someone wants an invite"""
# normal and good
request = models.InviteRequest.objects.create(email="mouse.reeve@gmail.com")
self.assertIsNone(request.invite)
# already in use
with self.assertRaises(IntegrityError):
request = models.InviteRequest.objects.create(email="mouse@mouse.com")
def test_password_reset(self):
"""password reset token"""
token = models.PasswordReset.objects.create(user=self.local_user, code="hello")
self.assertTrue(token.valid())
self.assertEqual(token.link, f"https://{settings.DOMAIN}/password-reset/hello")

View file

@ -3,28 +3,34 @@ from unittest.mock import patch
from io import BytesIO
import pathlib
from PIL import Image
from django.http import Http404
from django.core.files.base import ContentFile
from django.db import IntegrityError
from django.contrib.auth.models import AnonymousUser
from django.test import TestCase
from django.utils import timezone
from PIL import Image
import responses
from bookwyrm import activitypub, models, settings
# pylint: disable=too-many-public-methods
# pylint: disable=line-too-long
@patch("bookwyrm.models.Status.broadcast")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class Status(TestCase):
"""lotta types of statuses"""
def setUp(self):
"""useful things for creating a status"""
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -46,25 +52,32 @@ class Status(TestCase):
image.save(output, format=image.format)
self.book.cover.save("test.jpg", ContentFile(output.getvalue()))
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
def test_status_generated_fields(self, *_):
"""setting remote id"""
status = models.Status.objects.create(content="bleh", user=self.local_user)
expected_id = "https://%s/user/mouse/status/%d" % (settings.DOMAIN, status.id)
expected_id = f"https://{settings.DOMAIN}/user/mouse/status/{status.id}"
self.assertEqual(status.remote_id, expected_id)
self.assertEqual(status.privacy, "public")
def test_replies(self, *_):
"""get a list of replies"""
parent = models.Status.objects.create(content="hi", user=self.local_user)
child = models.Status.objects.create(
parent = models.Status(content="hi", user=self.local_user)
parent.save(broadcast=False)
child = models.Status(
content="hello", reply_parent=parent, user=self.local_user
)
models.Review.objects.create(
child.save(broadcast=False)
sibling = models.Review(
content="hey", reply_parent=parent, user=self.local_user, book=self.book
)
models.Status.objects.create(
sibling.save(broadcast=False)
grandchild = models.Status(
content="hi hello", reply_parent=child, user=self.local_user
)
grandchild.save(broadcast=False)
replies = models.Status.replies(parent)
self.assertEqual(replies.count(), 2)
@ -72,6 +85,11 @@ class Status(TestCase):
# should select subclasses
self.assertIsInstance(replies.last(), models.Review)
self.assertEqual(parent.thread_id, parent.id)
self.assertEqual(child.thread_id, parent.id)
self.assertEqual(sibling.thread_id, parent.id)
self.assertEqual(grandchild.thread_id, parent.id)
def test_status_type(self, *_):
"""class name"""
self.assertEqual(models.Status().status_type, "Note")
@ -101,7 +119,7 @@ class Status(TestCase):
)
replies = parent.to_replies()
self.assertEqual(replies["id"], "%s/replies" % parent.remote_id)
self.assertEqual(replies["id"], f"{parent.remote_id}/replies")
self.assertEqual(replies["totalItems"], 2)
def test_status_to_activity(self, *_):
@ -117,15 +135,12 @@ class Status(TestCase):
def test_status_to_activity_tombstone(self, *_):
"""subclass of the base model version with a "pure" serializer"""
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
):
status = models.Status.objects.create(
content="test content",
user=self.local_user,
deleted=True,
deleted_date=timezone.now(),
)
status = models.Status.objects.create(
content="test content",
user=self.local_user,
deleted=True,
deleted_date=timezone.now(),
)
activity = status.to_activity()
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Tombstone")
@ -168,7 +183,7 @@ class Status(TestCase):
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(
activity["content"],
'mouse test content <a href="%s">"Test Edition"</a>' % self.book.remote_id,
f'mouse test content <a href="{self.book.remote_id}">"Test Edition"</a>',
)
self.assertEqual(len(activity["tag"]), 2)
self.assertEqual(activity["type"], "Note")
@ -177,7 +192,7 @@ class Status(TestCase):
self.assertEqual(activity["attachment"][0].type, "Document")
self.assertEqual(
activity["attachment"][0].url,
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
@ -202,13 +217,12 @@ class Status(TestCase):
self.assertEqual(activity["type"], "Note")
self.assertEqual(
activity["content"],
'test content<p>(comment on <a href="%s">"Test Edition"</a>)</p>'
% self.book.remote_id,
f'test content<p>(comment on <a href="{self.book.remote_id}">"Test Edition"</a>)</p>',
)
self.assertEqual(activity["attachment"][0].type, "Document")
self.assertEqual(
activity["attachment"][0].url,
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
@ -240,13 +254,12 @@ class Status(TestCase):
self.assertEqual(activity["type"], "Note")
self.assertEqual(
activity["content"],
'a sickening sense <p>-- <a href="%s">"Test Edition"</a></p>'
"test content" % self.book.remote_id,
f'a sickening sense <p>-- <a href="{self.book.remote_id}">"Test Edition"</a></p>test content',
)
self.assertEqual(activity["attachment"][0].type, "Document")
self.assertEqual(
activity["attachment"][0].url,
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
@ -281,13 +294,13 @@ class Status(TestCase):
self.assertEqual(activity["type"], "Article")
self.assertEqual(
activity["name"],
'Review of "%s" (3 stars): Review\'s name' % self.book.title,
f'Review of "{self.book.title}" (3 stars): Review\'s name',
)
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["attachment"][0].type, "Document")
self.assertEqual(
activity["attachment"][0].url,
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
@ -303,13 +316,13 @@ class Status(TestCase):
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Article")
self.assertEqual(
activity["name"], 'Review of "%s": Review name' % self.book.title
activity["name"], f'Review of "{self.book.title}": Review name'
)
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["attachment"][0].type, "Document")
self.assertEqual(
activity["attachment"][0].url,
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
@ -325,13 +338,12 @@ class Status(TestCase):
self.assertEqual(activity["type"], "Note")
self.assertEqual(
activity["content"],
'Rated <em><a href="%s">%s</a></em>: 3 stars'
% (self.book.remote_id, self.book.title),
f'rated <em><a href="{self.book.remote_id}">{self.book.title}</a></em>: 3 stars',
)
self.assertEqual(activity["attachment"][0].type, "Document")
self.assertEqual(
activity["attachment"][0].url,
"https://%s%s" % (settings.MEDIA_FULL_URL, self.book.cover.url),
f"https://{settings.MEDIA_FULL_URL}{self.book.cover.url}",
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
@ -453,3 +465,60 @@ class Status(TestCase):
responses.add(responses.GET, "http://fish.com/nothing", status=404)
self.assertTrue(models.Status.ignore_activity(activity))
def test_raise_visible_to_user_public(self, *_):
"""privacy settings"""
status = models.Status.objects.create(
content="bleh", user=self.local_user, privacy="public"
)
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
self.assertIsNone(status.raise_visible_to_user(self.local_user))
self.assertIsNone(status.raise_visible_to_user(self.anonymous_user))
def test_raise_visible_to_user_unlisted(self, *_):
"""privacy settings"""
status = models.Status.objects.create(
content="bleh", user=self.local_user, privacy="unlisted"
)
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
self.assertIsNone(status.raise_visible_to_user(self.local_user))
self.assertIsNone(status.raise_visible_to_user(self.anonymous_user))
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
def test_raise_visible_to_user_followers(self, *_):
"""privacy settings"""
status = models.Status.objects.create(
content="bleh", user=self.local_user, privacy="followers"
)
status.raise_visible_to_user(self.local_user)
with self.assertRaises(Http404):
status.raise_visible_to_user(self.remote_user)
with self.assertRaises(Http404):
status.raise_visible_to_user(self.anonymous_user)
self.local_user.followers.add(self.remote_user)
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
def test_raise_visible_to_user_followers_mentioned(self, *_):
"""privacy settings"""
status = models.Status.objects.create(
content="bleh", user=self.local_user, privacy="followers"
)
status.mention_users.set([self.remote_user])
self.assertIsNone(status.raise_visible_to_user(self.remote_user))
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
def test_raise_visible_to_user_direct(self, *_):
"""privacy settings"""
status = models.Status.objects.create(
content="bleh", user=self.local_user, privacy="direct"
)
status.raise_visible_to_user(self.local_user)
with self.assertRaises(Http404):
status.raise_visible_to_user(self.remote_user)
with self.assertRaises(Http404):
status.raise_visible_to_user(self.anonymous_user)
# mentioned user
status.mention_users.set([self.remote_user])
self.assertIsNone(status.raise_visible_to_user(self.remote_user))

View file

@ -5,31 +5,37 @@ from django.test import TestCase
import responses
from bookwyrm import models
from bookwyrm.settings import DOMAIN
from bookwyrm.settings import USE_HTTPS, DOMAIN
# pylint: disable=missing-class-docstring
# pylint: disable=missing-function-docstring
class User(TestCase):
protocol = "https://" if USE_HTTPS else "http://"
def setUp(self):
self.user = models.User.objects.create_user(
"mouse@%s" % DOMAIN,
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
name="hi",
bookwyrm_user=False,
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"mouse@%s" % DOMAIN,
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
name="hi",
bookwyrm_user=False,
)
def test_computed_fields(self):
"""username instead of id here"""
expected_id = "https://%s/user/mouse" % DOMAIN
expected_id = f"{self.protocol}{DOMAIN}/user/mouse"
self.assertEqual(self.user.remote_id, expected_id)
self.assertEqual(self.user.username, "mouse@%s" % DOMAIN)
self.assertEqual(self.user.username, f"mouse@{DOMAIN}")
self.assertEqual(self.user.localname, "mouse")
self.assertEqual(self.user.shared_inbox, "https://%s/inbox" % DOMAIN)
self.assertEqual(self.user.inbox, "%s/inbox" % expected_id)
self.assertEqual(self.user.outbox, "%s/outbox" % expected_id)
self.assertEqual(self.user.shared_inbox, f"{self.protocol}{DOMAIN}/inbox")
self.assertEqual(self.user.inbox, f"{expected_id}/inbox")
self.assertEqual(self.user.outbox, f"{expected_id}/outbox")
self.assertEqual(self.user.followers_url, f"{expected_id}/followers")
self.assertIsNotNone(self.user.key_pair.private_key)
self.assertIsNotNone(self.user.key_pair.public_key)
@ -154,7 +160,8 @@ class User(TestCase):
self.assertIsNone(server.application_type)
self.assertIsNone(server.application_version)
def test_delete_user(self):
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_delete_user(self, _):
"""deactivate a user"""
self.assertTrue(self.user.is_active)
with patch(

View file

@ -0,0 +1,118 @@
""" test searching for books """
import datetime
from django.test import TestCase
from django.utils import timezone
from bookwyrm import book_search, models
from bookwyrm.connectors.abstract_connector import AbstractMinimalConnector
class BookSearch(TestCase):
"""look for some books"""
def setUp(self):
"""we need basic test data and mocks"""
self.work = models.Work.objects.create(title="Example Work")
self.first_edition = models.Edition.objects.create(
title="Example Edition",
parent_work=self.work,
isbn_10="0000000000",
physical_format="Paperback",
published_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc),
)
self.second_edition = models.Edition.objects.create(
title="Another Edition",
parent_work=self.work,
isbn_10="1111111111",
openlibrary_key="hello",
)
def test_search(self):
"""search for a book in the db"""
# title/author
results = book_search.search("Example")
self.assertEqual(len(results), 1)
self.assertEqual(results[0], self.first_edition)
# isbn
results = book_search.search("0000000000")
self.assertEqual(len(results), 1)
self.assertEqual(results[0], self.first_edition)
# identifier
results = book_search.search("hello")
self.assertEqual(len(results), 1)
self.assertEqual(results[0], self.second_edition)
def test_isbn_search(self):
"""test isbn search"""
results = book_search.isbn_search("0000000000")
self.assertEqual(len(results), 1)
self.assertEqual(results[0], self.first_edition)
def test_search_identifiers(self):
"""search by unique identifiers"""
results = book_search.search_identifiers("hello")
self.assertEqual(len(results), 1)
self.assertEqual(results[0], self.second_edition)
def test_search_title_author(self):
"""search by unique identifiers"""
results = book_search.search_title_author("Another", min_confidence=0)
self.assertEqual(len(results), 1)
self.assertEqual(results[0], self.second_edition)
def test_format_search_result(self):
"""format a search result"""
result = book_search.format_search_result(self.first_edition)
self.assertEqual(result["title"], "Example Edition")
self.assertEqual(result["key"], self.first_edition.remote_id)
self.assertEqual(result["year"], 2019)
result = book_search.format_search_result(self.second_edition)
self.assertEqual(result["title"], "Another Edition")
self.assertEqual(result["key"], self.second_edition.remote_id)
self.assertIsNone(result["year"])
def test_search_result(self):
"""a class that stores info about a search result"""
models.Connector.objects.create(
identifier="example.com",
connector_file="openlibrary",
base_url="https://example.com",
books_url="https://example.com/books",
covers_url="https://example.com/covers",
search_url="https://example.com/search?q=",
isbn_search_url="https://example.com/isbn?q=",
)
class TestConnector(AbstractMinimalConnector):
"""nothing added here"""
def format_search_result(self, search_result):
return search_result
def get_or_create_book(self, remote_id):
pass
def parse_search_data(self, data):
return data
def format_isbn_search_result(self, search_result):
return search_result
def parse_isbn_search_data(self, data):
return data
test_connector = TestConnector("example.com")
result = book_search.SearchResult(
title="Title",
key="https://example.com/book/1",
author="Author Name",
year="1850",
connector=test_connector,
)
# there's really not much to test here, it's just a dataclass
self.assertEqual(result.confidence, 1)
self.assertEqual(result.title, "Title")

View file

@ -14,13 +14,16 @@ class Emailing(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_invite_email(self, email_mock):

View file

@ -1,5 +1,6 @@
""" test generating preview images """
import pathlib
from unittest.mock import patch
from PIL import Image
from django.test import TestCase
@ -8,7 +9,6 @@ from django.core.files.uploadedfile import SimpleUploadedFile
from django.db.models.fields.files import ImageFieldFile
from bookwyrm import models, settings
from bookwyrm.preview_images import (
generate_site_preview_image_task,
generate_edition_preview_image_task,
@ -20,6 +20,7 @@ from bookwyrm.preview_images import (
# pylint: disable=unused-argument
# pylint: disable=missing-function-docstring
# pylint: disable=consider-using-with
class PreviewImages(TestCase):
"""every response to a get request, html or json"""
@ -29,18 +30,21 @@ class PreviewImages(TestCase):
avatar_file = pathlib.Path(__file__).parent.joinpath(
"../static/images/no_cover.jpg"
)
self.local_user = models.User.objects.create_user(
"possum@local.com",
"possum@possum.possum",
"password",
local=True,
localname="possum",
avatar=SimpleUploadedFile(
avatar_file,
open(avatar_file, "rb").read(),
content_type="image/jpeg",
),
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"possum@local.com",
"possum@possum.possum",
"password",
local=True,
localname="possum",
avatar=SimpleUploadedFile(
avatar_file,
open(avatar_file, "rb").read(),
content_type="image/jpeg",
),
)
self.work = models.Work.objects.create(title="Test Work")
self.edition = models.Edition.objects.create(
@ -117,3 +121,11 @@ class PreviewImages(TestCase):
self.assertEqual(
self.local_user.preview_image.height, settings.PREVIEW_IMG_HEIGHT
)
def test_generate_user_preview_images_task(self, *args, **kwargs):
"""test task's external calls"""
with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock:
generate_user_preview_image_task(self.local_user.id)
args = generate_mock.call_args.kwargs
self.assertEqual(args["texts"]["text_one"], "possum")
self.assertEqual(args["texts"]["text_three"], f"@possum@{settings.DOMAIN}")

View file

@ -37,19 +37,22 @@ class Signature(TestCase):
def setUp(self):
"""create users and test data"""
self.mouse = models.User.objects.create_user(
"mouse@%s" % DOMAIN,
"mouse@example.com",
"",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@%s" % DOMAIN, "rat@example.com", "", local=True, localname="rat"
)
self.cat = models.User.objects.create_user(
"cat@%s" % DOMAIN, "cat@example.com", "", local=True, localname="cat"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.mouse = models.User.objects.create_user(
"mouse@%s" % DOMAIN,
"mouse@example.com",
"",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@%s" % DOMAIN, "rat@example.com", "", local=True, localname="rat"
)
self.cat = models.User.objects.create_user(
"cat@%s" % DOMAIN, "cat@example.com", "", local=True, localname="cat"
)
private_key, public_key = create_key_pair()

View file

@ -0,0 +1,177 @@
""" testing user follow suggestions """
from collections import namedtuple
from unittest.mock import patch
from django.db.models import Q
from django.test import TestCase
from bookwyrm import models
from bookwyrm.suggested_users import suggested_users, get_annotated_users
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.suggested_users.rerank_user_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")
class SuggestedUsers(TestCase):
"""using redis to build activity streams"""
def setUp(self):
"""use a test csv"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse", "mouse@mouse.mouse", "password", local=True, localname="mouse"
)
def test_get_rank(self, *_):
"""a float that reflects both the mutuals count and shared books"""
Mock = namedtuple("AnnotatedUserMock", ("mutuals", "shared_books"))
annotated_user_mock = Mock(3, 27)
rank = suggested_users.get_rank(annotated_user_mock)
self.assertEqual(rank, 3) # 3.9642857142857144)
def test_store_id(self, *_):
"""redis key generation"""
self.assertEqual(
suggested_users.store_id(self.local_user),
"{:d}-suggestions".format(self.local_user.id),
)
def test_get_counts_from_rank(self, *_):
"""reverse the rank computation to get the mutuals and shared books counts"""
counts = suggested_users.get_counts_from_rank(3.9642857142857144)
self.assertEqual(counts["mutuals"], 3)
# self.assertEqual(counts["shared_books"], 27)
def test_get_objects_for_store(self, *_):
"""list of people to follow for a given user"""
mutual_user = models.User.objects.create_user(
"rat", "rat@local.rat", "password", local=True, localname="rat"
)
suggestable_user = models.User.objects.create_user(
"nutria",
"nutria@nutria.nutria",
"password",
local=True,
localname="nutria",
discoverable=True,
)
# you follow rat
mutual_user.followers.add(self.local_user)
# rat follows the suggested user
suggestable_user.followers.add(mutual_user)
results = suggested_users.get_objects_for_store(
"{:d}-suggestions".format(self.local_user.id)
)
self.assertEqual(results.count(), 1)
match = results.first()
self.assertEqual(match.id, suggestable_user.id)
self.assertEqual(match.mutuals, 1)
def test_create_user_signal(self, *_):
"""build suggestions for new users"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay") as mock:
models.User.objects.create_user(
"nutria", "nutria@nu.tria", "password", local=True, localname="nutria"
)
self.assertEqual(mock.call_count, 1)
def test_get_annotated_users(self, *_):
"""list of people you might know"""
user_1 = models.User.objects.create_user(
"nutria@local.com",
"nutria@nutria.com",
"nutriaword",
local=True,
localname="nutria",
discoverable=True,
)
user_2 = models.User.objects.create_user(
"fish@local.com",
"fish@fish.com",
"fishword",
local=True,
localname="fish",
)
work = models.Work.objects.create(title="Test Work")
book = models.Edition.objects.create(
title="Test Book",
remote_id="https://example.com/book/1",
parent_work=work,
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
# 1 shared follow
self.local_user.following.add(user_2)
user_1.followers.add(user_2)
# 1 shared book
models.ShelfBook.objects.create(
user=self.local_user,
book=book,
shelf=self.local_user.shelf_set.first(),
)
models.ShelfBook.objects.create(
user=user_1, book=book, shelf=user_1.shelf_set.first()
)
result = get_annotated_users(self.local_user)
self.assertEqual(result.count(), 1)
self.assertTrue(user_1 in result)
self.assertFalse(user_2 in result)
user_1_annotated = result.get(id=user_1.id)
self.assertEqual(user_1_annotated.mutuals, 1)
# self.assertEqual(user_1_annotated.shared_books, 1)
def test_get_annotated_users_counts(self, *_):
"""correct counting for multiple shared attributed"""
user_1 = models.User.objects.create_user(
"nutria@local.com",
"nutria@nutria.com",
"nutriaword",
local=True,
localname="nutria",
discoverable=True,
)
for i in range(3):
user = models.User.objects.create_user(
"{:d}@local.com".format(i),
"{:d}@nutria.com".format(i),
"password",
local=True,
localname=i,
)
user.following.add(user_1)
user.followers.add(self.local_user)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
for i in range(3):
book = models.Edition.objects.create(
title=i,
parent_work=models.Work.objects.create(title=i),
)
models.ShelfBook.objects.create(
user=self.local_user,
book=book,
shelf=self.local_user.shelf_set.first(),
)
models.ShelfBook.objects.create(
user=user_1, book=book, shelf=user_1.shelf_set.first()
)
result = get_annotated_users(
self.local_user,
~Q(id=self.local_user.id),
~Q(followers=self.local_user),
)
user_1_annotated = result.get(id=user_1.id)
self.assertEqual(user_1_annotated.mutuals, 3)

View file

@ -15,20 +15,23 @@ from bookwyrm.templatetags import (
)
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class TemplateTags(TestCase):
"""lotta different things here"""
def setUp(self):
"""create some filler objects"""
self.user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.mouse",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -72,15 +75,12 @@ class TemplateTags(TestCase):
second_child = models.Status.objects.create(
reply_parent=parent, user=self.user, content="hi"
)
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
):
third_child = models.Status.objects.create(
reply_parent=parent,
user=self.user,
deleted=True,
deleted_date=timezone.now(),
)
third_child = models.Status.objects.create(
reply_parent=parent,
user=self.user,
deleted=True,
deleted_date=timezone.now(),
)
replies = status_display.get_replies(parent)
self.assertEqual(len(replies), 2)
@ -174,3 +174,10 @@ class TemplateTags(TestCase):
result = bookwyrm_tags.related_status(notification)
self.assertIsInstance(result, models.Status)
def test_get_next_shelf(self, *_):
"""self progress helper"""
self.assertEqual(bookwyrm_tags.get_next_shelf("to-read"), "reading")
self.assertEqual(bookwyrm_tags.get_next_shelf("reading"), "read")
self.assertEqual(bookwyrm_tags.get_next_shelf("read"), "complete")
self.assertEqual(bookwyrm_tags.get_next_shelf("blooooga"), "to-read")

View file

@ -0,0 +1,21 @@
""" html validation on rendered templates """
from tidylib import tidy_document
def validate_html(html):
"""run tidy on html"""
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
# idk how else to filter out these unescape amp errs
errors = "\n".join(
e
for e in errors.split("\n")
if "&book" not in e and "id and name attribute" not in e
)
if errors:
raise Exception(errors)

View file

@ -0,0 +1 @@
from . import *

View file

@ -1,4 +1,5 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -12,13 +13,16 @@ class AnnouncementViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()

View file

@ -0,0 +1,39 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class DashboardViews(TestCase):
"""every response to a get request, html or json"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_dashboard(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Dashboard.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)

View file

@ -0,0 +1,75 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class EmailBlocklistViews(TestCase):
"""every response to a get request, html or json"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_blocklist_page_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.EmailBlocklist.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_blocklist_page_post(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.EmailBlocklist.as_view()
request = self.factory.post("", {"domain": "gmail.com"})
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertTrue(
models.EmailBlocklist.objects.filter(domain="gmail.com").exists()
)
def test_blocklist_page_delete(self):
"""there are so many views, this just makes sure it LOADS"""
domain = models.EmailBlocklist.objects.create(domain="gmail.com")
view = views.EmailBlocklist.as_view()
request = self.factory.post("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request, domain_id=domain.id)
self.assertEqual(result.status_code, 302)
self.assertFalse(
models.EmailBlocklist.objects.filter(domain="gmail.com").exists()
)

View file

@ -1,12 +1,14 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
class FederationViews(TestCase):
@ -15,13 +17,16 @@ class FederationViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -43,10 +48,10 @@ class FederationViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_server_page(self):
def test_instance_page(self):
"""there are so many views, this just makes sure it LOADS"""
server = models.FederatedServer.objects.create(server_name="hi.there.com")
view = views.FederatedServer.as_view()
@ -56,7 +61,7 @@ class FederationViews(TestCase):
result = view(request, server.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_server_page_block(self):
@ -68,16 +73,18 @@ class FederationViews(TestCase):
identifier="hi.there.com",
)
self.remote_user.federated_server = server
self.remote_user.save()
self.remote_user.save(update_fields=["federated_server"])
self.assertEqual(server.status, "federated")
view = views.federation.block_server
view = views.block_server
request = self.factory.post("")
request.user = self.local_user
request.user.is_superuser = True
view(request, server.id)
with patch("bookwyrm.suggested_users.bulk_remove_instance_task.delay") as mock:
view(request, server.id)
self.assertEqual(mock.call_count, 1)
server.refresh_from_db()
self.remote_user.refresh_from_db()
@ -107,13 +114,19 @@ class FederationViews(TestCase):
self.remote_user.federated_server = server
self.remote_user.is_active = False
self.remote_user.deactivation_reason = "domain_block"
self.remote_user.save()
self.remote_user.save(
update_fields=["federated_server", "is_active", "deactivation_reason"]
)
request = self.factory.post("")
request.user = self.local_user
request.user.is_superuser = True
views.federation.unblock_server(request, server.id)
with patch("bookwyrm.suggested_users.bulk_add_instance_task.delay") as mock:
views.unblock_server(request, server.id)
self.assertEqual(mock.call_count, 1)
self.assertEqual(mock.call_args[0][0], server.id)
server.refresh_from_db()
self.remote_user.refresh_from_db()
self.assertEqual(server.status, "federated")
@ -137,7 +150,7 @@ class FederationViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_add_view_post_create(self):
@ -158,18 +171,19 @@ class FederationViews(TestCase):
self.assertEqual(server.application_type, "coolsoft")
self.assertEqual(server.status, "blocked")
# pylint: disable=consider-using-with
def test_import_blocklist(self):
"""load a json file with a list of servers to block"""
server = models.FederatedServer.objects.create(server_name="hi.there.com")
self.remote_user.federated_server = server
self.remote_user.save()
self.remote_user.save(update_fields=["federated_server"])
data = [
{"instance": "server.name", "url": "https://explanation.url"}, # new server
{"instance": "hi.there.com", "url": "https://explanation.url"}, # existing
{"a": "b"}, # invalid
]
json.dump(data, open("file.json", "w"))
json.dump(data, open("file.json", "w")) # pylint: disable=unspecified-encoding
view = views.ImportServerBlocklist.as_view()
request = self.factory.post(

View file

@ -0,0 +1,41 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class IPBlocklistViews(TestCase):
"""every response to a get request, html or json"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_blocklist_page_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.IPBlocklist.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)

View file

@ -1,9 +1,13 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
class ReportViews(TestCase):
@ -12,20 +16,23 @@ class ReportViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@mouse.mouse",
"password",
local=True,
localname="rat",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@mouse.mouse",
"password",
local=True,
localname="rat",
)
models.SiteSettings.objects.create()
def test_reports_page(self):
@ -37,7 +44,7 @@ class ReportViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_reports_page_with_data(self):
@ -50,7 +57,7 @@ class ReportViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_report_page(self):
@ -64,7 +71,7 @@ class ReportViews(TestCase):
result = view(request, report.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_report_comment(self):
@ -114,7 +121,10 @@ class ReportViews(TestCase):
report.refresh_from_db()
self.assertFalse(report.resolved)
def test_suspend_user(self):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_suspend_user(self, *_):
"""toggle whether a user is able to log in"""
self.assertTrue(self.rat.is_active)
request = self.factory.post("")
@ -127,6 +137,26 @@ class ReportViews(TestCase):
self.assertFalse(self.rat.is_active)
# re-activate
views.suspend_user(request, self.rat.id)
views.unsuspend_user(request, self.rat.id)
self.rat.refresh_from_db()
self.assertTrue(self.rat.is_active)
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_delete_user(self, *_):
"""toggle whether a user is able to log in"""
self.assertTrue(self.rat.is_active)
request = self.factory.post("", {"password": "password"})
request.user = self.local_user
request.user.is_superuser = True
# de-activate
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.moderator_delete_user(request, self.rat.id)
self.assertEqual(mock.call_count, 1)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.rat.refresh_from_db()
self.assertFalse(self.rat.is_active)
self.assertEqual(self.rat.deactivation_reason, "moderator_deletion")

View file

@ -1,11 +1,13 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import Group
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class UserAdminViews(TestCase):
@ -14,13 +16,16 @@ class UserAdminViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_user_admin_list_page(self):
@ -31,7 +36,7 @@ class UserAdminViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_user_admin_page(self):
@ -44,10 +49,13 @@ class UserAdminViews(TestCase):
result = view(request, self.local_user.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_user_admin_page_post(self):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_user_admin_page_post(self, *_):
"""set the user's group"""
group = Group.objects.create(name="editor")
self.assertEqual(
@ -63,7 +71,7 @@ class UserAdminViews(TestCase):
result = view(request, self.local_user.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(
list(self.local_user.groups.values_list("name", flat=True)), ["editor"]

View file

@ -0,0 +1 @@
from . import *

View file

@ -0,0 +1,228 @@
""" test for app action functionality """
from io import BytesIO
import pathlib
from unittest.mock import patch
from PIL import Image
import responses
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import timezone
from bookwyrm import forms, models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.tests.validate_html import validate_html
class BookViews(TestCase):
"""books books books"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.group = Group.objects.create(name="editor")
self.group.permissions.add(
Permission.objects.create(
name="edit_book",
codename="edit_book",
content_type=ContentType.objects.get_for_model(models.User),
).id
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
models.SiteSettings.objects.create()
def test_book_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Book.as_view()
models.ReadThrough.objects.create(
user=self.local_user,
book=self.book,
start_date=timezone.now(),
)
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.book.id)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.book.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_book_page_statuses(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Book.as_view()
review = models.Review.objects.create(
user=self.local_user,
book=self.book,
content="hi",
)
comment = models.Comment.objects.create(
user=self.local_user,
book=self.book,
content="hi",
)
quote = models.Quotation.objects.create(
user=self.local_user,
book=self.book,
content="hi",
quote="wow",
)
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.book.id, user_statuses="review")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(result.context_data["statuses"].object_list[0], review)
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.book.id, user_statuses="comment")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(result.context_data["statuses"].object_list[0], comment)
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.book.id, user_statuses="quotation")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(result.context_data["statuses"].object_list[0], quote)
def test_book_page_invalid_id(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Book.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = False
with self.assertRaises(Http404):
view(request, 0)
def test_book_page_work_id(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Book.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.books.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(result.context_data["book"], self.book)
def test_upload_cover_file(self):
"""add a cover via file upload"""
self.assertFalse(self.book.cover)
image_file = pathlib.Path(__file__).parent.joinpath(
"../../../static/images/default_avi.jpg"
)
form = forms.CoverForm(instance=self.book)
# pylint: disable=consider-using-with
form.data["cover"] = SimpleUploadedFile(
image_file, open(image_file, "rb").read(), content_type="image/jpeg"
)
request = self.factory.post("", form.data)
request.user = self.local_user
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
views.upload_cover(request, self.book.id)
self.assertEqual(delay_mock.call_count, 1)
self.book.refresh_from_db()
self.assertTrue(self.book.cover)
@responses.activate
def test_upload_cover_url(self):
"""add a cover via url"""
self.assertFalse(self.book.cover)
form = forms.CoverForm(instance=self.book)
form.data["cover-url"] = _setup_cover_url()
request = self.factory.post("", form.data)
request.user = self.local_user
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
views.upload_cover(request, self.book.id)
self.assertEqual(delay_mock.call_count, 1)
self.book.refresh_from_db()
self.assertTrue(self.book.cover)
def test_add_description(self):
"""add a book description"""
self.local_user.groups.add(self.group)
request = self.factory.post("", {"description": "new description hi"})
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.add_description(request, self.book.id)
self.book.refresh_from_db()
self.assertEqual(self.book.description, "new description hi")
self.assertEqual(self.book.last_edited_by, self.local_user)
def _setup_cover_url():
"""creates cover url mock"""
cover_url = "http://example.com"
image_file = pathlib.Path(__file__).parent.joinpath(
"../../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
image.save(output, format=image.format)
responses.add(
responses.GET,
cover_url,
body=output.getvalue(),
status=200,
)
return cover_url

View file

@ -1,36 +1,35 @@
""" test for app action functionality """
from io import BytesIO
import pathlib
from unittest.mock import patch
from PIL import Image
import responses
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.tests.validate_html import validate_html
from bookwyrm.tests.views.books.test_book import _setup_cover_url
class BookViews(TestCase):
class EditBookViews(TestCase):
"""books books books"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.group = Group.objects.create(name="editor")
self.group.permissions.add(
Permission.objects.create(
@ -48,24 +47,6 @@ class BookViews(TestCase):
models.SiteSettings.objects.create()
def test_book_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Book.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.book.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.books.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.book.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_edit_book_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.EditBook.as_view()
@ -74,7 +55,18 @@ class BookViews(TestCase):
request.user.is_superuser = True
result = view(request, self.book.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_book_create_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.EditBook.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_book(self):
@ -105,7 +97,7 @@ class BookViews(TestCase):
request.user = self.local_user
result = view(request, self.book.id)
result.render()
validate_html(result.render())
# the changes haven't been saved yet
self.book.refresh_from_db()
@ -200,92 +192,17 @@ class BookViews(TestCase):
self.assertEqual(book.authors.first().name, "Sappho")
self.assertEqual(book.authors.first(), book.parent_work.authors.first())
def test_switch_edition(self):
"""updates user's relationships to a book"""
work = models.Work.objects.create(title="test work")
edition1 = models.Edition.objects.create(title="first ed", parent_work=work)
edition2 = models.Edition.objects.create(title="second ed", parent_work=work)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
models.ShelfBook.objects.create(
book=edition1,
user=self.local_user,
shelf=shelf,
)
models.ReadThrough.objects.create(user=self.local_user, book=edition1)
self.assertEqual(models.ShelfBook.objects.get().book, edition1)
self.assertEqual(models.ReadThrough.objects.get().book, edition1)
request = self.factory.post("", {"edition": edition2.id})
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.switch_edition(request)
self.assertEqual(models.ShelfBook.objects.get().book, edition2)
self.assertEqual(models.ReadThrough.objects.get().book, edition2)
def test_editions_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Editions.as_view()
request = self.factory.get("")
with patch("bookwyrm.views.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
request = self.factory.get("")
with patch("bookwyrm.views.books.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.work.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_upload_cover_file(self):
"""add a cover via file upload"""
self.assertFalse(self.book.cover)
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/default_avi.jpg"
)
form = forms.CoverForm(instance=self.book)
form.data["cover"] = SimpleUploadedFile(
image_file, open(image_file, "rb").read(), content_type="image/jpeg"
)
request = self.factory.post("", form.data)
request.user = self.local_user
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
views.upload_cover(request, self.book.id)
self.assertEqual(delay_mock.call_count, 1)
self.book.refresh_from_db()
self.assertTrue(self.book.cover)
@responses.activate
def test_upload_cover_url(self):
"""add a cover via url"""
def test_create_book_upload_cover_url(self):
"""create an entirely new book and work with cover url"""
self.assertFalse(self.book.cover)
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
image.save(output, format=image.format)
responses.add(
responses.GET,
"http://example.com",
body=output.getvalue(),
status=200,
)
form = forms.CoverForm(instance=self.book)
form.data["cover-url"] = "http://example.com"
self.local_user.groups.add(self.group)
cover_url = _setup_cover_url()
form = forms.EditionForm()
form.data["title"] = "New Title"
form.data["last_edited_by"] = self.local_user.id
form.data["cover-url"] = cover_url
request = self.factory.post("", form.data)
request.user = self.local_user

View file

@ -0,0 +1,131 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.tests.validate_html import validate_html
class BookViews(TestCase):
"""books books books"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
physical_format="paperback",
)
models.SiteSettings.objects.create()
def test_editions_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Editions.as_view()
request = self.factory.get("")
with patch("bookwyrm.views.books.editions.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertTrue("paperback" in result.context_data["formats"])
def test_editions_page_filtered(self):
"""editions view with filters"""
models.Edition.objects.create(
title="Fish",
physical_format="okay",
parent_work=self.work,
)
view = views.Editions.as_view()
request = self.factory.get("")
with patch("bookwyrm.views.books.editions.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(len(result.context_data["editions"].object_list), 2)
self.assertEqual(len(result.context_data["formats"]), 2)
self.assertTrue("paperback" in result.context_data["formats"])
self.assertTrue("okay" in result.context_data["formats"])
request = self.factory.get("", {"q": "fish"})
with patch("bookwyrm.views.books.editions.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(len(result.context_data["editions"].object_list), 1)
request = self.factory.get("", {"q": "okay"})
with patch("bookwyrm.views.books.editions.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(len(result.context_data["editions"].object_list), 1)
request = self.factory.get("", {"format": "okay"})
with patch("bookwyrm.views.books.editions.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.work.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(len(result.context_data["editions"].object_list), 1)
def test_editions_page_api(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Editions.as_view()
request = self.factory.get("")
with patch("bookwyrm.views.books.editions.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.work.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
def test_switch_edition(self, *_):
"""updates user's relationships to a book"""
work = models.Work.objects.create(title="test work")
edition1 = models.Edition.objects.create(title="first ed", parent_work=work)
edition2 = models.Edition.objects.create(title="second ed", parent_work=work)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
models.ShelfBook.objects.create(
book=edition1,
user=self.local_user,
shelf=shelf,
)
models.ReadThrough.objects.create(user=self.local_user, book=edition1)
self.assertEqual(models.ShelfBook.objects.get().book, edition1)
self.assertEqual(models.ReadThrough.objects.get().book, edition1)
request = self.factory.post("", {"edition": edition2.id})
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.switch_edition(request)
self.assertEqual(models.ShelfBook.objects.get().book, edition2)
self.assertEqual(models.ReadThrough.objects.get().book, edition2)

View file

@ -3,6 +3,7 @@ import json
import pathlib
from unittest.mock import patch
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseNotAllowed, HttpResponseNotFound
from django.test import TestCase, Client
from django.test.client import RequestFactory
@ -19,15 +20,18 @@ class Inbox(TestCase):
self.client = Client()
self.factory = RequestFactory()
local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
local_user.remote_id = "https://example.com/user/mouse"
local_user.save(broadcast=False)
local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -127,24 +131,27 @@ class Inbox(TestCase):
"",
HTTP_USER_AGENT="http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)",
)
self.assertFalse(views.inbox.is_blocked_user_agent(request))
self.assertIsNone(views.inbox.raise_is_blocked_user_agent(request))
models.FederatedServer.objects.create(
server_name="mastodon.social", status="blocked"
)
self.assertTrue(views.inbox.is_blocked_user_agent(request))
with self.assertRaises(PermissionDenied):
views.inbox.raise_is_blocked_user_agent(request)
def test_is_blocked_activity(self):
"""check for blocked servers"""
activity = {"actor": "https://mastodon.social/user/whaatever/else"}
self.assertFalse(views.inbox.is_blocked_activity(activity))
self.assertIsNone(views.inbox.raise_is_blocked_activity(activity))
models.FederatedServer.objects.create(
server_name="mastodon.social", status="blocked"
)
self.assertTrue(views.inbox.is_blocked_activity(activity))
with self.assertRaises(PermissionDenied):
views.inbox.raise_is_blocked_activity(activity)
def test_create_by_deactivated_user(self):
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_create_by_deactivated_user(self, _):
"""don't let deactivated users post"""
self.remote_user.delete(broadcast=False)
self.assertTrue(self.remote_user.deleted)
@ -153,11 +160,11 @@ class Inbox(TestCase):
activity = self.create_json
activity["actor"] = self.remote_user.remote_id
activity["object"] = status_data
activity["type"] = "Create"
with patch("bookwyrm.views.inbox.has_valid_signature") as mock_valid:
mock_valid.return_value = True
result = self.client.post(
"/inbox", json.dumps(activity), content_type="application/json"
)
self.assertEqual(result.status_code, 403)
response = self.client.post(
"/inbox",
json.dumps(activity),
content_type="application/json",
)
self.assertEqual(response.status_code, 403)

View file

@ -13,15 +13,18 @@ class InboxAdd(TestCase):
def setUp(self):
"""basic user and book data"""
local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
local_user.remote_id = "https://example.com/user/mouse"
local_user.save(broadcast=False)
local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",

View file

@ -13,15 +13,18 @@ class InboxActivities(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -34,7 +37,7 @@ class InboxActivities(TestCase):
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
self.status = models.Status.objects.create(
user=self.local_user,
content="Test status",
@ -52,9 +55,8 @@ class InboxActivities(TestCase):
models.SiteSettings.objects.create()
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
def test_boost(self, redis_mock, _):
@patch("bookwyrm.activitystreams.handle_boost_task.delay")
def test_boost(self, _):
"""boost a status"""
self.assertEqual(models.Notification.objects.count(), 0)
activity = {
@ -70,9 +72,6 @@ class InboxActivities(TestCase):
discarder.return_value = False
views.inbox.activity_task(activity)
# boost added to redis activitystreams
self.assertTrue(redis_mock.called)
# boost created of correct status
boost = models.Boost.objects.get()
self.assertEqual(boost.boosted_status, self.status)
@ -83,9 +82,8 @@ class InboxActivities(TestCase):
self.assertEqual(notification.related_status, self.status)
@responses.activate
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
def test_boost_remote_status(self, redis_mock, _):
@patch("bookwyrm.activitystreams.handle_boost_task.delay")
def test_boost_remote_status(self, _):
"""boost a status from a remote server"""
work = models.Work.objects.create(title="work title")
book = models.Edition.objects.create(
@ -126,7 +124,6 @@ class InboxActivities(TestCase):
with patch("bookwyrm.models.status.Status.ignore_activity") as discarder:
discarder.return_value = False
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
boost = models.Boost.objects.get()
self.assertEqual(boost.boosted_status.remote_id, "https://remote.com/status/1")
@ -140,7 +137,7 @@ class InboxActivities(TestCase):
content="hi",
user=self.remote_user,
)
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status.save(broadcast=False)
activity = {
"type": "Announce",
@ -157,8 +154,9 @@ class InboxActivities(TestCase):
views.inbox.activity_task(activity)
self.assertEqual(models.Boost.objects.count(), 0)
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.activitystreams.handle_boost_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
def test_unboost(self, *_):
"""undo a boost"""
boost = models.Boost.objects.create(

View file

@ -12,15 +12,18 @@ class InboxBlock(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -53,7 +56,7 @@ class InboxBlock(TestCase):
}
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_user_statuses"
"bookwyrm.activitystreams.remove_user_statuses_task.delay"
) as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
@ -66,7 +69,8 @@ class InboxBlock(TestCase):
self.assertFalse(models.UserFollows.objects.exists())
self.assertFalse(models.UserFollowRequest.objects.exists())
def test_handle_unblock(self):
@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay")
def test_handle_unblock(self, _):
"""unblock a user"""
self.remote_user.blocks.add(self.local_user)
@ -91,7 +95,7 @@ class InboxBlock(TestCase):
},
}
with patch(
"bookwyrm.activitystreams.ActivityStream.add_user_statuses"
"bookwyrm.activitystreams.add_user_statuses_task.delay"
) as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)

View file

@ -11,20 +11,24 @@ from bookwyrm.activitypub import ActivitySerializerError
# pylint: disable=too-many-public-methods
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
class InboxCreate(TestCase):
"""readthrough tests"""
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -46,7 +50,7 @@ class InboxCreate(TestCase):
}
models.SiteSettings.objects.create()
def test_create_status(self, _):
def test_create_status(self, *_):
"""the "it justs works" mode"""
datafile = pathlib.Path(__file__).parent.joinpath(
"../../data/ap_quotation.json"
@ -59,9 +63,7 @@ class InboxCreate(TestCase):
activity = self.create_json
activity["object"] = status_data
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
views.inbox.activity_task(activity)
status = models.Quotation.objects.get()
self.assertEqual(
@ -70,12 +72,37 @@ class InboxCreate(TestCase):
self.assertEqual(status.quote, "quote body")
self.assertEqual(status.content, "commentary")
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.thread_id, status.id)
# while we're here, lets ensure we avoid dupes
views.inbox.activity_task(activity)
self.assertEqual(models.Status.objects.count(), 1)
def test_create_status_remote_note_with_mention(self, _):
def test_create_comment_with_reading_status(self, *_):
"""the "it justs works" mode"""
datafile = pathlib.Path(__file__).parent.joinpath("../../data/ap_comment.json")
status_data = json.loads(datafile.read_bytes())
status_data["readingStatus"] = "to-read"
models.Edition.objects.create(
title="Test Book", remote_id="https://example.com/book/1"
)
activity = self.create_json
activity["object"] = status_data
views.inbox.activity_task(activity)
status = models.Comment.objects.get()
self.assertEqual(status.remote_id, "https://example.com/user/mouse/comment/6")
self.assertEqual(status.content, "commentary")
self.assertEqual(status.reading_status, "to-read")
self.assertEqual(status.user, self.local_user)
# while we're here, lets ensure we avoid dupes
views.inbox.activity_task(activity)
self.assertEqual(models.Status.objects.count(), 1)
def test_create_status_remote_note_with_mention(self, *_):
"""should only create it under the right circumstances"""
self.assertFalse(
models.Notification.objects.filter(user=self.local_user).exists()
@ -86,9 +113,8 @@ class InboxCreate(TestCase):
activity = self.create_json
activity["object"] = status_data
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
views.inbox.activity_task(activity)
status = models.Status.objects.last()
self.assertEqual(status.content, "test content in note")
self.assertEqual(status.mention_users.first(), self.local_user)
@ -97,14 +123,13 @@ class InboxCreate(TestCase):
)
self.assertEqual(models.Notification.objects.get().notification_type, "MENTION")
def test_create_status_remote_note_with_reply(self, _):
def test_create_status_remote_note_with_reply(self, *_):
"""should only create it under the right circumstances"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
parent_status = models.Status.objects.create(
user=self.local_user,
content="Test status",
remote_id="https://example.com/status/1",
)
parent_status = models.Status.objects.create(
user=self.local_user,
content="Test status",
remote_id="https://example.com/status/1",
)
self.assertEqual(models.Status.objects.count(), 1)
self.assertFalse(models.Notification.objects.filter(user=self.local_user))
@ -116,16 +141,15 @@ class InboxCreate(TestCase):
activity = self.create_json
activity["object"] = status_data
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
views.inbox.activity_task(activity)
status = models.Status.objects.last()
self.assertEqual(status.content, "test content in note")
self.assertEqual(status.reply_parent, parent_status)
self.assertEqual(status.thread_id, parent_status.id)
self.assertTrue(models.Notification.objects.filter(user=self.local_user))
self.assertEqual(models.Notification.objects.get().notification_type, "REPLY")
def test_create_rating(self, _):
def test_create_rating(self, *_):
"""a remote rating activity"""
book = models.Edition.objects.create(
title="Test Book", remote_id="https://example.com/book/1"
@ -155,14 +179,12 @@ class InboxCreate(TestCase):
"rating": 3,
"@context": "https://www.w3.org/ns/activitystreams",
}
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
views.inbox.activity_task(activity)
rating = models.ReviewRating.objects.first()
self.assertEqual(rating.book, book)
self.assertEqual(rating.rating, 3.0)
def test_create_list(self, _):
def test_create_list(self, *_):
"""a new list"""
activity = self.create_json
activity["object"] = {
@ -186,7 +208,7 @@ class InboxCreate(TestCase):
self.assertEqual(book_list.description, "summary text")
self.assertEqual(book_list.remote_id, "https://example.com/list/22")
def test_create_unsupported_type(self, _):
def test_create_unsupported_type(self, *_):
"""ignore activities we know we can't handle"""
activity = self.create_json
activity["object"] = {
@ -196,7 +218,7 @@ class InboxCreate(TestCase):
# just observer how it doesn't throw an error
views.inbox.activity_task(activity)
def test_create_unknown_type(self, _):
def test_create_unknown_type(self, *_):
"""ignore activities we know we've never heard of"""
activity = self.create_json
activity["object"] = {

View file

@ -1,4 +1,4 @@
""" tests incoming activities"""
"""tests incoming activities"""
from datetime import datetime
from unittest.mock import patch
@ -13,15 +13,18 @@ class InboxActivities(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -32,21 +35,13 @@ class InboxActivities(TestCase):
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
self.status = models.Status.objects.create(
user=self.remote_user,
content="Test status",
remote_id="https://example.com/status/1",
)
self.create_json = {
"id": "hi",
"type": "Create",
"actor": "hi",
"to": ["https://www.w3.org/ns/activitystreams#public"],
"cc": ["https://example.com/user/mouse/followers"],
"object": {},
}
models.SiteSettings.objects.create()
def test_delete_status(self):
@ -60,9 +55,7 @@ class InboxActivities(TestCase):
"actor": self.remote_user.remote_id,
"object": {"id": self.status.remote_id, "type": "Tombstone"},
}
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as redis_mock:
with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
# deletion doens't remove the status, it turns it into a tombstone
@ -91,9 +84,7 @@ class InboxActivities(TestCase):
"actor": self.remote_user.remote_id,
"object": {"id": self.status.remote_id, "type": "Tombstone"},
}
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as redis_mock:
with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock:
views.inbox.activity_task(activity)
self.assertTrue(redis_mock.called)
# deletion doens't remove the status, it turns it into a tombstone
@ -105,7 +96,8 @@ class InboxActivities(TestCase):
self.assertEqual(models.Notification.objects.count(), 1)
self.assertEqual(models.Notification.objects.get(), notif)
def test_delete_user(self):
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_delete_user(self, _):
"""delete a user"""
self.assertTrue(models.User.objects.get(username="rat@example.com").is_active)
activity = {
@ -135,3 +127,30 @@ class InboxActivities(TestCase):
# nothing happens.
views.inbox.activity_task(activity)
self.assertEqual(models.User.objects.filter(is_active=True).count(), 2)
def test_delete_list(self):
"""delete a list"""
book_list = models.List.objects.create(
name="test list",
user=self.remote_user,
remote_id="https://example.com/list/1",
)
activity = {
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.com/users/test-user#delete",
"type": "Delete",
"actor": "https://example.com/users/test-user",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"object": {
"id": book_list.remote_id,
"owner": self.remote_user.remote_id,
"type": "BookList",
"totalItems": 0,
"first": "",
"name": "test list",
"to": [],
"cc": [],
},
}
views.inbox.activity_task(activity)
self.assertFalse(models.List.objects.exists())

View file

@ -13,15 +13,18 @@ class InboxRelationships(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -102,7 +105,9 @@ class InboxRelationships(TestCase):
}
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
self.local_user.save(
broadcast=False, update_fields=["manually_approves_followers"]
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.inbox.activity_task(activity)
@ -124,7 +129,9 @@ class InboxRelationships(TestCase):
def test_undo_follow_request(self):
"""the requester cancels a follow request"""
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
self.local_user.save(
broadcast=False, update_fields=["manually_approves_followers"]
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
request = models.UserFollowRequest.objects.create(
user_subject=self.remote_user, user_object=self.local_user
@ -176,7 +183,8 @@ class InboxRelationships(TestCase):
views.inbox.activity_task(activity)
self.assertIsNone(self.local_user.followers.first())
def test_follow_accept(self):
@patch("bookwyrm.activitystreams.add_user_statuses_task.delay")
def test_follow_accept(self, _):
"""a remote user approved a follow request from local"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
rel = models.UserFollowRequest.objects.create(

View file

@ -12,15 +12,18 @@ class InboxActivities(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -33,7 +36,7 @@ class InboxActivities(TestCase):
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
self.status = models.Status.objects.create(
user=self.local_user,
content="Test status",

View file

@ -12,15 +12,18 @@ class InboxRemove(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",

View file

@ -14,15 +14,18 @@ class InboxUpdate(TestCase):
def setUp(self):
"""basic user and book data"""
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@example.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
)
self.local_user.remote_id = "https://example.com/user/mouse"
self.local_user.save(broadcast=False)
self.local_user.save(broadcast=False, update_fields=["remote_id"])
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -34,9 +37,9 @@ class InboxUpdate(TestCase):
outbox="https://example.com/users/rat/outbox",
)
self.create_json = {
self.update_json = {
"id": "hi",
"type": "Create",
"type": "Update",
"actor": "hi",
"to": ["https://www.w3.org/ns/activitystreams#public"],
"cc": ["https://example.com/user/mouse/followers"],
@ -51,26 +54,20 @@ class InboxUpdate(TestCase):
book_list = models.List.objects.create(
name="hi", remote_id="https://example.com/list/22", user=self.local_user
)
activity = {
"type": "Update",
"to": [],
"cc": [],
"actor": "hi",
"id": "sdkjf",
"object": {
"id": "https://example.com/list/22",
"type": "BookList",
"totalItems": 1,
"first": "https://example.com/list/22?page=1",
"last": "https://example.com/list/22?page=1",
"name": "Test List",
"owner": "https://example.com/user/mouse",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://example.com/user/mouse/followers"],
"summary": "summary text",
"curation": "curated",
"@context": "https://www.w3.org/ns/activitystreams",
},
activity = self.update_json
activity["object"] = {
"id": "https://example.com/list/22",
"type": "BookList",
"totalItems": 1,
"first": "https://example.com/list/22?page=1",
"last": "https://example.com/list/22?page=1",
"name": "Test List",
"owner": "https://example.com/user/mouse",
"to": ["https://www.w3.org/ns/activitystreams#Public"],
"cc": ["https://example.com/user/mouse/followers"],
"summary": "summary text",
"curation": "curated",
"@context": "https://www.w3.org/ns/activitystreams",
}
views.inbox.activity_task(activity)
book_list.refresh_from_db()
@ -79,7 +76,9 @@ class InboxUpdate(TestCase):
self.assertEqual(book_list.description, "summary text")
self.assertEqual(book_list.remote_id, "https://example.com/list/22")
def test_update_user(self):
@patch("bookwyrm.suggested_users.rerank_user_task.delay")
@patch("bookwyrm.activitystreams.add_user_statuses_task.delay")
def test_update_user(self, *_):
"""update an existing user"""
models.UserFollows.objects.create(
user_subject=self.local_user,
@ -171,3 +170,26 @@ class InboxUpdate(TestCase):
)
book = models.Work.objects.get(id=book.id)
self.assertEqual(book.title, "Piranesi")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_update_status(self, *_):
"""edit a status"""
status = models.Status.objects.create(user=self.remote_user, content="hi")
datafile = pathlib.Path(__file__).parent.joinpath("../../data/ap_note.json")
status_data = json.loads(datafile.read_bytes())
status_data["id"] = status.remote_id
status_data["updated"] = "2021-12-13T05:09:29Z"
activity = self.update_json
activity["object"] = status_data
with patch("bookwyrm.activitypub.base_activity.set_related_field.delay"):
views.inbox.activity_task(activity)
status.refresh_from_db()
self.assertEqual(status.content, "test content in note")
self.assertEqual(status.edited_date.year, 2021)
self.assertEqual(status.edited_date.month, 12)
self.assertEqual(status.edited_date.day, 13)

View file

@ -0,0 +1 @@
from . import *

View file

@ -8,6 +8,7 @@ from django.test.client import RequestFactory
from bookwyrm import forms, models
from bookwyrm import views
from bookwyrm.tests.validate_html import validate_html
class InviteViews(TestCase):
@ -16,13 +17,16 @@ class InviteViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_invite_page(self):
@ -37,7 +41,7 @@ class InviteViews(TestCase):
invite.return_value = True
result = view(request, "hi")
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_manage_invites(self):
@ -48,9 +52,29 @@ class InviteViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_manage_invites_post(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.ManageInvites.as_view()
form = forms.CreateInviteForm()
form.data["use_limit"] = 3
form.data["expiry"] = ""
request = self.factory.post("", form.data)
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
invite = models.SiteInvite.objects.get()
self.assertEqual(invite.use_limit, 3)
self.assertIsNone(invite.expiry)
def test_invite_request(self):
"""request to join a server"""
form = forms.InviteRequestForm()
@ -60,7 +84,7 @@ class InviteViews(TestCase):
request = self.factory.post("", form.data)
result = view(request)
result.render()
validate_html(result.render())
req = models.InviteRequest.objects.get()
self.assertEqual(req.email, "new@user.email")
@ -74,7 +98,7 @@ class InviteViews(TestCase):
request = self.factory.post("", form.data)
result = view(request)
result.render()
validate_html(result.render())
# no request created
self.assertFalse(models.InviteRequest.objects.exists())
@ -87,14 +111,14 @@ class InviteViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
# now with data
models.InviteRequest.objects.create(email="fish@example.com")
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_manage_invite_requests_send(self):

View file

@ -7,6 +7,7 @@ from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
from bookwyrm.tests.validate_html import validate_html
class LandingViews(TestCase):
@ -15,18 +16,22 @@ class LandingViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_home_page(self):
@patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions")
def test_home_page(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.Home.as_view()
request = self.factory.get("")
@ -34,13 +39,13 @@ class LandingViews(TestCase):
with patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream"):
result = view(request)
self.assertEqual(result.status_code, 200)
result.render()
validate_html(result.render())
request.user = self.anonymous_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
self.assertEqual(result.status_code, 200)
result.render()
validate_html(result.render())
def test_about_page(self):
"""there are so many views, this just makes sure it LOADS"""
@ -49,12 +54,12 @@ class LandingViews(TestCase):
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_discover(self):
def test_landing(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
view = views.Landing.as_view()
request = self.factory.get("")
result = view(request)
self.assertIsInstance(result, TemplateResponse)

View file

@ -0,0 +1,111 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
# pylint: disable=too-many-public-methods
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class LoginViews(TestCase):
"""login and password management"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@your.domain.here",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create(id=1, require_confirm_email=False)
def test_login_get(self, *_):
"""there are so many views, this just makes sure it LOADS"""
login = views.Login.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = login(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
request.user = self.local_user
result = login(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_login_post_localname(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Login.as_view()
form = forms.LoginForm()
form.data["localname"] = "mouse@mouse.com"
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.anonymous_user
with patch("bookwyrm.views.landing.login.login"):
result = view(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_login_post_username(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Login.as_view()
form = forms.LoginForm()
form.data["localname"] = "mouse@your.domain.here"
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.anonymous_user
with patch("bookwyrm.views.landing.login.login"):
result = view(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_login_post_email(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Login.as_view()
form = forms.LoginForm()
form.data["localname"] = "mouse"
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.anonymous_user
with patch("bookwyrm.views.landing.login.login"):
result = view(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_login_post_invalid_credentials(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Login.as_view()
form = forms.LoginForm()
form.data["localname"] = "mouse"
form.data["password"] = "passsword1"
request = self.factory.post("", form.data)
request.user = self.anonymous_user
with patch("bookwyrm.views.landing.login.login"):
result = view(request)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(
result.context_data["login_form"].non_field_errors,
"Username or password are incorrect",
)

View file

@ -1,12 +1,16 @@
""" test for app action functionality """
from datetime import timedelta
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import timezone
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class PasswordViews(TestCase):
@ -15,13 +19,16 @@ class PasswordViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create(id=1)
@ -34,21 +41,23 @@ class PasswordViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_password_reset_request_post(self):
"""send 'em an email"""
request = self.factory.post("", {"email": "aa@bb.ccc"})
request.user = self.anonymous_user
view = views.PasswordResetRequest.as_view()
resp = view(request)
self.assertEqual(resp.status_code, 200)
resp.render()
validate_html(resp.render())
request = self.factory.post("", {"email": "mouse@mouse.com"})
request.user = self.anonymous_user
with patch("bookwyrm.emailing.send_email.delay"):
resp = view(request)
resp.render()
validate_html(resp.render())
self.assertEqual(models.PasswordReset.objects.get().user, self.local_user)
@ -60,15 +69,43 @@ class PasswordViews(TestCase):
request.user = self.anonymous_user
result = view(request, code.code)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_password_reset_nonexistant_code(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.PasswordReset.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
with self.assertRaises(PermissionDenied):
view(request, "beep")
def test_password_reset_invalid_code(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.PasswordReset.as_view()
code = models.PasswordReset.objects.create(
user=self.local_user, expiry=timezone.now() - timedelta(days=2)
)
request = self.factory.get("")
request.user = self.anonymous_user
with self.assertRaises(PermissionDenied):
view(request, code.code)
def test_password_reset_logged_in(self):
"""redirect logged in users"""
view = views.PasswordReset.as_view()
code = models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.get("")
request.user = self.local_user
result = view(request, code.code)
self.assertEqual(result.status_code, 302)
def test_password_reset_post(self):
"""reset from code"""
view = views.PasswordReset.as_view()
code = models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
with patch("bookwyrm.views.password.login"):
with patch("bookwyrm.views.landing.password.login"):
resp = view(request, code.code)
self.assertEqual(resp.status_code, 302)
self.assertFalse(models.PasswordReset.objects.exists())
@ -79,7 +116,7 @@ class PasswordViews(TestCase):
models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
resp = view(request, "jhgdkfjgdf")
resp.render()
validate_html(resp.render())
self.assertTrue(models.PasswordReset.objects.exists())
def test_password_reset_mismatch(self):
@ -88,35 +125,5 @@ class PasswordViews(TestCase):
code = models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
resp = view(request, code.code)
resp.render()
validate_html(resp.render())
self.assertTrue(models.PasswordReset.objects.exists())
def test_password_change_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.ChangePassword.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_password_change(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
request.user = self.local_user
with patch("bookwyrm.views.password.login"):
view(request)
self.assertNotEqual(self.local_user.password, password_hash)
def test_password_change_mismatch(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
request.user = self.local_user
view(request)
self.assertEqual(self.local_user.password, password_hash)

View file

@ -0,0 +1,368 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.http.response import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.settings import DOMAIN
from bookwyrm.tests.validate_html import validate_html
# pylint: disable=too-many-public-methods
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class RegisterViews(TestCase):
"""login and password management"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@your.domain.here",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
self.settings = models.SiteSettings.objects.create(
id=1, require_confirm_email=False
)
def test_get_redirect(self, *_):
"""there's no dedicated registration page"""
view = views.Register.as_view()
request = self.factory.get("register/")
response = view(request)
self.assertEqual(response.status_code, 302)
def test_register(self, *_):
"""create a user"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/",
{
"localname": "nutria-user.user_nutria",
"password": "mouseword",
"email": "aa@bb.cccc",
},
)
with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.last()
self.assertEqual(nutria.username, f"nutria-user.user_nutria@{DOMAIN}")
self.assertEqual(nutria.localname, "nutria-user.user_nutria")
self.assertEqual(nutria.local, True)
@patch("bookwyrm.emailing.send_email.delay")
def test_register_email_confirm(self, *_):
"""create a user"""
self.settings.require_confirm_email = True
self.settings.save()
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/",
{
"localname": "nutria",
"password": "mouseword",
"email": "aa@bb.cccc",
},
)
with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.get(localname="nutria")
self.assertEqual(nutria.username, f"nutria@{DOMAIN}")
self.assertEqual(nutria.local, True)
self.assertFalse(nutria.is_active)
self.assertEqual(nutria.deactivation_reason, "pending")
self.assertIsNotNone(nutria.confirmation_code)
def test_register_trailing_space(self, *_):
"""django handles this so weirdly"""
view = views.Register.as_view()
request = self.factory.post(
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
)
with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.last()
self.assertEqual(nutria.username, f"nutria@{DOMAIN}")
self.assertEqual(nutria.localname, "nutria")
self.assertEqual(nutria.local, True)
def test_register_invalid_email(self, *_):
"""gotta have an email"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/", {"localname": "nutria", "password": "mouseword", "email": "aa"}
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
validate_html(response.render())
def test_register_error_and_invite(self, *_):
"""redirect to the invite page"""
view = views.Register.as_view()
self.settings.allow_registration = False
self.settings.save()
models.SiteInvite.objects.create(
code="testcode", user=self.local_user, use_limit=1
)
self.assertEqual(models.SiteInvite.objects.get().times_used, 0)
request = self.factory.post(
"register/",
{
"localname": "nutria",
"password": "mouseword",
"email": "",
"invite_code": "testcode",
},
)
with patch("bookwyrm.views.landing.register.login"):
response = view(request)
response = view(request)
validate_html(response.render())
def test_register_username_in_use(self, *_):
"""that username is taken"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/",
{"localname": "mouse", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
validate_html(response.render())
def test_register_invalid_username(self, *_):
"""gotta have an email"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/",
{"localname": "nut@ria", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
validate_html(response.render())
request = self.factory.post(
"register/",
{"localname": "nutr ia", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
validate_html(response.render())
request = self.factory.post(
"register/",
{"localname": "nut@ria", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
validate_html(response.render())
def test_register_closed_instance(self, *_):
"""you can't just register"""
view = views.Register.as_view()
self.settings.allow_registration = False
self.settings.save()
request = self.factory.post(
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
)
with self.assertRaises(PermissionDenied):
view(request)
def test_register_blocked_domain(self, *_):
"""you can't register with a blocked domain"""
view = views.Register.as_view()
models.EmailBlocklist.objects.create(domain="gmail.com")
# one that fails
request = self.factory.post(
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@gmail.com"},
)
result = view(request)
self.assertEqual(result.status_code, 302)
self.assertFalse(models.User.objects.filter(email="aa@gmail.com").exists())
# one that succeeds
request = self.factory.post(
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bleep.com"},
)
with patch("bookwyrm.views.landing.register.login"):
result = view(request)
self.assertEqual(result.status_code, 302)
self.assertTrue(models.User.objects.filter(email="aa@bleep.com").exists())
def test_register_invite(self, *_):
"""you can't just register"""
view = views.Register.as_view()
self.settings.allow_registration = False
self.settings.save()
models.SiteInvite.objects.create(
code="testcode", user=self.local_user, use_limit=1
)
self.assertEqual(models.SiteInvite.objects.get().times_used, 0)
request = self.factory.post(
"register/",
{
"localname": "nutria",
"password": "mouseword",
"email": "aa@bb.ccc",
"invite_code": "testcode",
},
)
with patch("bookwyrm.views.landing.register.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
self.assertEqual(models.SiteInvite.objects.get().times_used, 1)
# invite already used to max capacity
request = self.factory.post(
"register/",
{
"localname": "nutria2",
"password": "mouseword",
"email": "aa@bb.ccc",
"invite_code": "testcode",
},
)
with self.assertRaises(PermissionDenied):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
# bad invite code
request = self.factory.post(
"register/",
{
"localname": "nutria3",
"password": "mouseword",
"email": "aa@bb.ccc",
"invite_code": "dkfkdjgdfkjgkdfj",
},
)
with self.assertRaises(Http404):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
def test_confirm_email_code_get(self, *_):
"""there are so many views, this just makes sure it LOADS"""
self.settings.require_confirm_email = True
self.settings.save()
self.local_user.is_active = False
self.local_user.deactivation_reason = "pending"
self.local_user.confirmation_code = "12345"
self.local_user.save(
broadcast=False,
update_fields=["is_active", "deactivation_reason", "confirmation_code"],
)
view = views.ConfirmEmailCode.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request, "12345")
self.assertEqual(result.url, "/login/confirmed")
self.assertEqual(result.status_code, 302)
self.local_user.refresh_from_db()
self.assertTrue(self.local_user.is_active)
self.assertIsNone(self.local_user.deactivation_reason)
request.user = self.local_user
result = view(request, "12345")
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_confirm_email_code_get_invalid_code(self, *_):
"""there are so many views, this just makes sure it LOADS"""
self.settings.require_confirm_email = True
self.settings.save()
self.local_user.is_active = False
self.local_user.deactivation_reason = "pending"
self.local_user.confirmation_code = "12345"
self.local_user.save(
broadcast=False,
update_fields=["is_active", "deactivation_reason", "confirmation_code"],
)
view = views.ConfirmEmailCode.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request, "abcde")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertFalse(self.local_user.is_active)
self.assertEqual(self.local_user.deactivation_reason, "pending")
def test_confirm_email_get(self, *_):
"""there are so many views, this just makes sure it LOADS"""
self.settings.require_confirm_email = True
self.settings.save()
login = views.ConfirmEmail.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = login(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
request.user = self.local_user
result = login(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_confirm_email_post(self, *_):
"""send the email"""
self.settings.require_confirm_email = True
self.settings.save()
view = views.ConfirmEmail.as_view()
models.SiteInvite.objects.create(
code="testcode", user=self.local_user, use_limit=1
)
request = self.factory.post("", {"code": "testcode"})
request.user = self.anonymous_user
result = view(request)
validate_html(result.render())
def test_resend_link(self, *_):
"""try again"""
request = self.factory.post("", {"email": "mouse@mouse.com"})
request.user = self.anonymous_user
with patch("bookwyrm.emailing.send_email.delay") as mock:
views.resend_link(request)
self.assertEqual(mock.call_count, 1)

View file

@ -0,0 +1 @@
from . import *

View file

@ -1,10 +1,12 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@ -14,13 +16,16 @@ class BlockViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -41,7 +46,7 @@ class BlockViews(TestCase):
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_block_post(self, _):
@ -56,7 +61,7 @@ class BlockViews(TestCase):
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.remove_user_statuses"):
with patch("bookwyrm.activitystreams.remove_user_statuses_task.delay"):
view(request, self.remote_user.id)
block = models.UserBlocks.objects.get()
self.assertEqual(block.user_subject, self.local_user)
@ -71,7 +76,7 @@ class BlockViews(TestCase):
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_user_statuses"):
views.block.unblock(request, self.remote_user.id)
with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"):
views.unblock(request, self.remote_user.id)
self.assertFalse(models.UserBlocks.objects.exists())

View file

@ -0,0 +1,58 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class ChangePasswordViews(TestCase):
"""view user and edit profile"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create(id=1)
def test_password_change_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.ChangePassword.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_password_change(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
request.user = self.local_user
with patch("bookwyrm.views.preferences.change_password.login"):
view(request)
self.assertNotEqual(self.local_user.password, password_hash)
def test_password_change_mismatch(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
request.user = self.local_user
view(request)
self.assertEqual(self.local_user.password, password_hash)

View file

@ -0,0 +1,86 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.contrib.sessions.middleware import SessionMiddleware
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.suggested_users.remove_user_task.delay")
class DeleteUserViews(TestCase):
"""view user and edit profile"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
self.book = models.Edition.objects.create(
title="test", parent_work=models.Work.objects.create(title="test work")
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch(
"bookwyrm.activitystreams.add_book_statuses_task.delay"
):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
)
models.SiteSettings.objects.create()
def test_delete_user_page(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.DeleteUser.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.suggested_users.rerank_suggestions_task")
def test_delete_user(self, *_):
"""use a form to update a user"""
view = views.DeleteUser.as_view()
form = forms.DeleteUserForm()
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.local_user
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
self.assertIsNone(self.local_user.name)
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
view(request)
self.assertEqual(delay_mock.call_count, 1)
activity = json.loads(delay_mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(
activity["cc"][0], "https://www.w3.org/ns/activitystreams#Public"
)
self.local_user.refresh_from_db()
self.assertFalse(self.local_user.is_active)
self.assertEqual(self.local_user.deactivation_reason, "self_deletion")

View file

@ -1,11 +1,9 @@
""" test for app action functionality """
import json
import pathlib
from unittest.mock import patch
from PIL import Image
from django.contrib.auth.models import AnonymousUser
from django.contrib.sessions.middleware import SessionMiddleware
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
@ -13,53 +11,63 @@ from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.suggested_users.remove_user_task.delay")
class EditUserViews(TestCase):
"""view user and edit profile"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
self.book = models.Edition.objects.create(title="test")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
self.book = models.Edition.objects.create(
title="test", parent_work=models.Work.objects.create(title="test work")
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch(
"bookwyrm.activitystreams.add_book_statuses_task.delay"
):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
)
models.SiteSettings.objects.create()
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
def test_edit_user_page(self):
def test_edit_user_page(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.EditUser.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_user(self):
def test_edit_user(self, _):
"""use a form to update a user"""
view = views.EditUser.as_view()
form = forms.EditUserForm(instance=self.local_user)
form.data["name"] = "New Name"
form.data["email"] = "wow@email.com"
form.data["default_post_privacy"] = "public"
form.data["preferred_timezone"] = "UTC"
request = self.factory.post("", form.data)
request.user = self.local_user
@ -73,16 +81,18 @@ class EditUserViews(TestCase):
self.assertEqual(self.local_user.name, "New Name")
self.assertEqual(self.local_user.email, "wow@email.com")
def test_edit_user_avatar(self):
def test_edit_user_avatar(self, _):
"""use a form to update a user"""
view = views.EditUser.as_view()
form = forms.EditUserForm(instance=self.local_user)
form.data["name"] = "New Name"
form.data["email"] = "wow@email.com"
form.data["default_post_privacy"] = "public"
form.data["preferred_timezone"] = "UTC"
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/no_cover.jpg"
"../../../static/images/no_cover.jpg"
)
# pylint: disable=consider-using-with
form.data["avatar"] = SimpleUploadedFile(
image_file, open(image_file, "rb").read(), content_type="image/jpeg"
)
@ -100,52 +110,14 @@ class EditUserViews(TestCase):
self.assertEqual(self.local_user.avatar.width, 120)
self.assertEqual(self.local_user.avatar.height, 120)
def test_crop_avatar(self):
def test_crop_avatar(self, _):
"""reduce that image size"""
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/no_cover.jpg"
"../../../static/images/no_cover.jpg"
)
image = Image.open(image_file)
result = views.edit_user.crop_avatar(image)
result = views.preferences.edit_user.crop_avatar(image)
self.assertIsInstance(result, ContentFile)
image_result = Image.open(result)
self.assertEqual(image_result.size, (120, 120))
def test_delete_user_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.DeleteUser.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_delete_user(self):
"""use a form to update a user"""
view = views.DeleteUser.as_view()
form = forms.DeleteUserForm()
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.local_user
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
self.assertIsNone(self.local_user.name)
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
view(request)
self.assertEqual(delay_mock.call_count, 1)
activity = json.loads(delay_mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(
activity["cc"][0], "https://www.w3.org/ns/activitystreams#Public"
)
self.local_user.refresh_from_db()
self.assertFalse(self.local_user.is_active)
self.assertEqual(self.local_user.deactivation_reason, "self_deletion")

View file

@ -0,0 +1 @@
from . import *

View file

@ -0,0 +1,165 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
class ShelfViews(TestCase):
"""tag views"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.shelf = models.Shelf.objects.create(
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
models.SiteSettings.objects.create()
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
def test_shelf_page_all_books(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Shelf.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.local_user.username)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_shelf_page_all_books_anonymous(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Shelf.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.local_user.username)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_shelf_page_sorted(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.first()
request = self.factory.get("", {"sort": "author"})
request.user = self.local_user
with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_shelf_page(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.first()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
request = self.factory.get("/?page=1")
request.user = self.local_user
with patch("bookwyrm.views.shelf.shelf.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_edit_shelf_privacy(self, *_):
"""set name or privacy on shelf"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.get(identifier="to-read")
self.assertEqual(shelf.privacy, "public")
request = self.factory.post(
"",
{
"privacy": "unlisted",
"user": self.local_user.id,
"name": "To Read",
},
)
request.user = self.local_user
view(request, self.local_user.username, shelf.identifier)
shelf.refresh_from_db()
self.assertEqual(shelf.privacy, "unlisted")
def test_edit_shelf_name(self, *_):
"""change the name of an editable shelf"""
view = views.Shelf.as_view()
shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
self.assertEqual(shelf.privacy, "public")
request = self.factory.post(
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, request.user.username, shelf.identifier)
shelf.refresh_from_db()
self.assertEqual(shelf.name, "cool name")
self.assertEqual(shelf.identifier, f"testshelf-{shelf.id}")
def test_edit_shelf_name_not_editable(self, *_):
"""can't change the name of an non-editable shelf"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.get(identifier="to-read")
self.assertEqual(shelf.privacy, "public")
request = self.factory.post(
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, request.user.username, shelf.identifier)
self.assertEqual(shelf.name, "To Read")

View file

@ -1,29 +1,36 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.core.exceptions import PermissionDenied
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm import forms, models, views
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class ShelfViews(TestCase):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
class ShelfActionViews(TestCase):
"""tag views"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
@ -36,86 +43,7 @@ class ShelfViews(TestCase):
)
models.SiteSettings.objects.create()
def test_shelf_page(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.first()
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
request = self.factory.get("/?page=1")
request.user = self.local_user
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_edit_shelf_privacy(self, _):
"""set name or privacy on shelf"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.get(identifier="to-read")
self.assertEqual(shelf.privacy, "public")
request = self.factory.post(
"",
{
"privacy": "unlisted",
"user": self.local_user.id,
"name": "To Read",
},
)
request.user = self.local_user
view(request, self.local_user.username, shelf.identifier)
shelf.refresh_from_db()
self.assertEqual(shelf.privacy, "unlisted")
def test_edit_shelf_name(self, _):
"""change the name of an editable shelf"""
view = views.Shelf.as_view()
shelf = models.Shelf.objects.create(name="Test Shelf", user=self.local_user)
self.assertEqual(shelf.privacy, "public")
request = self.factory.post(
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, request.user.username, shelf.identifier)
shelf.refresh_from_db()
self.assertEqual(shelf.name, "cool name")
self.assertEqual(shelf.identifier, "testshelf-%d" % shelf.id)
def test_edit_shelf_name_not_editable(self, _):
"""can't change the name of an non-editable shelf"""
view = views.Shelf.as_view()
shelf = self.local_user.shelf_set.get(identifier="to-read")
self.assertEqual(shelf.privacy, "public")
request = self.factory.post(
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, request.user.username, shelf.identifier)
self.assertEqual(shelf.name, "To Read")
def test_handle_shelve(self, _):
def test_shelve(self, *_):
"""shelve a book"""
request = self.factory.post(
"", {"book": self.book.id, "shelf": self.shelf.identifier}
@ -133,7 +61,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(self.shelf.books.get(), self.book)
def test_handle_shelve_to_read(self, _):
def test_shelve_to_read(self, *_):
"""special behavior for the to-read shelf"""
shelf = models.Shelf.objects.get(identifier="to-read")
request = self.factory.post(
@ -146,7 +74,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
def test_handle_shelve_reading(self, _):
def test_shelve_reading(self, *_):
"""special behavior for the reading shelf"""
shelf = models.Shelf.objects.get(identifier="reading")
request = self.factory.post(
@ -159,7 +87,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
def test_handle_shelve_read(self, _):
def test_shelve_read(self, *_):
"""special behavior for the read shelf"""
shelf = models.Shelf.objects.get(identifier="read")
request = self.factory.post(
@ -172,7 +100,31 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
def test_handle_unshelve(self, _):
def test_shelve_read_with_change_shelf(self, *_):
"""special behavior for the read shelf"""
previous_shelf = models.Shelf.objects.get(identifier="reading")
models.ShelfBook.objects.create(
shelf=previous_shelf, user=self.local_user, book=self.book
)
shelf = models.Shelf.objects.get(identifier="read")
request = self.factory.post(
"",
{
"book": self.book.id,
"shelf": shelf.identifier,
"change-shelf-from": previous_shelf.identifier,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.shelve(request)
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
self.assertEqual(list(previous_shelf.books.all()), [])
def test_unshelve(self, *_):
"""remove a book from a shelf"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
@ -190,3 +142,76 @@ class ShelfViews(TestCase):
self.assertEqual(activity["type"], "Remove")
self.assertEqual(activity["object"]["id"], item.remote_id)
self.assertEqual(self.shelf.books.count(), 0)
def test_create_shelf(self, *_):
"""a brand new custom shelf"""
form = forms.ShelfForm()
form.data["user"] = self.local_user.id
form.data["name"] = "new shelf name"
form.data["description"] = "desc"
form.data["privacy"] = "unlisted"
request = self.factory.post("", form.data)
request.user = self.local_user
views.create_shelf(request)
shelf = models.Shelf.objects.get(name="new shelf name")
self.assertEqual(shelf.privacy, "unlisted")
self.assertEqual(shelf.description, "desc")
self.assertEqual(shelf.user, self.local_user)
def test_delete_shelf(self, *_):
"""delete a brand new custom shelf"""
request = self.factory.post("")
request.user = self.local_user
shelf_id = self.shelf.id
views.delete_shelf(request, shelf_id)
self.assertFalse(models.Shelf.objects.filter(id=shelf_id).exists())
def test_delete_shelf_unauthorized(self, *_):
"""delete a brand new custom shelf"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
rat = models.User.objects.create_user(
"rat@local.com",
"rat@mouse.mouse",
"password",
local=True,
localname="rat",
)
request = self.factory.post("")
request.user = rat
with self.assertRaises(PermissionDenied):
views.delete_shelf(request, self.shelf.id)
self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists())
def test_delete_shelf_has_book(self, *_):
"""delete a brand new custom shelf"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
book=self.book, user=self.local_user, shelf=self.shelf
)
request = self.factory.post("")
request.user = self.local_user
with self.assertRaises(PermissionDenied):
views.delete_shelf(request, self.shelf.id)
self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists())
def test_delete_shelf_not_editable(self, *_):
"""delete a brand new custom shelf"""
shelf = self.local_user.shelf_set.first()
self.assertFalse(shelf.editable)
request = self.factory.post("")
request.user = self.local_user
with self.assertRaises(PermissionDenied):
views.delete_shelf(request, shelf.id)
self.assertTrue(models.Shelf.objects.filter(id=shelf.id).exists())

View file

@ -1,189 +0,0 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.http.response import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.settings import DOMAIN
# pylint: disable=too-many-public-methods
class AuthenticationViews(TestCase):
"""login and password management"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
self.settings = models.SiteSettings.objects.create(id=1)
def test_login_get(self):
"""there are so many views, this just makes sure it LOADS"""
login = views.Login.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = login(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
request.user = self.local_user
result = login(request)
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_register(self):
"""create a user"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/",
{
"localname": "nutria-user.user_nutria",
"password": "mouseword",
"email": "aa@bb.cccc",
},
)
with patch("bookwyrm.views.authentication.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.last()
self.assertEqual(nutria.username, "nutria-user.user_nutria@%s" % DOMAIN)
self.assertEqual(nutria.localname, "nutria-user.user_nutria")
self.assertEqual(nutria.local, True)
def test_register_trailing_space(self):
"""django handles this so weirdly"""
view = views.Register.as_view()
request = self.factory.post(
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
)
with patch("bookwyrm.views.authentication.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
nutria = models.User.objects.last()
self.assertEqual(nutria.username, "nutria@%s" % DOMAIN)
self.assertEqual(nutria.localname, "nutria")
self.assertEqual(nutria.local, True)
def test_register_invalid_email(self):
"""gotta have an email"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/", {"localname": "nutria", "password": "mouseword", "email": "aa"}
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
response.render()
def test_register_invalid_username(self):
"""gotta have an email"""
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
"register/",
{"localname": "nut@ria", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
response.render()
request = self.factory.post(
"register/",
{"localname": "nutr ia", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
response.render()
request = self.factory.post(
"register/",
{"localname": "nut@ria", "password": "mouseword", "email": "aa@bb.ccc"},
)
response = view(request)
self.assertEqual(models.User.objects.count(), 1)
response.render()
def test_register_closed_instance(self):
"""you can't just register"""
view = views.Register.as_view()
self.settings.allow_registration = False
self.settings.save()
request = self.factory.post(
"register/",
{"localname": "nutria ", "password": "mouseword", "email": "aa@bb.ccc"},
)
with self.assertRaises(PermissionDenied):
view(request)
def test_register_invite(self):
"""you can't just register"""
view = views.Register.as_view()
self.settings.allow_registration = False
self.settings.save()
models.SiteInvite.objects.create(
code="testcode", user=self.local_user, use_limit=1
)
self.assertEqual(models.SiteInvite.objects.get().times_used, 0)
request = self.factory.post(
"register/",
{
"localname": "nutria",
"password": "mouseword",
"email": "aa@bb.ccc",
"invite_code": "testcode",
},
)
with patch("bookwyrm.views.authentication.login"):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
self.assertEqual(response.status_code, 302)
self.assertEqual(models.SiteInvite.objects.get().times_used, 1)
# invite already used to max capacity
request = self.factory.post(
"register/",
{
"localname": "nutria2",
"password": "mouseword",
"email": "aa@bb.ccc",
"invite_code": "testcode",
},
)
with self.assertRaises(PermissionDenied):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)
# bad invite code
request = self.factory.post(
"register/",
{
"localname": "nutria3",
"password": "mouseword",
"email": "aa@bb.ccc",
"invite_code": "dkfkdjgdfkjgkdfj",
},
)
with self.assertRaises(Http404):
response = view(request)
self.assertEqual(models.User.objects.count(), 2)

View file

@ -9,6 +9,7 @@ from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.tests.validate_html import validate_html
class AuthorViews(TestCase):
@ -17,14 +18,17 @@ class AuthorViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.group = Group.objects.create(name="editor")
self.group.permissions.add(
Permission.objects.create(
@ -51,7 +55,7 @@ class AuthorViews(TestCase):
is_api.return_value = False
result = view(request, author.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 200)
@ -72,7 +76,7 @@ class AuthorViews(TestCase):
result = view(request, author.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 200)

View file

@ -1,9 +1,13 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
# pylint: disable=unused-argument
class DirectoryViews(TestCase):
@ -12,15 +16,28 @@ class DirectoryViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
models.SiteSettings.objects.create()
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.suggested_users.rerank_user_task.delay")
def test_directory_page(self, *_):
"""there are so many views, this just makes sure it LOADS"""
models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
@ -29,10 +46,16 @@ class DirectoryViews(TestCase):
remote_id="https://example.com/users/rat",
discoverable=True,
)
view = views.Directory.as_view()
request = self.factory.get("")
request.user = self.local_user
models.SiteSettings.objects.create()
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_directory_page(self):
def test_directory_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Directory.as_view()
request = self.factory.get("")
@ -40,5 +63,14 @@ class DirectoryViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_directory_page_logged_out(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Directory.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request)
self.assertEqual(result.status_code, 302)

View file

@ -0,0 +1,78 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
class DiscoverViews(TestCase):
"""pages you land on without really trying"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_discover_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
request = self.factory.get("")
request.user = self.local_user
with patch(
"bookwyrm.activitystreams.ActivityStream.get_activity_stream"
) as mock:
result = view(request)
self.assertEqual(mock.call_count, 1)
self.assertEqual(result.status_code, 200)
result.render()
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_discover_page(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
request = self.factory.get("")
request.user = self.local_user
book = models.Edition.objects.create(
title="hi", parent_work=models.Work.objects.create(title="work")
)
models.Comment.objects.create(
book=book,
user=self.local_user,
content="hello",
)
models.Status.objects.create(user=self.local_user, content="beep")
with patch(
"bookwyrm.activitystreams.ActivityStream.get_activity_stream"
) as mock:
mock.return_value = models.Status.objects.all()
result = view(request)
self.assertEqual(mock.call_count, 1)
self.assertEqual(result.status_code, 200)
result.render()
def test_discover_page_logged_out(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Discover.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request)
self.assertEqual(result.status_code, 302)

View file

@ -5,6 +5,7 @@ import pathlib
from PIL import Image
from django.core.files.base import ContentFile
from django.http import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -15,20 +16,26 @@ from bookwyrm.activitypub import ActivitypubResponse
@patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream")
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.suggested_users.remove_user_task.delay")
class FeedViews(TestCase):
"""activity feed, statuses, dms"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.book = models.Edition.objects.create(
parent_work=models.Work.objects.create(title="hi"),
title="Example Edition",
@ -36,12 +43,13 @@ class FeedViews(TestCase):
)
models.SiteSettings.objects.create()
@patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions")
def test_feed(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Feed.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request, "local")
result = view(request, "home")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
@ -74,9 +82,28 @@ class FeedViews(TestCase):
request.user = self.local_user
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse", 12345)
with self.assertRaises(Http404):
view(request, "mouse", 12345)
self.assertEqual(result.status_code, 404)
def test_status_page_not_found_wrong_user(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Status.as_view()
another_user = models.User.objects.create_user(
"rat@local.com",
"rat@rat.rat",
"password",
local=True,
localname="rat",
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(content="hi", user=another_user)
request = self.factory.get("")
request.user = self.local_user
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = False
with self.assertRaises(Http404):
view(request, "mouse", status.id)
def test_status_page_with_image(self, *_):
"""there are so many views, this just makes sure it LOADS"""
@ -144,14 +171,15 @@ class FeedViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
def test_get_suggested_book(self, *_):
"""gets books the ~*~ algorithm ~*~ thinks you want to post about"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.local_user.shelf_set.get(identifier="reading"),
)
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.local_user.shelf_set.get(identifier="reading"),
)
suggestions = views.feed.get_suggested_books(self.local_user)
self.assertEqual(suggestions[0]["name"], "Currently Reading")
self.assertEqual(suggestions[0]["books"][0], self.book)

View file

@ -10,20 +10,24 @@ from django.test.client import RequestFactory
from bookwyrm import models, views
class BookViews(TestCase):
"""books books books"""
@patch("bookwyrm.activitystreams.add_user_statuses_task.delay")
class FollowViews(TestCase):
"""follows"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.models.user.set_remote_server"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -49,7 +53,7 @@ class BookViews(TestCase):
parent_work=self.work,
)
def test_handle_follow_remote(self):
def test_handle_follow_remote(self, _):
"""send a follow request"""
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
@ -64,17 +68,20 @@ class BookViews(TestCase):
self.assertEqual(rel.user_object, self.remote_user)
self.assertEqual(rel.status, "follow_request")
def test_handle_follow_local_manually_approves(self):
def test_handle_follow_local_manually_approves(self, _):
"""send a follow request"""
rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
manually_approves_followers=True,
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
manually_approves_followers=True,
)
request = self.factory.post("", {"user": rat})
request.user = self.local_user
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
@ -87,16 +94,19 @@ class BookViews(TestCase):
self.assertEqual(rel.user_object, rat)
self.assertEqual(rel.status, "follow_request")
def test_handle_follow_local(self):
def test_handle_follow_local(self, _):
"""send a follow request"""
rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
request = self.factory.post("", {"user": rat})
request.user = self.local_user
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
@ -110,7 +120,8 @@ class BookViews(TestCase):
self.assertEqual(rel.user_object, rat)
self.assertEqual(rel.status, "follows")
def test_handle_unfollow(self):
@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay")
def test_handle_unfollow(self, *_):
"""send an unfollow"""
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
@ -124,10 +135,12 @@ class BookViews(TestCase):
self.assertEqual(self.remote_user.followers.count(), 0)
def test_handle_accept(self):
def test_handle_accept(self, _):
"""accept a follow request"""
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
self.local_user.save(
broadcast=False, update_fields=["manually_approves_followers"]
)
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
rel = models.UserFollowRequest.objects.create(
@ -141,10 +154,12 @@ class BookViews(TestCase):
# follow relationship should exist
self.assertEqual(self.local_user.followers.first(), self.remote_user)
def test_handle_reject(self):
def test_handle_reject(self, _):
"""reject a follow request"""
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
self.local_user.save(
broadcast=False, update_fields=["manually_approves_followers"]
)
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
rel = models.UserFollowRequest.objects.create(

View file

@ -7,30 +7,31 @@ from django.test.client import RequestFactory
from bookwyrm import forms, models, views
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
class GetStartedViews(TestCase):
"""helping new users get oriented"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.book = models.Edition.objects.create(
parent_work=models.Work.objects.create(title="hi"),
title="Example Edition",
remote_id="https://example.com/book/1",
)
models.Connector.objects.create(
identifier="self", connector_file="self_connector", local=True
)
models.SiteSettings.objects.create()
def test_profile_view(self):
def test_profile_view(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.GetStartedProfile.as_view()
request = self.factory.get("")
@ -42,7 +43,9 @@ class GetStartedViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_profile_view_post(self):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.suggested_users.rerank_user_task.delay")
def test_profile_view_post(self, *_):
"""save basic user details"""
view = views.GetStartedProfile.as_view()
form = forms.LimitedEditUserForm(instance=self.local_user)
@ -60,7 +63,7 @@ class GetStartedViews(TestCase):
self.assertEqual(self.local_user.name, "New Name")
self.assertTrue(self.local_user.discoverable)
def test_books_view(self):
def test_books_view(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.GetStartedBooks.as_view()
request = self.factory.get("")
@ -72,7 +75,7 @@ class GetStartedViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_books_view_with_query(self):
def test_books_view_with_query(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.GetStartedBooks.as_view()
request = self.factory.get("?query=Example")
@ -84,7 +87,9 @@ class GetStartedViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_books_view_post(self):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
def test_books_view_post(self, *_):
"""shelve some books"""
view = views.GetStartedBooks.as_view()
data = {self.book.id: self.local_user.shelf_set.first().id}
@ -102,7 +107,8 @@ class GetStartedViews(TestCase):
self.assertEqual(shelfbook.book, self.book)
self.assertEqual(shelfbook.user, self.local_user)
def test_users_view(self):
@patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions")
def test_users_view(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.GetStartedUsers.as_view()
request = self.factory.get("")
@ -114,7 +120,8 @@ class GetStartedViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_users_view_with_query(self):
@patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions")
def test_users_view_with_query(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.GetStartedUsers.as_view()
request = self.factory.get("?query=rat")

View file

@ -1,13 +1,15 @@
""" test for app action functionality """
from unittest.mock import patch
from django.utils import timezone
from django.contrib.auth.models import AnonymousUser
from django.http import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import timezone
from bookwyrm import models, views
from bookwyrm.tests.validate_html import validate_html
class GoalViews(TestCase):
@ -16,28 +18,32 @@ class GoalViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
self.book = models.Edition.objects.create(
title="Example Edition",
remote_id="https://example.com/book/1",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
self.year = timezone.now().year
models.SiteSettings.objects.create()
def test_goal_page_no_goal(self):
@ -46,7 +52,7 @@ class GoalViews(TestCase):
request = self.factory.get("")
request.user = self.rat
result = view(request, self.local_user.localname, 2020)
result = view(request, self.local_user.localname, self.year)
self.assertEqual(result.status_code, 404)
def test_goal_page_no_goal_self(self):
@ -55,8 +61,8 @@ class GoalViews(TestCase):
request = self.factory.get("")
request.user = self.local_user
result = view(request, self.local_user.localname, 2020)
result.render()
result = view(request, self.local_user.localname, self.year)
validate_html(result.render())
self.assertIsInstance(result, TemplateResponse)
def test_goal_page_anonymous(self):
@ -65,7 +71,7 @@ class GoalViews(TestCase):
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request, self.local_user.localname, 2020)
result = view(request, self.local_user.localname, self.year)
self.assertEqual(result.status_code, 302)
def test_goal_page_public(self):
@ -87,22 +93,22 @@ class GoalViews(TestCase):
request.user = self.rat
result = view(request, self.local_user.localname, timezone.now().year)
result.render()
validate_html(result.render())
self.assertIsInstance(result, TemplateResponse)
def test_goal_page_private(self):
"""view a user's private goal"""
models.AnnualGoal.objects.create(
user=self.local_user, year=2020, goal=15, privacy="followers"
user=self.local_user, year=self.year, goal=15, privacy="followers"
)
view = views.Goal.as_view()
request = self.factory.get("")
request.user = self.rat
result = view(request, self.local_user.localname, 2020)
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, self.local_user.localname, self.year)
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_create_goal(self, _):
"""create a new goal"""
view = views.Goal.as_view()
@ -111,19 +117,19 @@ class GoalViews(TestCase):
{
"user": self.local_user.id,
"goal": 10,
"year": 2020,
"year": self.year,
"privacy": "unlisted",
"post-status": True,
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.local_user.localname, 2020)
view(request, self.local_user.localname, self.year)
goal = models.AnnualGoal.objects.get()
self.assertEqual(goal.user, self.local_user)
self.assertEqual(goal.goal, 10)
self.assertEqual(goal.year, 2020)
self.assertEqual(goal.year, self.year)
self.assertEqual(goal.privacy, "unlisted")
status = models.GeneratedNote.objects.get()

View file

@ -0,0 +1,119 @@
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth import decorators
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views, forms
from bookwyrm.tests.validate_html import validate_html
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class GroupViews(TestCase):
"""view group and edit details"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.testgroup = models.Group.objects.create(
name="Test Group",
description="Initial description",
user=self.local_user,
privacy="public",
)
self.membership = models.GroupMember.objects.create(
group=self.testgroup, user=self.local_user
)
models.SiteSettings.objects.create()
def test_group_get(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.Group.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request, group_id=self.testgroup.id)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_usergroups_get(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.UserGroups.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request, username="mouse@local.com")
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.suggested_users.SuggestedUsers.get_suggestions")
def test_findusers_get(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.FindUsers.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request, group_id=self.testgroup.id)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_group_create(self, _):
"""create group view"""
view = views.UserGroups.as_view()
request = self.factory.post(
"",
{
"name": "A group",
"description": "wowzers",
"privacy": "unlisted",
"user": self.local_user.id,
},
)
request.user = self.local_user
result = view(request, "username")
self.assertEqual(result.status_code, 302)
new_group = models.Group.objects.filter(name="A group").get()
self.assertEqual(new_group.description, "wowzers")
self.assertEqual(new_group.privacy, "unlisted")
self.assertTrue(
models.GroupMember.objects.filter(
group=new_group, user=self.local_user
).exists()
)
def test_group_edit(self, _):
"""test editing a "group" database entry"""
view = views.Group.as_view()
request = self.factory.post(
"",
{
"name": "Updated Group name",
"description": "wow",
"privacy": "direct",
"user": self.local_user.id,
},
)
request.user = self.local_user
result = view(request, group_id=self.testgroup.id)
self.assertEqual(result.status_code, 302)
self.testgroup.refresh_from_db()
self.assertEqual(self.testgroup.name, "Updated Group name")
self.assertEqual(self.testgroup.description, "wow")
self.assertEqual(self.testgroup.privacy, "direct")

View file

@ -2,7 +2,6 @@
import json
from unittest.mock import patch
import pathlib
from django.db.models import Q
from django.http import Http404
from django.test import TestCase
from django.test.client import RequestFactory
@ -12,33 +11,41 @@ from bookwyrm import models, views
from bookwyrm.settings import USER_AGENT
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.suggested_users.rerank_user_task.delay")
class ViewsHelpers(TestCase):
"""viewing and creating statuses"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
discoverable=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
with patch("bookwyrm.suggested_users.rerank_user_task.delay"):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
discoverable=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
discoverable=True,
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
with patch("bookwyrm.suggested_users.rerank_user_task.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.com",
"ratword",
local=False,
remote_id="https://example.com/users/rat",
discoverable=True,
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Test Book",
@ -53,12 +60,12 @@ class ViewsHelpers(TestCase):
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
def test_get_edition(self, _):
def test_get_edition(self, *_):
"""given an edition or a work, returns an edition"""
self.assertEqual(views.helpers.get_edition(self.book.id), self.book)
self.assertEqual(views.helpers.get_edition(self.work.id), self.book)
def test_get_user_from_username(self, _):
def test_get_user_from_username(self, *_):
"""works for either localname or username"""
self.assertEqual(
views.helpers.get_user_from_username(self.local_user, "mouse"),
@ -71,7 +78,7 @@ class ViewsHelpers(TestCase):
with self.assertRaises(Http404):
views.helpers.get_user_from_username(self.local_user, "mojfse@example.com")
def test_is_api_request(self, _):
def test_is_api_request(self, *_):
"""should it return html or json"""
request = self.factory.get("/path")
request.headers = {"Accept": "application/json"}
@ -85,12 +92,12 @@ class ViewsHelpers(TestCase):
request.headers = {"Accept": "Praise"}
self.assertFalse(views.helpers.is_api_request(request))
def test_is_api_request_no_headers(self, _):
def test_is_api_request_no_headers(self, *_):
"""should it return html or json"""
request = self.factory.get("/path")
self.assertFalse(views.helpers.is_api_request(request))
def test_is_bookwyrm_request(self, _):
def test_is_bookwyrm_request(self, *_):
"""checks if a request came from a bookwyrm instance"""
request = self.factory.get("", {"q": "Test Book"})
self.assertFalse(views.helpers.is_bookwyrm_request(request))
@ -105,7 +112,7 @@ class ViewsHelpers(TestCase):
request = self.factory.get("", {"q": "Test Book"}, HTTP_USER_AGENT=USER_AGENT)
self.assertTrue(views.helpers.is_bookwyrm_request(request))
def test_existing_user(self, _):
def test_existing_user(self, *_):
"""simple database lookup by username"""
result = views.helpers.handle_remote_webfinger("@mouse@local.com")
self.assertEqual(result, self.local_user)
@ -117,7 +124,7 @@ class ViewsHelpers(TestCase):
self.assertEqual(result, self.local_user)
@responses.activate
def test_load_user(self, _):
def test_load_user(self, *_):
"""find a remote user using webfinger"""
username = "mouse@example.com"
wellknown = {
@ -147,7 +154,7 @@ class ViewsHelpers(TestCase):
self.assertIsInstance(result, models.User)
self.assertEqual(result.username, "mouse@example.com")
def test_user_on_blocked_server(self, _):
def test_user_on_blocked_server(self, *_):
"""find a remote user using webfinger"""
models.FederatedServer.objects.create(
server_name="example.com", status="blocked"
@ -156,7 +163,7 @@ class ViewsHelpers(TestCase):
result = views.helpers.handle_remote_webfinger("@mouse@example.com")
self.assertIsNone(result)
def test_handle_reading_status_to_read(self, _):
def test_handle_reading_status_to_read(self, *_):
"""posts shelve activities"""
shelf = self.local_user.shelf_set.get(identifier="to-read")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
@ -168,7 +175,7 @@ class ViewsHelpers(TestCase):
self.assertEqual(status.mention_books.first(), self.book)
self.assertEqual(status.content, "wants to read")
def test_handle_reading_status_reading(self, _):
def test_handle_reading_status_reading(self, *_):
"""posts shelve activities"""
shelf = self.local_user.shelf_set.get(identifier="reading")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
@ -180,7 +187,7 @@ class ViewsHelpers(TestCase):
self.assertEqual(status.mention_books.first(), self.book)
self.assertEqual(status.content, "started reading")
def test_handle_reading_status_read(self, _):
def test_handle_reading_status_read(self, *_):
"""posts shelve activities"""
shelf = self.local_user.shelf_set.get(identifier="read")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
@ -192,102 +199,10 @@ class ViewsHelpers(TestCase):
self.assertEqual(status.mention_books.first(), self.book)
self.assertEqual(status.content, "finished reading")
def test_handle_reading_status_other(self, _):
def test_handle_reading_status_other(self, *_):
"""posts shelve activities"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.helpers.handle_reading_status(
self.local_user, self.shelf, self.book, "public"
)
self.assertFalse(models.GeneratedNote.objects.exists())
def test_get_annotated_users(self, _):
"""list of people you might know"""
user_1 = models.User.objects.create_user(
"nutria@local.com",
"nutria@nutria.com",
"nutriaword",
local=True,
localname="nutria",
discoverable=True,
)
user_2 = models.User.objects.create_user(
"fish@local.com",
"fish@fish.com",
"fishword",
local=True,
localname="fish",
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
# 1 shared follow
self.local_user.following.add(user_2)
user_1.followers.add(user_2)
# 1 shared book
models.ShelfBook.objects.create(
user=self.local_user,
book=self.book,
shelf=self.local_user.shelf_set.first(),
)
models.ShelfBook.objects.create(
user=user_1, book=self.book, shelf=user_1.shelf_set.first()
)
result = views.helpers.get_annotated_users(self.local_user)
self.assertEqual(result.count(), 3)
self.assertTrue(user_1 in result)
self.assertFalse(user_2 in result)
self.assertTrue(self.local_user in result)
self.assertTrue(self.remote_user in result)
user_1_annotated = result.get(id=user_1.id)
self.assertEqual(user_1_annotated.mutuals, 1)
self.assertEqual(user_1_annotated.shared_books, 1)
remote_user_annotated = result.get(id=self.remote_user.id)
self.assertEqual(remote_user_annotated.mutuals, 0)
self.assertEqual(remote_user_annotated.shared_books, 0)
def test_get_annotated_users_counts(self, _):
"""correct counting for multiple shared attributed"""
user_1 = models.User.objects.create_user(
"nutria@local.com",
"nutria@nutria.com",
"nutriaword",
local=True,
localname="nutria",
discoverable=True,
)
for i in range(3):
user = models.User.objects.create_user(
"{:d}@local.com".format(i),
"{:d}@nutria.com".format(i),
"password",
local=True,
localname=i,
)
user.following.add(user_1)
user.followers.add(self.local_user)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
for i in range(3):
book = models.Edition.objects.create(
title=i,
parent_work=models.Work.objects.create(title=i),
)
models.ShelfBook.objects.create(
user=self.local_user,
book=book,
shelf=self.local_user.shelf_set.first(),
)
models.ShelfBook.objects.create(
user=user_1, book=book, shelf=user_1.shelf_set.first()
)
result = views.helpers.get_annotated_users(
self.local_user,
~Q(id=self.local_user.id),
~Q(followers=self.local_user),
)
self.assertEqual(result.count(), 2)
user_1_annotated = result.get(id=user_1.id)
self.assertEqual(user_1_annotated.mutuals, 3)

View file

@ -1,11 +1,12 @@
""" test for app action functionality """
import pathlib
from unittest.mock import patch
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
from bookwyrm import forms, models, views
class ImportViews(TestCase):
@ -14,13 +15,16 @@ class ImportViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_import_page(self):
@ -46,6 +50,27 @@ class ImportViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_start_import(self):
"""retry failed items"""
view = views.Import.as_view()
form = forms.ImportForm()
form.data["source"] = "LibraryThing"
form.data["privacy"] = "public"
form.data["include_reviews"] = False
csv_file = pathlib.Path(__file__).parent.joinpath("../data/goodreads.csv")
form.data["csv_file"] = SimpleUploadedFile(
csv_file, open(csv_file, "rb").read(), content_type="text/csv"
)
request = self.factory.post("", form.data)
request.user = self.local_user
with patch("bookwyrm.importers.Importer.start_import"):
view(request)
job = models.ImportJob.objects.get()
self.assertFalse(job.include_reviews)
self.assertEqual(job.privacy, "public")
def test_retry_import(self):
"""retry failed items"""
view = views.ImportStatus.as_view()

View file

@ -8,21 +8,24 @@ from bookwyrm import models, views
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
class InteractionViews(TestCase):
"""viewing and creating statuses"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.models.user.set_remote_server"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -46,7 +49,7 @@ class InteractionViews(TestCase):
view = views.Favorite.as_view()
request = self.factory.post("")
request.user = self.remote_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
view(request, status.id)
@ -64,7 +67,7 @@ class InteractionViews(TestCase):
view = views.Unfavorite.as_view()
request = self.factory.post("")
request.user = self.remote_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
views.Favorite.as_view()(request, status.id)
@ -81,7 +84,7 @@ class InteractionViews(TestCase):
view = views.Boost.as_view()
request = self.factory.post("")
request.user = self.remote_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
view(request, status.id)
@ -103,7 +106,7 @@ class InteractionViews(TestCase):
view = views.Boost.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
with patch(
@ -127,7 +130,7 @@ class InteractionViews(TestCase):
view = views.Boost.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="unlisted"
)
@ -142,7 +145,7 @@ class InteractionViews(TestCase):
view = views.Boost.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(
user=self.local_user, content="hi", privacy="followers"
)
@ -155,14 +158,14 @@ class InteractionViews(TestCase):
view = views.Boost.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
view(request, status.id)
view(request, status.id)
self.assertEqual(models.Boost.objects.count(), 1)
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_unboost(self, *_):
"""undo a boost"""
view = views.Unboost.as_view()
@ -170,17 +173,12 @@ class InteractionViews(TestCase):
request.user = self.remote_user
status = models.Status.objects.create(user=self.local_user, content="hi")
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
):
views.Boost.as_view()(request, status.id)
views.Boost.as_view()(request, status.id)
self.assertEqual(models.Boost.objects.count(), 1)
self.assertEqual(models.Notification.objects.count(), 1)
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as redis_mock:
view(request, status.id)
self.assertTrue(redis_mock.called)
view(request, status.id)
self.assertEqual(models.Boost.objects.count(), 0)
self.assertEqual(models.Notification.objects.count(), 0)

View file

@ -16,14 +16,17 @@ class IsbnViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Test Book",
@ -31,9 +34,6 @@ class IsbnViews(TestCase):
remote_id="https://example.com/book/1",
parent_work=self.work,
)
models.Connector.objects.create(
identifier="self", connector_file="self_connector", local=True
)
models.SiteSettings.objects.create()
def test_isbn_json_response(self):
@ -48,4 +48,4 @@ class IsbnViews(TestCase):
data = json.loads(response.content)
self.assertEqual(len(data), 1)
self.assertEqual(data[0]["title"], "Test Book")
self.assertEqual(data[0]["key"], "https://%s/book/%d" % (DOMAIN, self.book.id))
self.assertEqual(data[0]["key"], f"https://{DOMAIN}/book/{self.book.id}")

View file

@ -17,22 +17,25 @@ class ListViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
work = models.Work.objects.create(title="Work")
self.book = models.Edition.objects.create(
title="Example Edition",
@ -90,6 +93,52 @@ class ListViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_saved_lists_page(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.SavedLists.as_view()
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
booklist = models.List.objects.create(
name="Public list", user=self.local_user
)
models.List.objects.create(
name="Private list", privacy="direct", user=self.local_user
)
self.local_user.saved_lists.add(booklist)
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
self.assertEqual(result.context_data["lists"].object_list, [booklist])
def test_saved_lists_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.SavedLists.as_view()
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.List.objects.create(name="Public list", user=self.local_user)
models.List.objects.create(
name="Private list", privacy="direct", user=self.local_user
)
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
self.assertEqual(len(result.context_data["lists"].object_list), 0)
def test_saved_lists_page_logged_out(self):
"""logged out saved lists"""
view = views.SavedLists.as_view()
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request)
self.assertEqual(result.status_code, 302)
def test_lists_create(self):
"""create list view"""
view = views.Lists.as_view()
@ -327,15 +376,8 @@ class ListViews(TestCase):
def test_user_lists_page_logged_out(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.UserLists.as_view()
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.List.objects.create(name="Public list", user=self.local_user)
models.List.objects.create(
name="Private list", privacy="direct", user=self.local_user
)
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request, self.local_user.username)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 302)

View file

@ -3,6 +3,7 @@ import json
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import PermissionDenied
from django.test import TestCase
from django.test.client import RequestFactory
@ -15,22 +16,25 @@ class ListActionViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com",
"rat@rat.com",
"ratword",
local=True,
localname="rat",
remote_id="https://example.com/users/rat",
)
work = models.Work.objects.create(title="Work")
self.book = models.Edition.objects.create(
@ -65,6 +69,44 @@ class ListActionViews(TestCase):
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_delete_list(self):
"""delete an entire list"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=True,
order=1,
)
models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book_two,
approved=False,
order=2,
)
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.delete_list(request, self.list.id)
activity = json.loads(mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], self.list.remote_id)
self.assertEqual(activity["object"]["type"], "BookList")
self.assertEqual(mock.call_count, 1)
self.assertFalse(models.List.objects.exists())
self.assertFalse(models.ListItem.objects.exists())
def test_delete_list_permission_denied(self):
"""delete an entire list"""
request = self.factory.post("")
request.user = self.rat
with self.assertRaises(PermissionDenied):
views.delete_list(request, self.list.id)
def test_curate_approve(self):
"""approve a pending item"""
view = views.Curate.as_view()
@ -526,5 +568,6 @@ class ListActionViews(TestCase):
)
request.user = self.rat
views.list.remove_book(request, self.list.id)
with self.assertRaises(PermissionDenied):
views.list.remove_book(request, self.list.id)
self.assertTrue(self.list.listitem_set.exists())

View file

@ -1,10 +1,12 @@
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm import views
from bookwyrm.tests.validate_html import validate_html
class NotificationViews(TestCase):
@ -13,23 +15,63 @@ class NotificationViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.status = models.Status.objects.create(
content="hi",
user=self.local_user,
)
models.SiteSettings.objects.create()
def test_notifications_page(self):
def test_notifications_page_empty(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.Notifications.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_notifications_page_notifications(self):
"""there are so many views, this just makes sure it LOADS"""
models.Notification.objects.create(
user=self.local_user,
notification_type="FAVORITE",
related_status=self.status,
)
models.Notification.objects.create(
user=self.local_user,
notification_type="BOOST",
related_status=self.status,
)
models.Notification.objects.create(
user=self.local_user,
notification_type="MENTION",
related_status=self.status,
)
self.status.reply_parent = self.status
self.status.save(broadcast=False)
models.Notification.objects.create(
user=self.local_user,
notification_type="REPLY",
related_status=self.status,
)
view = views.Notifications.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_clear_notifications(self):

View file

@ -18,14 +18,17 @@ class OutboxView(TestCase):
def setUp(self):
"""we'll need some data"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
@ -55,7 +58,7 @@ class OutboxView(TestCase):
def test_outbox_privacy(self, _):
"""don't show dms et cetera in outbox"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
models.Status.objects.create(
content="PRIVATE!!", user=self.local_user, privacy="direct"
)
@ -78,7 +81,7 @@ class OutboxView(TestCase):
def test_outbox_filter(self, _):
"""if we only care about reviews, only get reviews"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
models.Review.objects.create(
content="look at this",
name="hi",
@ -104,7 +107,7 @@ class OutboxView(TestCase):
def test_outbox_bookwyrm_request_true(self, _):
"""should differentiate between bookwyrm and outside requests"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
models.Review.objects.create(
name="hi",
content="look at this",
@ -122,7 +125,7 @@ class OutboxView(TestCase):
def test_outbox_bookwyrm_request_false(self, _):
"""should differentiate between bookwyrm and outside requests"""
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
models.Review.objects.create(
name="hi",
content="look at this",

View file

@ -8,21 +8,27 @@ from django.utils import timezone
from bookwyrm import models, views
@patch("bookwyrm.activitystreams.ActivityStream.add_status")
@patch("bookwyrm.activitystreams.add_status_task.delay")
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
class ReadingViews(TestCase):
"""viewing and creating statuses"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -40,7 +46,7 @@ class ReadingViews(TestCase):
parent_work=self.work,
)
def test_start_reading(self, _):
def test_start_reading(self, *_):
"""begin a book"""
shelf = self.local_user.shelf_set.get(identifier=models.Shelf.READING)
self.assertFalse(shelf.books.exists())
@ -52,6 +58,9 @@ class ReadingViews(TestCase):
"post-status": True,
"privacy": "followers",
"start_date": "2020-01-05",
"book": self.book.id,
"mention_books": self.book.id,
"user": self.local_user.id,
},
)
request.user = self.local_user
@ -71,7 +80,48 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.user, self.local_user)
self.assertEqual(readthrough.book, self.book)
def test_start_reading_reshelf(self, _):
def test_start_reading_with_comment(self, *_):
"""begin a book"""
shelf = self.local_user.shelf_set.get(identifier=models.Shelf.READING)
self.assertFalse(shelf.books.exists())
self.assertFalse(models.Status.objects.exists())
request = self.factory.post(
"",
{
"post-status": True,
"privacy": "followers",
"start_date": "2020-01-05",
"content": "hello hello",
"book": self.book.id,
"mention_books": self.book.id,
"user": self.local_user.id,
"reading_status": "reading",
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.ReadingStatus.as_view()(request, "start", self.book.id)
self.assertEqual(shelf.books.get(), self.book)
status = models.Comment.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.book, self.book)
self.assertFalse(status.mention_books.exists())
self.assertEqual(status.privacy, "followers")
self.assertEqual(status.content, "<p>hello hello</p>")
self.assertEqual(status.reading_status, "reading")
readthrough = models.ReadThrough.objects.get()
self.assertIsNotNone(readthrough.start_date)
self.assertIsNone(readthrough.finish_date)
self.assertEqual(readthrough.user, self.local_user)
self.assertEqual(readthrough.book, self.book)
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
def test_start_reading_reshelve(self, *_):
"""begin a book"""
to_read_shelf = self.local_user.shelf_set.get(identifier=models.Shelf.TO_READ)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
@ -91,7 +141,7 @@ class ReadingViews(TestCase):
self.assertFalse(to_read_shelf.books.exists())
self.assertEqual(shelf.books.get(), self.book)
def test_finish_reading(self, _):
def test_finish_reading(self, *_):
"""begin a book"""
shelf = self.local_user.shelf_set.get(identifier=models.Shelf.READ_FINISHED)
self.assertFalse(shelf.books.exists())
@ -105,7 +155,8 @@ class ReadingViews(TestCase):
{
"post-status": True,
"privacy": "followers",
"finish_date": "2020-01-07",
"start_date": readthrough.start_date,
"finish_date": timezone.now().isoformat(),
"id": readthrough.id,
},
)
@ -127,7 +178,7 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.user, self.local_user)
self.assertEqual(readthrough.book, self.book)
def test_edit_readthrough(self, _):
def test_edit_readthrough(self, *_):
"""adding dates to an ongoing readthrough"""
start = timezone.make_aware(dateutil.parser.parse("2021-01-03"))
readthrough = models.ReadThrough.objects.create(
@ -154,7 +205,7 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.finish_date.day, 7)
self.assertEqual(readthrough.book, self.book)
def test_delete_readthrough(self, _):
def test_delete_readthrough(self, *_):
"""remove a readthrough"""
readthrough = models.ReadThrough.objects.create(
book=self.book, user=self.local_user
@ -171,7 +222,7 @@ class ReadingViews(TestCase):
views.delete_readthrough(request)
self.assertFalse(models.ReadThrough.objects.filter(id=readthrough.id).exists())
def test_create_readthrough(self, _):
def test_create_readthrough(self, *_):
"""adding new read dates"""
request = self.factory.post(
"",
@ -194,3 +245,42 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.finish_date.day, 7)
self.assertEqual(readthrough.book, self.book)
self.assertEqual(readthrough.user, self.local_user)
def test_update_progress_comment(self, *_):
"""update progress with commentary"""
readthrough = models.ReadThrough.objects.create(
user=self.local_user, start_date=timezone.now(), book=self.book
)
request = self.factory.post(
"",
{
"post-status": True,
"privacy": "followers",
"start_date": "2020-01-05",
"content": "hello hello",
"book": self.book.id,
"mention_books": self.book.id,
"user": self.local_user.id,
"id": readthrough.id,
"progress": 23,
"progress_mode": "PCT",
},
)
request.user = self.local_user
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.update_progress(request, self.book.id)
status = models.Comment.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.book, self.book)
self.assertFalse(status.mention_books.exists())
self.assertEqual(status.privacy, "followers")
self.assertEqual(status.content, "<p>hello hello</p>")
self.assertIsNone(status.reading_status)
self.assertEqual(status.progress, 23)
self.assertEqual(status.progress_mode, "PCT")
self.assertIsNotNone(readthrough.start_date)
self.assertIsNone(readthrough.finish_date)
self.assertEqual(readthrough.user, self.local_user)
self.assertEqual(readthrough.book, self.book)

View file

@ -7,7 +7,11 @@ from django.utils import timezone
from bookwyrm import models
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.add_book_statuses_task.delay")
@patch("bookwyrm.activitystreams.remove_book_statuses_task.delay")
class ReadThrough(TestCase):
"""readthrough tests"""
@ -21,14 +25,18 @@ class ReadThrough(TestCase):
title="Example Edition", parent_work=self.work
)
self.user = models.User.objects.create_user(
"cinco", "cinco@example.com", "seissiete", local=True, localname="cinco"
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.user = models.User.objects.create_user(
"cinco", "cinco@example.com", "seissiete", local=True, localname="cinco"
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.client.force_login(self.user)
def test_create_basic_readthrough(self, delay_mock):
@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay")
def test_create_basic_readthrough(self, *_):
"""A basic readthrough doesn't create a progress update"""
self.assertEqual(self.edition.readthrough_set.count(), 0)
@ -47,9 +55,9 @@ class ReadThrough(TestCase):
)
self.assertEqual(readthroughs[0].progress, None)
self.assertEqual(readthroughs[0].finish_date, None)
self.assertEqual(delay_mock.call_count, 1)
def test_create_progress_readthrough(self, delay_mock):
@patch("bookwyrm.activitystreams.remove_user_statuses_task.delay")
def test_create_progress_readthrough(self, *_):
"""a readthrough with progress"""
self.assertEqual(self.edition.readthrough_set.count(), 0)
@ -84,8 +92,6 @@ class ReadThrough(TestCase):
self.assertEqual(progress_updates[0].progress, 100)
# Edit doesn't publish anything
self.assertEqual(delay_mock.call_count, 1)
self.client.post(
"/delete-readthrough",
{

View file

@ -1,5 +1,4 @@
""" testing import """
from unittest.mock import patch
from django.test import RequestFactory, TestCase
@ -7,58 +6,79 @@ from bookwyrm import models
from bookwyrm.views import rss_feed
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
@patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream")
@patch("bookwyrm.activitystreams.add_status_task.delay")
class RssFeedView(TestCase):
"""rss feed behaves as expected"""
def setUp(self):
"""test data"""
self.site = models.SiteSettings.objects.create()
self.user = models.User.objects.create_user(
"rss_user", "rss@test.rss", "password", local=True
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"rss_user", "rss@test.rss", "password", local=True
)
work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
self.review = models.Review.objects.create(
name="Review name",
content="test content",
rating=3,
user=self.user,
book=self.book,
)
self.quote = models.Quotation.objects.create(
quote="a sickening sense",
content="test content",
user=self.user,
book=self.book,
)
self.generatednote = models.GeneratedNote.objects.create(
content="test content", user=self.user
)
self.factory = RequestFactory()
@patch("bookwyrm.activitystreams.ActivityStream.get_activity_stream")
def test_rss_feed(self, _):
models.SiteSettings.objects.create()
def test_rss_empty(self, *_):
"""load an rss feed"""
view = rss_feed.RssFeed()
request = self.factory.get("/user/rss_user/rss")
request.user = self.user
with patch("bookwyrm.models.SiteSettings.objects.get") as site:
site.return_value = self.site
result = view(request, username=self.user.username)
request.user = self.local_user
result = view(request, username=self.local_user.username)
self.assertEqual(result.status_code, 200)
self.assertIn(b"Status updates from rss_user", result.content)
def test_rss_comment(self, *_):
"""load an rss feed"""
models.Comment.objects.create(
content="comment test content",
user=self.local_user,
book=self.book,
)
view = rss_feed.RssFeed()
request = self.factory.get("/user/rss_user/rss")
request.user = self.local_user
result = view(request, username=self.local_user.username)
self.assertEqual(result.status_code, 200)
self.assertIn(b"Example Edition", result.content)
def test_rss_review(self, *_):
"""load an rss feed"""
models.Review.objects.create(
name="Review name",
content="test content",
rating=3,
user=self.local_user,
book=self.book,
)
view = rss_feed.RssFeed()
request = self.factory.get("/user/rss_user/rss")
request.user = self.local_user
result = view(request, username=self.local_user.username)
self.assertEqual(result.status_code, 200)
def test_rss_quotation(self, *_):
"""load an rss feed"""
models.Quotation.objects.create(
quote="a sickening sense",
content="test content",
user=self.local_user,
book=self.book,
)
view = rss_feed.RssFeed()
request = self.factory.get("/user/rss_user/rss")
request.user = self.local_user
result = view(request, username=self.local_user.username)
self.assertEqual(result.status_code, 200)
self.assertIn(b"Status updates from rss_user", result.content)
self.assertIn(b"a sickening sense", result.content)
self.assertIn(b"Example Edition", result.content)

View file

@ -1,5 +1,6 @@
""" test for app action functionality """
import json
import pathlib
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
@ -7,9 +8,9 @@ from django.http import JsonResponse
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
import responses
from bookwyrm import models, views
from bookwyrm.connectors import abstract_connector
from bookwyrm.settings import DOMAIN
@ -19,29 +20,28 @@ class Views(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
self.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title="Test Book",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
models.Connector.objects.create(
identifier="self", connector_file="self_connector", local=True
)
models.SiteSettings.objects.create()
def test_search_json_response(self):
"""searches local data only and returns book data in json format"""
view = views.Search.as_view()
# we need a connector for this, sorry
request = self.factory.get("", {"q": "Test Book"})
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = True
@ -51,7 +51,7 @@ class Views(TestCase):
data = json.loads(response.content)
self.assertEqual(len(data), 1)
self.assertEqual(data[0]["title"], "Test Book")
self.assertEqual(data[0]["key"], "https://%s/book/%d" % (DOMAIN, self.book.id))
self.assertEqual(data[0]["key"], f"https://{DOMAIN}/book/{self.book.id}")
def test_search_no_query(self):
"""just the search page"""
@ -64,28 +64,11 @@ class Views(TestCase):
self.assertIsInstance(response, TemplateResponse)
response.render()
@responses.activate
def test_search_books(self):
"""searches remote connectors"""
view = views.Search.as_view()
class TestConnector(abstract_connector.AbstractMinimalConnector):
"""nothing added here"""
def format_search_result(self, search_result):
pass
def get_or_create_book(self, remote_id):
pass
def parse_search_data(self, data):
pass
def format_isbn_search_result(self, search_result):
return search_result
def parse_isbn_search_data(self, data):
return data
models.Connector.objects.create(
identifier="example.com",
connector_file="openlibrary",
@ -94,26 +77,40 @@ class Views(TestCase):
covers_url="https://example.com/covers",
search_url="https://example.com/search?q=",
)
connector = TestConnector("example.com")
search_result = abstract_connector.SearchResult(
key="http://www.example.com/book/1",
title="Gideon the Ninth",
author="Tamsyn Muir",
year="2019",
connector=connector,
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_search.json")
search_data = json.loads(datafile.read_bytes())
responses.add(
responses.GET, "https://example.com/search?q=Test%20Book", json=search_data
)
request = self.factory.get("", {"q": "Test Book", "remote": True})
request.user = self.local_user
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = False
with patch("bookwyrm.connectors.connector_manager.search") as manager:
manager.return_value = [search_result]
response = view(request)
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
self.assertEqual(response.context_data["results"][0].title, "Gideon the Ninth")
connector_results = response.context_data["results"]
self.assertEqual(len(connector_results), 2)
self.assertEqual(connector_results[0]["results"][0].title, "Test Book")
self.assertEqual(
connector_results[1]["results"][0].title,
"This Is How You Lose the Time War",
)
# don't search remote
request = self.factory.get("", {"q": "Test Book", "remote": True})
anonymous_user = AnonymousUser
anonymous_user.is_authenticated = False
request.user = anonymous_user
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = False
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
connector_results = response.context_data["results"]
self.assertEqual(len(connector_results), 1)
self.assertEqual(connector_results[0]["results"][0].title, "Test Book")
def test_search_users(self):
"""searches remote connectors"""

View file

@ -1,14 +1,19 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.core.exceptions import PermissionDenied
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
from bookwyrm.settings import DOMAIN
from bookwyrm.tests.validate_html import validate_html
# pylint: disable=invalid-name
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
@patch("bookwyrm.activitystreams.remove_status_task.delay")
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class StatusViews(TestCase):
"""viewing and creating statuses"""
@ -16,14 +21,17 @@ class StatusViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
with patch("bookwyrm.models.user.set_remote_server"):
self.remote_user = models.User.objects.create_user(
"rat",
@ -43,7 +51,7 @@ class StatusViews(TestCase):
)
models.SiteSettings.objects.create()
def test_handle_status(self, _):
def test_create_status_comment(self, *_):
"""create a status"""
view = views.CreateStatus.as_view()
form = forms.CommentForm(
@ -57,25 +65,24 @@ class StatusViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
view(request, "comment")
self.assertTrue(redis_mock.called)
view(request, "comment")
status = models.Comment.objects.get()
self.assertEqual(status.raw_content, "hi")
self.assertEqual(status.content, "<p>hi</p>")
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.book, self.book)
self.assertIsNone(status.edited_date)
def test_handle_status_reply(self, _):
def test_create_status_reply(self, *_):
"""create a status in reply to an existing status"""
view = views.CreateStatus.as_view()
user = models.User.objects.create_user(
"rat", "rat@rat.com", "password", local=True
)
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
parent = models.Status.objects.create(
content="parent status", user=self.local_user
)
parent = models.Status.objects.create(
content="parent status", user=self.local_user
)
form = forms.ReplyForm(
{
"content": "hi",
@ -87,20 +94,18 @@ class StatusViews(TestCase):
request = self.factory.post("", form.data)
request.user = user
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
view(request, "reply")
self.assertTrue(redis_mock.called)
view(request, "reply")
status = models.Status.objects.get(user=user)
self.assertEqual(status.content, "<p>hi</p>")
self.assertEqual(status.user, user)
self.assertEqual(models.Notification.objects.get().user, self.local_user)
def test_handle_status_mentions(self, _):
def test_create_status_mentions(self, *_):
"""@mention a user in a post"""
view = views.CreateStatus.as_view()
user = models.User.objects.create_user(
"rat@%s" % DOMAIN,
f"rat@{DOMAIN}",
"rat@rat.com",
"password",
local=True,
@ -117,18 +122,16 @@ class StatusViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
view(request, "comment")
self.assertTrue(redis_mock.called)
view(request, "comment")
status = models.Status.objects.get()
self.assertEqual(list(status.mention_users.all()), [user])
self.assertEqual(models.Notification.objects.get().user, user)
self.assertEqual(
status.content, '<p>hi <a href="%s">@rat</a></p>' % user.remote_id
status.content, f'<p>hi <a href="{user.remote_id}">@rat</a></p>'
)
def test_handle_status_reply_with_mentions(self, _):
def test_create_status_reply_with_mentions(self, *_):
"""reply to a post with an @mention'ed user"""
view = views.CreateStatus.as_view()
user = models.User.objects.create_user(
@ -145,9 +148,7 @@ class StatusViews(TestCase):
request = self.factory.post("", form.data)
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
view(request, "comment")
self.assertTrue(redis_mock.called)
view(request, "comment")
status = models.Status.objects.get()
form = forms.ReplyForm(
@ -161,9 +162,7 @@ class StatusViews(TestCase):
request = self.factory.post("", form.data)
request.user = user
with patch("bookwyrm.activitystreams.ActivityStream.add_status") as redis_mock:
view(request, "reply")
self.assertTrue(redis_mock.called)
view(request, "reply")
reply = models.Status.replies(status).first()
self.assertEqual(reply.content, "<p>right</p>")
@ -172,77 +171,16 @@ class StatusViews(TestCase):
self.assertFalse(self.remote_user in reply.mention_users.all())
self.assertTrue(self.local_user in reply.mention_users.all())
def test_delete_and_redraft(self, _):
"""delete and re-draft a status"""
view = views.DeleteAndRedraft.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
status = models.Comment.objects.create(
content="hi", book=self.book, user=self.local_user
)
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as mock:
result = view(request, status.id)
self.assertTrue(mock.called)
result.render()
# make sure it was deleted
status.refresh_from_db()
self.assertTrue(status.deleted)
def test_delete_and_redraft_invalid_status_type_rating(self, _):
"""you can't redraft generated statuses"""
view = views.DeleteAndRedraft.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
status = models.ReviewRating.objects.create(
book=self.book, rating=2.0, user=self.local_user
)
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as mock:
result = view(request, status.id)
self.assertFalse(mock.called)
self.assertEqual(result.status_code, 400)
status.refresh_from_db()
self.assertFalse(status.deleted)
def test_delete_and_redraft_invalid_status_type_generated_note(self, _):
"""you can't redraft generated statuses"""
view = views.DeleteAndRedraft.as_view()
request = self.factory.post("")
request.user = self.local_user
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
status = models.GeneratedNote.objects.create(
content="hi", user=self.local_user
)
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as mock:
result = view(request, status.id)
self.assertFalse(mock.called)
self.assertEqual(result.status_code, 400)
status.refresh_from_db()
self.assertFalse(status.deleted)
def test_find_mentions(self, _):
def test_find_mentions(self, *_):
"""detect and look up @ mentions of users"""
user = models.User.objects.create_user(
"nutria@%s" % DOMAIN,
f"nutria@{DOMAIN}",
"nutria@nutria.com",
"password",
local=True,
localname="nutria",
)
self.assertEqual(user.username, "nutria@%s" % DOMAIN)
self.assertEqual(user.username, f"nutria@{DOMAIN}")
self.assertEqual(
list(views.status.find_mentions("@nutria"))[0], ("@nutria", user)
@ -275,34 +213,68 @@ class StatusViews(TestCase):
self.assertEqual(list(views.status.find_mentions("@beep@beep.com")), [])
self.assertEqual(
list(views.status.find_mentions("@nutria@%s" % DOMAIN))[0],
("@nutria@%s" % DOMAIN, user),
list(views.status.find_mentions(f"@nutria@{DOMAIN}"))[0],
(f"@nutria@{DOMAIN}", user),
)
def test_format_links(self, _):
def test_format_links_simple_url(self, *_):
"""find and format urls into a tags"""
url = "http://www.fish.com/"
self.assertEqual(
views.status.format_links(url), '<a href="%s">www.fish.com/</a>' % url
views.status.format_links(url), f'<a href="{url}">www.fish.com/</a>'
)
self.assertEqual(
views.status.format_links("(%s)" % url),
'(<a href="%s">www.fish.com/</a>)' % url,
views.status.format_links(f"({url})"),
f'(<a href="{url}">www.fish.com/</a>)',
)
def test_format_links_paragraph_break(self, *_):
"""find and format urls into a tags"""
url = """okay
http://www.fish.com/"""
self.assertEqual(
views.status.format_links(url),
'okay\n\n<a href="http://www.fish.com/">www.fish.com/</a>',
)
def test_format_links_parens(self, *_):
"""find and format urls into a tags"""
url = "http://www.fish.com/"
self.assertEqual(
views.status.format_links(f"({url})"),
f'(<a href="{url}">www.fish.com/</a>)',
)
def test_format_links_special_chars(self, *_):
"""find and format urls into a tags"""
url = "https://archive.org/details/dli.granth.72113/page/n25/mode/2up"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">'
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>" % url,
f'<a href="{url}">'
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>",
)
url = "https://openlibrary.org/search?q=arkady+strugatsky&mode=everything"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">openlibrary.org/search'
"?q=arkady+strugatsky&mode=everything</a>" % url,
f'<a href="{url}">openlibrary.org/search'
"?q=arkady+strugatsky&mode=everything</a>",
)
url = "https://tech.lgbt/@bookwyrm"
self.assertEqual(
views.status.format_links(url), f'<a href="{url}">tech.lgbt/@bookwyrm</a>'
)
url = "https://users.speakeasy.net/~lion/nb/book.pdf"
self.assertEqual(
views.status.format_links(url),
f'<a href="{url}">users.speakeasy.net/~lion/nb/book.pdf</a>',
)
url = "https://pkm.one/#/page/The%20Book%20launched%20a%201000%20Note%20apps"
self.assertEqual(
views.status.format_links(url), f'<a href="{url}">{url[8:]}</a>'
)
def test_to_markdown(self, _):
def test_to_markdown(self, *_):
"""this is mostly handled in other places, but nonetheless"""
text = "_hi_ and http://fish.com is <marquee>rad</marquee>"
result = views.status.to_markdown(text)
@ -311,7 +283,7 @@ class StatusViews(TestCase):
'<p><em>hi</em> and <a href="http://fish.com">fish.com</a> ' "is rad</p>",
)
def test_to_markdown_detect_url(self, _):
def test_to_markdown_detect_url(self, *_):
"""this is mostly handled in other places, but nonetheless"""
text = "http://fish.com/@hello#okay"
result = views.status.to_markdown(text)
@ -320,24 +292,22 @@ class StatusViews(TestCase):
'<p><a href="http://fish.com/@hello#okay">fish.com/@hello#okay</a></p>',
)
def test_to_markdown_link(self, _):
def test_to_markdown_link(self, *_):
"""this is mostly handled in other places, but nonetheless"""
text = "[hi](http://fish.com) is <marquee>rad</marquee>"
result = views.status.to_markdown(text)
self.assertEqual(result, '<p><a href="http://fish.com">hi</a> ' "is rad</p>")
def test_handle_delete_status(self, mock):
def test_delete_status(self, mock, *_):
"""marks a status as deleted"""
view = views.DeleteStatus.as_view()
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
request = self.factory.post("")
request.user = self.local_user
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as redis_mock:
with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock:
view(request, status.id)
self.assertTrue(redis_mock.called)
activity = json.loads(mock.call_args_list[1][0][1])
@ -346,33 +316,32 @@ class StatusViews(TestCase):
status.refresh_from_db()
self.assertTrue(status.deleted)
def test_handle_delete_status_permission_denied(self, _):
def test_delete_status_permission_denied(self, *_):
"""marks a status as deleted"""
view = views.DeleteStatus.as_view()
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
request = self.factory.post("")
request.user = self.remote_user
view(request, status.id)
with self.assertRaises(PermissionDenied):
view(request, status.id)
status.refresh_from_db()
self.assertFalse(status.deleted)
def test_handle_delete_status_moderator(self, mock):
def test_delete_status_moderator(self, mock, *_):
"""marks a status as deleted"""
view = views.DeleteStatus.as_view()
with patch("bookwyrm.activitystreams.ActivityStream.add_status"):
with patch("bookwyrm.activitystreams.add_status_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
request = self.factory.post("")
request.user = self.remote_user
request.user.is_superuser = True
with patch(
"bookwyrm.activitystreams.ActivityStream.remove_object_from_related_stores"
) as redis_mock:
with patch("bookwyrm.activitystreams.remove_status_task.delay") as redis_mock:
view(request, status.id)
self.assertTrue(redis_mock.called)
activity = json.loads(mock.call_args_list[1][0][1])
@ -380,3 +349,75 @@ class StatusViews(TestCase):
self.assertEqual(activity["object"]["type"], "Tombstone")
status.refresh_from_db()
self.assertTrue(status.deleted)
def test_edit_status_get(self, *_):
"""load the edit status view"""
view = views.EditStatus.as_view()
status = models.Comment.objects.create(
content="status", user=self.local_user, book=self.book
)
request = self.factory.get("")
request.user = self.local_user
result = view(request, status.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_status_get_reply(self, *_):
"""load the edit status view"""
view = views.EditStatus.as_view()
parent = models.Comment.objects.create(
content="parent status", user=self.local_user, book=self.book
)
status = models.Status.objects.create(
content="reply", user=self.local_user, reply_parent=parent
)
request = self.factory.get("")
request.user = self.local_user
result = view(request, status.id)
validate_html(result.render())
self.assertEqual(result.status_code, 200)
def test_edit_status_success(self, mock, *_):
"""update an existing status"""
status = models.Status.objects.create(content="status", user=self.local_user)
self.assertIsNone(status.edited_date)
view = views.CreateStatus.as_view()
form = forms.CommentForm(
{
"content": "hi",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
request.user = self.local_user
view(request, "comment", existing_status_id=status.id)
activity = json.loads(mock.call_args_list[1][0][1])
self.assertEqual(activity["type"], "Update")
self.assertEqual(activity["object"]["id"], status.remote_id)
status.refresh_from_db()
self.assertEqual(status.content, "<p>hi</p>")
self.assertIsNotNone(status.edited_date)
def test_edit_status_permission_denied(self, *_):
"""update an existing status"""
status = models.Status.objects.create(content="status", user=self.local_user)
view = views.CreateStatus.as_view()
form = forms.CommentForm(
{
"content": "hi",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
request.user = self.remote_user
with self.assertRaises(PermissionDenied):
view(request, "comment", existing_status_id=status.id)

View file

@ -15,13 +15,16 @@ class UpdateViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_get_notification_count(self):

View file

@ -9,6 +9,7 @@ from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.activitypub import ActivitypubResponse
from bookwyrm.tests.validate_html import validate_html
class UserViews(TestCase):
@ -17,18 +18,25 @@ class UserViews(TestCase):
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
self.book = models.Edition.objects.create(
title="test", parent_work=models.Work.objects.create(title="test work")
)
self.rat = models.User.objects.create_user(
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
self.book = models.Edition.objects.create(title="test")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch(
"bookwyrm.suggested_users.rerank_suggestions_task.delay"
), patch("bookwyrm.activitystreams.add_book_statuses_task.delay"):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
@ -48,7 +56,7 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
request.user = self.anonymous_user
@ -56,7 +64,7 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:
@ -85,7 +93,7 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:
@ -94,7 +102,9 @@ class UserViews(TestCase):
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_followers_page_blocked(self):
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@patch("bookwyrm.activitystreams.populate_stream_task.delay")
def test_followers_page_blocked(self, *_):
"""there are so many views, this just makes sure it LOADS"""
view = views.Followers.as_view()
request = self.factory.get("")
@ -114,7 +124,7 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
validate_html(result.render())
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:

Some files were not shown because too many files have changed in this diff Show more