Merge branch 'main' into create-book

This commit is contained in:
Mouse Reeve
2021-03-08 10:07:02 -08:00
committed by GitHub
201 changed files with 10253 additions and 8555 deletions

View File

@@ -7,19 +7,18 @@ from bookwyrm import models
class Author(TestCase):
def setUp(self):
self.book = models.Edition.objects.create(
title='Example Edition',
remote_id='https://example.com/book/1',
title="Example Edition",
remote_id="https://example.com/book/1",
)
self.author = models.Author.objects.create(
name='Author fullname',
aliases=['One', 'Two'],
bio='bio bio bio',
name="Author fullname",
aliases=["One", "Two"],
bio="bio bio bio",
)
def test_serialize_model(self):
activity = self.author.to_activity()
self.assertEqual(activity['id'], self.author.remote_id)
self.assertIsInstance(activity['aliases'], list)
self.assertEqual(activity['aliases'], ['One', 'Two'])
self.assertEqual(activity['name'], 'Author fullname')
self.assertEqual(activity["id"], self.author.remote_id)
self.assertIsInstance(activity["aliases"], list)
self.assertEqual(activity["aliases"], ["One", "Two"])
self.assertEqual(activity["name"], "Author fullname")

View File

@@ -1,4 +1,4 @@
''' tests the base functionality for activitypub dataclasses '''
""" tests the base functionality for activitypub dataclasses """
from io import BytesIO
import json
import pathlib
@@ -10,231 +10,229 @@ from PIL import Image
import responses
from bookwyrm import activitypub
from bookwyrm.activitypub.base_activity import ActivityObject, \
resolve_remote_id, set_related_field
from bookwyrm.activitypub.base_activity import (
ActivityObject,
resolve_remote_id,
set_related_field,
)
from bookwyrm.activitypub import ActivitySerializerError
from bookwyrm import models
class BaseActivity(TestCase):
''' the super class for model-linked activitypub dataclasses '''
""" the super class for model-linked activitypub dataclasses """
def setUp(self):
''' we're probably going to re-use this so why copy/paste '''
""" 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')
self.user.remote_id = 'http://example.com/a/b'
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
self.user.remote_id = "http://example.com/a/b"
self.user.save(broadcast=False)
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ap_user.json'
)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
self.userdata = json.loads(datafile.read_bytes())
# don't try to load the user icon
del self.userdata['icon']
del self.userdata["icon"]
image_file = pathlib.Path(__file__).parent.joinpath(
'../../static/images/default_avi.jpg')
"../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
image.save(output, format=image.format)
self.image_data = output.getvalue()
def test_init(self):
''' simple successfuly init '''
instance = ActivityObject(id='a', type='b')
self.assertTrue(hasattr(instance, 'id'))
self.assertTrue(hasattr(instance, 'type'))
""" simple successfuly init """
instance = ActivityObject(id="a", type="b")
self.assertTrue(hasattr(instance, "id"))
self.assertTrue(hasattr(instance, "type"))
def test_init_missing(self):
''' init with missing required params '''
""" init with missing required params """
with self.assertRaises(ActivitySerializerError):
ActivityObject()
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'))
""" 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):
''' replace an existing required field with a default field '''
""" replace an existing required field with a default field """
@dataclass(init=False)
class TestClass(ActivityObject):
''' test class with default field '''
type: str = 'TestObject'
""" test class with default field """
instance = TestClass(id='a')
self.assertEqual(instance.id, 'a')
self.assertEqual(instance.type, 'TestObject')
type: str = "TestObject"
instance = TestClass(id="a")
self.assertEqual(instance.id, "a")
self.assertEqual(instance.type, "TestObject")
def test_serialize(self):
''' simple function for converting dataclass to dict '''
instance = ActivityObject(id='a', type='b')
""" simple function for converting dataclass to dict """
instance = ActivityObject(id="a", type="b")
serialized = instance.serialize()
self.assertIsInstance(serialized, dict)
self.assertEqual(serialized['id'], 'a')
self.assertEqual(serialized['type'], 'b')
self.assertEqual(serialized["id"], "a")
self.assertEqual(serialized["type"], "b")
@responses.activate
def test_resolve_remote_id(self):
''' look up or load remote data '''
""" look up or load remote data """
# existing item
result = resolve_remote_id('http://example.com/a/b', model=models.User)
result = resolve_remote_id("http://example.com/a/b", model=models.User)
self.assertEqual(result, self.user)
# remote item
responses.add(
responses.GET,
'https://example.com/user/mouse',
"https://example.com/user/mouse",
json=self.userdata,
status=200)
status=200,
)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
result = resolve_remote_id(
'https://example.com/user/mouse', model=models.User)
"https://example.com/user/mouse", model=models.User
)
self.assertIsInstance(result, models.User)
self.assertEqual(result.remote_id, 'https://example.com/user/mouse')
self.assertEqual(result.name, 'MOUSE?? MOUSE!!')
self.assertEqual(result.remote_id, "https://example.com/user/mouse")
self.assertEqual(result.name, "MOUSE?? MOUSE!!")
def test_to_model_invalid_model(self):
''' catch mismatch between activity type and model type '''
instance = ActivityObject(id='a', type='b')
""" 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):
''' update an image field '''
""" update an image field """
activity = activitypub.Person(
id=self.user.remote_id,
name='New Name',
preferredUsername='mouse',
inbox='http://www.com/',
outbox='http://www.com/',
followers='',
summary='',
publicKey={
'id': 'hi',
'owner': self.user.remote_id,
'publicKeyPem': 'hi'},
name="New Name",
preferredUsername="mouse",
inbox="http://www.com/",
outbox="http://www.com/",
followers="",
summary="",
publicKey={"id": "hi", "owner": self.user.remote_id, "publicKeyPem": "hi"},
endpoints={},
icon={
'type': 'Image',
'url': 'http://www.example.com/image.jpg'
}
icon={"type": "Image", "url": "http://www.example.com/image.jpg"},
)
responses.add(
responses.GET,
'http://www.example.com/image.jpg',
"http://www.example.com/image.jpg",
body=self.image_data,
status=200)
status=200,
)
self.assertIsNone(self.user.avatar.name)
with self.assertRaises(ValueError):
self.user.avatar.file #pylint: disable=pointless-statement
self.user.avatar.file # pylint: disable=pointless-statement
# this would trigger a broadcast because it's a local user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
activity.to_model(model=models.User, instance=self.user)
self.assertIsNotNone(self.user.avatar.file)
self.assertEqual(self.user.name, 'New Name')
self.assertEqual(self.user.key_pair.public_key, 'hi')
self.assertEqual(self.user.name, "New Name")
self.assertEqual(self.user.key_pair.public_key, "hi")
def test_to_model_many_to_many(self):
''' annoying that these all need special handling '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" annoying that these all need special handling """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(
content='test status',
content="test status",
user=self.user,
)
book = models.Edition.objects.create(
title='Test Edition', remote_id='http://book.com/book')
title="Test Edition", remote_id="http://book.com/book"
)
update_data = activitypub.Note(
id=status.remote_id,
content=status.content,
attributedTo=self.user.remote_id,
published='hi',
published="hi",
to=[],
cc=[],
tag=[
{"type": "Mention", "name": "gerald", "href": "http://example.com/a/b"},
{
'type': 'Mention',
'name': 'gerald',
'href': 'http://example.com/a/b'
"type": "Edition",
"name": "gerald j. books",
"href": "http://book.com/book",
},
{
'type': 'Edition',
'name': 'gerald j. books',
'href': 'http://book.com/book'
},
]
],
)
update_data.to_model(model=models.Status, instance=status)
self.assertEqual(status.mention_users.first(), self.user)
self.assertEqual(status.mention_books.first(), book)
@responses.activate
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'):
"""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"):
status = models.Status.objects.create(
content='test status',
content="test status",
user=self.user,
)
update_data = activitypub.Note(
id=status.remote_id,
content=status.content,
attributedTo=self.user.remote_id,
published='hi',
published="hi",
to=[],
cc=[],
attachment=[{
'url': 'http://www.example.com/image.jpg',
'name': 'alt text',
'type': 'Image',
}],
attachment=[
{
"url": "http://www.example.com/image.jpg",
"name": "alt text",
"type": "Image",
}
],
)
responses.add(
responses.GET,
'http://www.example.com/image.jpg',
"http://www.example.com/image.jpg",
body=self.image_data,
status=200)
status=200,
)
# sets the celery task call to the function call
with patch(
'bookwyrm.activitypub.base_activity.set_related_field.delay'):
with patch('bookwyrm.models.status.Status.ignore_activity') \
as discarder:
with patch("bookwyrm.activitypub.base_activity.set_related_field.delay"):
with patch("bookwyrm.models.status.Status.ignore_activity") as discarder:
discarder.return_value = False
update_data.to_model(model=models.Status, instance=status)
self.assertIsNone(status.attachments.first())
@responses.activate
def test_set_related_field(self):
''' celery task to add back-references to created objects '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" celery task to add back-references to created objects """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(
content='test status',
content="test status",
user=self.user,
)
data = {
'url': 'http://www.example.com/image.jpg',
'name': 'alt text',
'type': 'Image',
"url": "http://www.example.com/image.jpg",
"name": "alt text",
"type": "Image",
}
responses.add(
responses.GET,
'http://www.example.com/image.jpg',
"http://www.example.com/image.jpg",
body=self.image_data,
status=200)
set_related_field(
'Image', 'Status', 'status', status.remote_id, data)
status=200,
)
set_related_field("Image", "Status", "status", status.remote_id, data)
self.assertIsInstance(status.attachments.first(), models.Image)
self.assertIsNotNone(status.attachments.first().image)

View File

@@ -9,23 +9,19 @@ from bookwyrm import activitypub, models
class Person(TestCase):
def setUp(self):
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ap_user.json'
)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
self.user_data = json.loads(datafile.read_bytes())
def test_load_user_data(self):
activity = activitypub.Person(**self.user_data)
self.assertEqual(activity.id, 'https://example.com/user/mouse')
self.assertEqual(activity.preferredUsername, 'mouse')
self.assertEqual(activity.type, 'Person')
self.assertEqual(activity.id, "https://example.com/user/mouse")
self.assertEqual(activity.preferredUsername, "mouse")
self.assertEqual(activity.type, "Person")
def test_user_to_model(self):
activity = activitypub.Person(**self.user_data)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
user = activity.to_model(model=models.User)
self.assertEqual(user.username, 'mouse@example.com')
self.assertEqual(user.remote_id, 'https://example.com/user/mouse')
self.assertEqual(user.username, "mouse@example.com")
self.assertEqual(user.remote_id, "https://example.com/user/mouse")
self.assertFalse(user.local)

View File

@@ -1,4 +1,4 @@
''' quotation activty object serializer class '''
""" quotation activty object serializer class """
import json
import pathlib
from unittest.mock import patch
@@ -8,43 +8,40 @@ from bookwyrm import activitypub, models
class Quotation(TestCase):
''' we have hecka ways to create statuses '''
""" we have hecka ways to create statuses """
def setUp(self):
''' model objects we'll need '''
with patch('bookwyrm.models.user.set_remote_server.delay'):
""" model objects we'll need """
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.user = models.User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword',
"mouse",
"mouse@mouse.mouse",
"mouseword",
local=False,
inbox='https://example.com/user/mouse/inbox',
outbox='https://example.com/user/mouse/outbox',
remote_id='https://example.com/user/mouse',
inbox="https://example.com/user/mouse/inbox",
outbox="https://example.com/user/mouse/outbox",
remote_id="https://example.com/user/mouse",
)
self.book = models.Edition.objects.create(
title='Example Edition',
remote_id='https://example.com/book/1',
)
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ap_quotation.json'
title="Example Edition",
remote_id="https://example.com/book/1",
)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_quotation.json")
self.status_data = json.loads(datafile.read_bytes())
def test_quotation_activity(self):
''' create a Quoteation ap object from json '''
""" create a Quoteation ap object from json """
quotation = activitypub.Quotation(**self.status_data)
self.assertEqual(quotation.type, 'Quotation')
self.assertEqual(
quotation.id, 'https://example.com/user/mouse/quotation/13')
self.assertEqual(quotation.content, 'commentary')
self.assertEqual(quotation.quote, 'quote body')
self.assertEqual(quotation.inReplyToBook, 'https://example.com/book/1')
self.assertEqual(
quotation.published, '2020-05-10T02:38:31.150343+00:00')
self.assertEqual(quotation.type, "Quotation")
self.assertEqual(quotation.id, "https://example.com/user/mouse/quotation/13")
self.assertEqual(quotation.content, "commentary")
self.assertEqual(quotation.quote, "quote body")
self.assertEqual(quotation.inReplyToBook, "https://example.com/book/1")
self.assertEqual(quotation.published, "2020-05-10T02:38:31.150343+00:00")
def test_activity_to_model(self):
''' create a model instance from an activity object '''
""" create a model instance from an activity object """
activity = activitypub.Quotation(**self.status_data)
quotation = activity.to_model(model=models.Quotation)

View File

@@ -1,4 +1,4 @@
''' testing book data connectors '''
""" testing book data connectors """
from unittest.mock import patch
from django.test import TestCase
import responses
@@ -10,109 +10,115 @@ from bookwyrm.settings import DOMAIN
class AbstractConnector(TestCase):
''' generic code for connecting to outside data sources '''
""" generic code for connecting to outside data sources """
def setUp(self):
''' we need an example connector '''
""" we need an example connector """
self.connector_info = 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=',
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=",
)
work_data = {
'id': 'abc1',
'title': 'Test work',
'type': 'work',
'openlibraryKey': 'OL1234W',
"id": "abc1",
"title": "Test work",
"type": "work",
"openlibraryKey": "OL1234W",
}
self.work_data = work_data
edition_data = {
'id': 'abc2',
'title': 'Test edition',
'type': 'edition',
'openlibraryKey': 'OL1234M',
"id": "abc2",
"title": "Test edition",
"type": "edition",
"openlibraryKey": "OL1234M",
}
self.edition_data = edition_data
class TestConnector(abstract_connector.AbstractConnector):
''' nothing added here '''
""" nothing added here """
def format_search_result(self, search_result):
return search_result
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
def is_work_data(self, data):
return data['type'] == 'work'
return data["type"] == "work"
def get_edition_from_work_data(self, data):
return edition_data
def get_work_from_edition_data(self, data):
return work_data
def get_authors_from_data(self, data):
return []
def expand_book_data(self, book):
pass
self.connector = TestConnector('example.com')
self.connector = TestConnector("example.com")
self.connector.book_mappings = [
Mapping('id'),
Mapping('title'),
Mapping('openlibraryKey'),
Mapping("id"),
Mapping("title"),
Mapping("openlibraryKey"),
]
self.book = models.Edition.objects.create(
title='Test Book', remote_id='https://example.com/book/1234',
openlibrary_key='OL1234M')
title="Test Book",
remote_id="https://example.com/book/1234",
openlibrary_key="OL1234M",
)
def test_abstract_connector_init(self):
''' barebones connector for search with defaults '''
""" barebones connector for search with defaults """
self.assertIsInstance(self.connector.book_mappings, list)
def test_is_available(self):
''' this isn't used.... '''
""" this isn't used.... """
self.assertTrue(self.connector.is_available())
self.connector.max_query_count = 1
self.connector.connector.query_count = 2
self.assertFalse(self.connector.is_available())
def test_get_or_create_book_existing(self):
''' find an existing book by remote/origin id '''
""" find an existing book by remote/origin id """
self.assertEqual(models.Book.objects.count(), 1)
self.assertEqual(
self.book.remote_id, 'https://%s/book/%d' % (DOMAIN, self.book.id))
self.assertEqual(
self.book.origin_id, 'https://example.com/book/1234')
self.book.remote_id, "https://%s/book/%d" % (DOMAIN, self.book.id)
)
self.assertEqual(self.book.origin_id, "https://example.com/book/1234")
# dedupe by origin id
result = self.connector.get_or_create_book(
'https://example.com/book/1234')
result = self.connector.get_or_create_book("https://example.com/book/1234")
self.assertEqual(models.Book.objects.count(), 1)
self.assertEqual(result, self.book)
# dedupe by remote id
result = self.connector.get_or_create_book(
'https://%s/book/%d' % (DOMAIN, self.book.id))
"https://%s/book/%d" % (DOMAIN, self.book.id)
)
self.assertEqual(models.Book.objects.count(), 1)
self.assertEqual(result, self.book)
@responses.activate
def test_get_or_create_book_deduped(self):
''' load remote data and deduplicate '''
""" load remote data and deduplicate """
responses.add(
responses.GET,
'https://example.com/book/abcd',
json=self.edition_data
responses.GET, "https://example.com/book/abcd", json=self.edition_data
)
with patch(
'bookwyrm.connectors.abstract_connector.load_more_data.delay'):
result = self.connector.get_or_create_book(
'https://example.com/book/abcd')
with patch("bookwyrm.connectors.abstract_connector.load_more_data.delay"):
result = self.connector.get_or_create_book("https://example.com/book/abcd")
self.assertEqual(result, self.book)
self.assertEqual(models.Edition.objects.count(), 1)
self.assertEqual(models.Edition.objects.count(), 1)

View File

@@ -1,4 +1,4 @@
''' testing book data connectors '''
""" testing book data connectors """
from django.test import TestCase
import responses
@@ -8,99 +8,101 @@ from bookwyrm.connectors.abstract_connector import Mapping, SearchResult
class AbstractConnector(TestCase):
''' generic code for connecting to outside data sources '''
""" generic code for connecting to outside data sources """
def setUp(self):
''' we need an example connector '''
""" we need an example connector """
self.connector_info = 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',
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",
)
class TestConnector(abstract_connector.AbstractMinimalConnector):
''' nothing added here '''
""" 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
self.test_connector = TestConnector('example.com')
self.test_connector = TestConnector("example.com")
def test_abstract_minimal_connector_init(self):
''' barebones connector for search with defaults '''
""" barebones connector for search with defaults """
connector = self.test_connector
self.assertEqual(connector.connector, self.connector_info)
self.assertEqual(connector.base_url, 'https://example.com')
self.assertEqual(connector.books_url, 'https://example.com/books')
self.assertEqual(connector.covers_url, 'https://example.com/covers')
self.assertEqual(connector.search_url, 'https://example.com/search?q=')
self.assertEqual(connector.isbn_search_url, 'https://example.com/isbn')
self.assertEqual(connector.base_url, "https://example.com")
self.assertEqual(connector.books_url, "https://example.com/books")
self.assertEqual(connector.covers_url, "https://example.com/covers")
self.assertEqual(connector.search_url, "https://example.com/search?q=")
self.assertEqual(connector.isbn_search_url, "https://example.com/isbn")
self.assertIsNone(connector.name)
self.assertEqual(connector.identifier, 'example.com')
self.assertEqual(connector.identifier, "example.com")
self.assertIsNone(connector.max_query_count)
self.assertFalse(connector.local)
@responses.activate
def test_search(self):
''' makes an http request to the outside service '''
""" makes an http request to the outside service """
responses.add(
responses.GET,
'https://example.com/search?q=a%20book%20title',
json=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l'],
status=200)
results = self.test_connector.search('a book title')
"https://example.com/search?q=a%20book%20title",
json=["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"],
status=200,
)
results = self.test_connector.search("a book title")
self.assertEqual(len(results), 10)
self.assertEqual(results[0], 'a')
self.assertEqual(results[1], 'b')
self.assertEqual(results[2], 'c')
self.assertEqual(results[0], "a")
self.assertEqual(results[1], "b")
self.assertEqual(results[2], "c")
def test_search_result(self):
''' a class that stores info about a search result '''
""" a class that stores info about a search result """
result = SearchResult(
title='Title',
key='https://example.com/book/1',
author='Author Name',
year='1850',
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')
self.assertEqual(result.title, "Title")
def test_create_mapping(self):
''' maps remote fields for book data to bookwyrm activitypub fields '''
mapping = Mapping('isbn')
self.assertEqual(mapping.local_field, 'isbn')
self.assertEqual(mapping.remote_field, 'isbn')
self.assertEqual(mapping.formatter('bb'), 'bb')
""" maps remote fields for book data to bookwyrm activitypub fields """
mapping = Mapping("isbn")
self.assertEqual(mapping.local_field, "isbn")
self.assertEqual(mapping.remote_field, "isbn")
self.assertEqual(mapping.formatter("bb"), "bb")
def test_create_mapping_with_remote(self):
''' the remote field is different than the local field '''
mapping = Mapping('isbn', remote_field='isbn13')
self.assertEqual(mapping.local_field, 'isbn')
self.assertEqual(mapping.remote_field, 'isbn13')
self.assertEqual(mapping.formatter('bb'), 'bb')
""" the remote field is different than the local field """
mapping = Mapping("isbn", remote_field="isbn13")
self.assertEqual(mapping.local_field, "isbn")
self.assertEqual(mapping.remote_field, "isbn13")
self.assertEqual(mapping.formatter("bb"), "bb")
def test_create_mapping_with_formatter(self):
''' a function is provided to modify the data '''
formatter = lambda x: 'aa' + x
mapping = Mapping('isbn', formatter=formatter)
self.assertEqual(mapping.local_field, 'isbn')
self.assertEqual(mapping.remote_field, 'isbn')
""" a function is provided to modify the data """
formatter = lambda x: "aa" + x
mapping = Mapping("isbn", formatter=formatter)
self.assertEqual(mapping.local_field, "isbn")
self.assertEqual(mapping.remote_field, "isbn")
self.assertEqual(mapping.formatter, formatter)
self.assertEqual(mapping.formatter('bb'), 'aabb')
self.assertEqual(mapping.formatter("bb"), "aabb")

View File

@@ -1,4 +1,4 @@
''' testing book data connectors '''
""" testing book data connectors """
import json
import pathlib
from django.test import TestCase
@@ -9,39 +9,36 @@ from bookwyrm.connectors.abstract_connector import SearchResult
class BookWyrmConnector(TestCase):
''' this connector doesn't do much, just search '''
def setUp(self):
''' create the connector '''
models.Connector.objects.create(
identifier='example.com',
connector_file='bookwyrm_connector',
base_url='https://example.com',
books_url='https://example.com',
covers_url='https://example.com/images/covers',
search_url='https://example.com/search?q=',
)
self.connector = Connector('example.com')
""" this connector doesn't do much, just search """
work_file = pathlib.Path(__file__).parent.joinpath(
'../data/bw_work.json')
edition_file = pathlib.Path(__file__).parent.joinpath(
'../data/bw_edition.json')
def setUp(self):
""" create the connector """
models.Connector.objects.create(
identifier="example.com",
connector_file="bookwyrm_connector",
base_url="https://example.com",
books_url="https://example.com",
covers_url="https://example.com/images/covers",
search_url="https://example.com/search?q=",
)
self.connector = Connector("example.com")
work_file = pathlib.Path(__file__).parent.joinpath("../data/bw_work.json")
edition_file = pathlib.Path(__file__).parent.joinpath("../data/bw_edition.json")
self.work_data = json.loads(work_file.read_bytes())
self.edition_data = json.loads(edition_file.read_bytes())
def test_format_search_result(self):
''' create a SearchResult object from search response json '''
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/bw_search.json')
""" create a SearchResult object from search response json """
datafile = pathlib.Path(__file__).parent.joinpath("../data/bw_search.json")
search_data = json.loads(datafile.read_bytes())
results = self.connector.parse_search_data(search_data)
self.assertIsInstance(results, list)
result = self.connector.format_search_result(results[0])
self.assertIsInstance(result, SearchResult)
self.assertEqual(result.title, 'Jonathan Strange and Mr Norrell')
self.assertEqual(result.key, 'https://example.com/book/122')
self.assertEqual(result.author, 'Susanna Clarke')
self.assertEqual(result.title, "Jonathan Strange and Mr Norrell")
self.assertEqual(result.key, "https://example.com/book/122")
self.assertEqual(result.author, "Susanna Clarke")
self.assertEqual(result.year, 2017)
self.assertEqual(result.connector, self.connector)

View File

@@ -1,54 +1,49 @@
''' interface between the app and various connectors '''
""" interface between the app and various connectors """
from django.test import TestCase
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
from bookwyrm.connectors.bookwyrm_connector import Connector as BookWyrmConnector
from bookwyrm.connectors.self_connector import Connector as SelfConnector
class ConnectorManager(TestCase):
''' interface between the app and various connectors '''
""" interface between the app and various connectors """
def setUp(self):
''' we'll need some books and a connector info entry '''
self.work = models.Work.objects.create(
title='Example Work'
)
""" 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(
title='Example Edition',
parent_work=self.work
title="Example Edition", parent_work=self.work
)
self.work.default_edition = self.edition
self.work.save()
self.connector = models.Connector.objects.create(
identifier='test_connector',
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/',
connector_file="self_connector",
base_url="http://test.com/",
books_url="http://test.com/",
covers_url="http://test.com/",
)
def test_get_or_create_connector(self):
''' loads a connector if the data source is known or creates one '''
remote_id = 'https://example.com/object/1'
""" loads a connector if the data source is known or creates one """
remote_id = "https://example.com/object/1"
connector = connector_manager.get_or_create_connector(remote_id)
self.assertIsInstance(connector, BookWyrmConnector)
self.assertEqual(connector.identifier, 'example.com')
self.assertEqual(connector.base_url, 'https://example.com')
self.assertEqual(connector.identifier, "example.com")
self.assertEqual(connector.base_url, "https://example.com")
same_connector = connector_manager.get_or_create_connector(remote_id)
self.assertEqual(connector.identifier, same_connector.identifier)
def test_get_connectors(self):
''' load all connectors '''
remote_id = 'https://example.com/object/1'
""" load all connectors """
remote_id = "https://example.com/object/1"
connector_manager.get_or_create_connector(remote_id)
connectors = list(connector_manager.get_connectors())
self.assertEqual(len(connectors), 2)
@@ -56,28 +51,28 @@ class ConnectorManager(TestCase):
self.assertIsInstance(connectors[1], BookWyrmConnector)
def test_search(self):
''' search all connectors '''
results = connector_manager.search('Example')
""" search all connectors """
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.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')
""" 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].title, "Example Edition")
def test_first_search_result(self):
''' only get one search result '''
result = connector_manager.first_search_result('Example')
self.assertEqual(result.title, 'Example Edition')
no_result = connector_manager.first_search_result('dkjfhg')
""" only get one search result """
result = connector_manager.first_search_result("Example")
self.assertEqual(result.title, "Example Edition")
no_result = connector_manager.first_search_result("dkjfhg")
self.assertIsNone(no_result)
def test_load_connector(self):
''' load a connector object from the database entry '''
""" 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')
self.assertEqual(connector.identifier, "test_connector")

View File

@@ -1,4 +1,4 @@
''' testing book data connectors '''
""" testing book data connectors """
import json
import pathlib
from unittest.mock import patch
@@ -9,253 +9,231 @@ import responses
from bookwyrm import models
from bookwyrm.connectors.openlibrary import Connector
from bookwyrm.connectors.openlibrary import get_languages, get_description
from bookwyrm.connectors.openlibrary import pick_default_edition, \
get_openlibrary_key
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
class Openlibrary(TestCase):
''' test loading data from openlibrary.org '''
def setUp(self):
''' creates the connector we'll use '''
models.Connector.objects.create(
identifier='openlibrary.org',
name='OpenLibrary',
connector_file='openlibrary',
base_url='https://openlibrary.org',
books_url='https://openlibrary.org',
covers_url='https://covers.openlibrary.org',
search_url='https://openlibrary.org/search?q=',
isbn_search_url='https://openlibrary.org/isbn',
)
self.connector = Connector('openlibrary.org')
""" test loading data from openlibrary.org """
work_file = pathlib.Path(__file__).parent.joinpath(
'../data/ol_work.json')
edition_file = pathlib.Path(__file__).parent.joinpath(
'../data/ol_edition.json')
def setUp(self):
""" creates the connector we'll use """
models.Connector.objects.create(
identifier="openlibrary.org",
name="OpenLibrary",
connector_file="openlibrary",
base_url="https://openlibrary.org",
books_url="https://openlibrary.org",
covers_url="https://covers.openlibrary.org",
search_url="https://openlibrary.org/search?q=",
isbn_search_url="https://openlibrary.org/isbn",
)
self.connector = Connector("openlibrary.org")
work_file = pathlib.Path(__file__).parent.joinpath("../data/ol_work.json")
edition_file = pathlib.Path(__file__).parent.joinpath("../data/ol_edition.json")
edition_list_file = pathlib.Path(__file__).parent.joinpath(
'../data/ol_edition_list.json')
"../data/ol_edition_list.json"
)
self.work_data = json.loads(work_file.read_bytes())
self.edition_data = json.loads(edition_file.read_bytes())
self.edition_list_data = json.loads(edition_list_file.read_bytes())
def test_get_remote_id_from_data(self):
''' format the remote id from the data '''
data = {'key': '/work/OL1234W'}
""" format the remote id from the data """
data = {"key": "/work/OL1234W"}
result = self.connector.get_remote_id_from_data(data)
self.assertEqual(result, 'https://openlibrary.org/work/OL1234W')
self.assertEqual(result, "https://openlibrary.org/work/OL1234W")
# error handlding
with self.assertRaises(ConnectorException):
self.connector.get_remote_id_from_data({})
def test_is_work_data(self):
''' detect if the loaded json is a work '''
""" detect if the loaded json is a work """
self.assertEqual(self.connector.is_work_data(self.work_data), True)
self.assertEqual(self.connector.is_work_data(self.edition_data), False)
@responses.activate
def test_get_edition_from_work_data(self):
''' loads a list of editions '''
data = {'key': '/work/OL1234W'}
""" loads a list of editions """
data = {"key": "/work/OL1234W"}
responses.add(
responses.GET,
'https://openlibrary.org/work/OL1234W/editions',
json={'entries': []},
status=200)
with patch('bookwyrm.connectors.openlibrary.pick_default_edition') \
as pick_edition:
pick_edition.return_value = 'hi'
"https://openlibrary.org/work/OL1234W/editions",
json={"entries": []},
status=200,
)
with patch(
"bookwyrm.connectors.openlibrary.pick_default_edition"
) as pick_edition:
pick_edition.return_value = "hi"
result = self.connector.get_edition_from_work_data(data)
self.assertEqual(result, 'hi')
self.assertEqual(result, "hi")
@responses.activate
def test_get_work_from_edition_data(self):
''' loads a list of editions '''
data = {'works': [{'key': '/work/OL1234W'}]}
""" loads a list of editions """
data = {"works": [{"key": "/work/OL1234W"}]}
responses.add(
responses.GET,
'https://openlibrary.org/work/OL1234W',
json={'hi': 'there'},
status=200)
"https://openlibrary.org/work/OL1234W",
json={"hi": "there"},
status=200,
)
result = self.connector.get_work_from_edition_data(data)
self.assertEqual(result, {'hi': 'there'})
self.assertEqual(result, {"hi": "there"})
@responses.activate
def test_get_authors_from_data(self):
''' find authors in data '''
""" find authors in data """
responses.add(
responses.GET,
'https://openlibrary.org/authors/OL382982A',
"https://openlibrary.org/authors/OL382982A",
json={
"name": "George Elliott",
"personal_name": "George Elliott",
"last_modified": {
"type": "/type/datetime",
"value": "2008-08-31 10:09:33.413686"
},
"value": "2008-08-31 10:09:33.413686",
},
"key": "/authors/OL453734A",
"type": {
"key": "/type/author"
},
"type": {"key": "/type/author"},
"id": 1259965,
"revision": 2
"revision": 2,
},
status=200)
status=200,
)
results = self.connector.get_authors_from_data(self.work_data)
result = list(results)[0]
self.assertIsInstance(result, models.Author)
self.assertEqual(result.name, 'George Elliott')
self.assertEqual(result.openlibrary_key, 'OL453734A')
self.assertEqual(result.name, "George Elliott")
self.assertEqual(result.openlibrary_key, "OL453734A")
def test_get_cover_url(self):
''' formats a url that should contain the cover image '''
blob = ['image']
""" formats a url that should contain the cover image """
blob = ["image"]
result = self.connector.get_cover_url(blob)
self.assertEqual(
result, 'https://covers.openlibrary.org/b/id/image-L.jpg')
self.assertEqual(result, "https://covers.openlibrary.org/b/id/image-L.jpg")
def test_parse_search_result(self):
''' extract the results from the search json response '''
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ol_search.json')
""" extract the results from the search json response """
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_search.json")
search_data = json.loads(datafile.read_bytes())
result = self.connector.parse_search_data(search_data)
self.assertIsInstance(result, list)
self.assertEqual(len(result), 2)
def test_format_search_result(self):
''' translate json from openlibrary into SearchResult '''
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ol_search.json')
""" translate json from openlibrary into SearchResult """
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_search.json")
search_data = json.loads(datafile.read_bytes())
results = self.connector.parse_search_data(search_data)
self.assertIsInstance(results, list)
result = self.connector.format_search_result(results[0])
self.assertIsInstance(result, SearchResult)
self.assertEqual(result.title, 'This Is How You Lose the Time War')
self.assertEqual(
result.key, 'https://openlibrary.org/works/OL20639540W')
self.assertEqual(result.author, 'Amal El-Mohtar, Max Gladstone')
self.assertEqual(result.title, "This Is How You Lose the Time War")
self.assertEqual(result.key, "https://openlibrary.org/works/OL20639540W")
self.assertEqual(result.author, "Amal El-Mohtar, Max Gladstone")
self.assertEqual(result.year, 2019)
self.assertEqual(result.connector, self.connector)
def test_parse_isbn_search_result(self):
''' extract the results from the search json response '''
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ol_isbn_search.json')
""" extract the results from the search json response """
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_isbn_search.json")
search_data = json.loads(datafile.read_bytes())
result = self.connector.parse_isbn_search_data(search_data)
self.assertIsInstance(result, list)
self.assertEqual(len(result), 1)
def test_format_isbn_search_result(self):
''' translate json from openlibrary into SearchResult '''
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ol_isbn_search.json')
""" translate json from openlibrary into SearchResult """
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_isbn_search.json")
search_data = json.loads(datafile.read_bytes())
results = self.connector.parse_isbn_search_data(search_data)
self.assertIsInstance(results, list)
result = self.connector.format_isbn_search_result(results[0])
self.assertIsInstance(result, SearchResult)
self.assertEqual(result.title, 'Les ombres errantes')
self.assertEqual(
result.key, 'https://openlibrary.org/books/OL16262504M')
self.assertEqual(result.author, 'Pascal Quignard')
self.assertEqual(result.year, '2002')
self.assertEqual(result.title, "Les ombres errantes")
self.assertEqual(result.key, "https://openlibrary.org/books/OL16262504M")
self.assertEqual(result.author, "Pascal Quignard")
self.assertEqual(result.year, "2002")
self.assertEqual(result.connector, self.connector)
@responses.activate
def test_load_edition_data(self):
''' format url from key and make request '''
key = 'OL1234W'
""" format url from key and make request """
key = "OL1234W"
responses.add(
responses.GET,
'https://openlibrary.org/works/OL1234W/editions',
json={'hi': 'there'}
"https://openlibrary.org/works/OL1234W/editions",
json={"hi": "there"},
)
result = self.connector.load_edition_data(key)
self.assertEqual(result, {'hi': 'there'})
self.assertEqual(result, {"hi": "there"})
@responses.activate
def test_expand_book_data(self):
''' given a book, get more editions '''
work = models.Work.objects.create(
title='Test Work', openlibrary_key='OL1234W')
edition = models.Edition.objects.create(
title='Test Edition', parent_work=work)
""" given a book, get more editions """
work = models.Work.objects.create(title="Test Work", openlibrary_key="OL1234W")
edition = models.Edition.objects.create(title="Test Edition", parent_work=work)
responses.add(
responses.GET,
'https://openlibrary.org/works/OL1234W/editions',
json={'entries': []},
"https://openlibrary.org/works/OL1234W/editions",
json={"entries": []},
)
with patch(
'bookwyrm.connectors.abstract_connector.AbstractConnector.' \
'create_edition_from_data'):
"bookwyrm.connectors.abstract_connector.AbstractConnector."
"create_edition_from_data"
):
self.connector.expand_book_data(edition)
self.connector.expand_book_data(work)
def test_get_description(self):
''' should do some cleanup on the description data '''
description = get_description(self.work_data['description'])
expected = 'First in the Old Kingdom/Abhorsen series.'
""" should do some cleanup on the description data """
description = get_description(self.work_data["description"])
expected = "First in the Old Kingdom/Abhorsen series."
self.assertEqual(description, expected)
def test_get_openlibrary_key(self):
''' extracts the uuid '''
key = get_openlibrary_key('/books/OL27320736M')
self.assertEqual(key, 'OL27320736M')
""" extracts the uuid """
key = get_openlibrary_key("/books/OL27320736M")
self.assertEqual(key, "OL27320736M")
def test_get_languages(self):
''' looks up languages from a list '''
languages = get_languages(self.edition_data['languages'])
self.assertEqual(languages, ['English'])
""" looks up languages from a list """
languages = get_languages(self.edition_data["languages"])
self.assertEqual(languages, ["English"])
def test_pick_default_edition(self):
''' detect if the loaded json is an edition '''
edition = pick_default_edition(self.edition_list_data['entries'])
self.assertEqual(edition['key'], '/books/OL9788823M')
""" detect if the loaded json is an edition """
edition = pick_default_edition(self.edition_list_data["entries"])
self.assertEqual(edition["key"], "/books/OL9788823M")
@responses.activate
def test_create_edition_from_data(self):
''' okay but can it actually create an edition with proper metadata '''
work = models.Work.objects.create(title='Hello')
""" okay but can it actually create an edition with proper metadata """
work = models.Work.objects.create(title="Hello")
responses.add(
responses.GET,
'https://openlibrary.org/authors/OL382982A',
json={'hi': 'there'},
status=200)
with patch('bookwyrm.connectors.openlibrary.Connector.' \
'get_authors_from_data') as mock:
"https://openlibrary.org/authors/OL382982A",
json={"hi": "there"},
status=200,
)
with patch(
"bookwyrm.connectors.openlibrary.Connector." "get_authors_from_data"
) as mock:
mock.return_value = []
result = self.connector.create_edition_from_data(
work, self.edition_data)
result = self.connector.create_edition_from_data(work, self.edition_data)
self.assertEqual(result.parent_work, work)
self.assertEqual(result.title, 'Sabriel')
self.assertEqual(result.isbn_10, '0060273224')
self.assertEqual(result.title, "Sabriel")
self.assertEqual(result.isbn_10, "0060273224")
self.assertIsNotNone(result.description)
self.assertEqual(result.languages[0], 'English')
self.assertEqual(result.publishers[0], 'Harper Trophy')
self.assertEqual(result.languages[0], "English")
self.assertEqual(result.publishers[0], "Harper Trophy")
self.assertEqual(result.pages, 491)
self.assertEqual(result.subjects[0], 'Fantasy.')
self.assertEqual(result.physical_format, 'Hardcover')
self.assertEqual(result.subjects[0], "Fantasy.")
self.assertEqual(result.physical_format, "Hardcover")

View File

@@ -1,4 +1,4 @@
''' testing book data connectors '''
""" testing book data connectors """
import datetime
from django.test import TestCase
from django.utils import timezone
@@ -9,100 +9,98 @@ from bookwyrm.settings import DOMAIN
class SelfConnector(TestCase):
''' just uses local data '''
""" just uses local data """
def setUp(self):
''' creating the connector '''
""" creating the connector """
models.Connector.objects.create(
identifier=DOMAIN,
name='Local',
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,
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')
""" create a SearchResult """
author = models.Author.objects.create(name="Anonymous")
edition = models.Edition.objects.create(
title='Edition of Example Work',
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')
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.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')
""" prioritize certain results """
author = models.Author.objects.create(name="Anonymous")
edition = models.Edition.objects.create(
title='Edition of Example Work',
title="Edition of Example Work",
published_date=datetime.datetime(1980, 5, 10, tzinfo=timezone.utc),
parent_work=models.Work.objects.create(title='')
parent_work=models.Work.objects.create(title=""),
)
# author text is rank C
edition.authors.add(author)
# series is rank D
models.Edition.objects.create(
title='Another Edition',
series='Anonymous',
parent_work=models.Work.objects.create(title='')
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="More Editions",
subtitle="The Anonymous Edition",
parent_work=models.Work.objects.create(title=""),
)
# title is rank A
models.Edition.objects.create(title='Anonymous')
models.Edition.objects.create(title="Anonymous")
# doesn't rank in this search
edition = models.Edition.objects.create(
title='An Edition',
parent_work=models.Work.objects.create(title='')
title="An Edition", parent_work=models.Work.objects.create(title="")
)
results = self.connector.search('Anonymous')
results = self.connector.search("Anonymous")
self.assertEqual(len(results), 3)
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[0].title, "Anonymous")
self.assertEqual(results[1].title, "More Editions")
self.assertEqual(results[2].title, "Edition of Example Work")
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')
""" 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)
title="Edition 1 Title", parent_work=work
)
edition_2 = models.Edition.objects.create(
title='Edition 2 Title', parent_work=work)
edition_3 = models.Edition.objects.create(
title='Fish', parent_work=work)
title="Edition 2 Title", parent_work=work
)
edition_3 = models.Edition.objects.create(title="Fish", parent_work=work)
work.default_edition = edition_2
work.save()
# pick the best edition
results = self.connector.search('Edition 1 Title')
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')
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')
results = self.connector.search("Fish")
self.assertEqual(len(results), 1)
self.assertEqual(results[0].key, edition_3.remote_id)

View File

@@ -1,4 +1,4 @@
''' testing model activitypub utilities '''
""" testing model activitypub utilities """
from unittest.mock import patch
from collections import namedtuple
from dataclasses import dataclass
@@ -12,238 +12,249 @@ from bookwyrm.models import base_model
from bookwyrm.models.activitypub_mixin import ActivitypubMixin
from bookwyrm.models.activitypub_mixin import ActivityMixin, ObjectMixin
class ActivitypubMixins(TestCase):
''' functionality shared across models '''
""" functionality shared across models """
def setUp(self):
''' shared data '''
""" shared data """
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'
"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)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@rat.com', 'ratword',
"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',
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
self.object_mock = {
'to': 'to field', 'cc': 'cc field',
'content': 'hi', 'id': 'bip', 'type': 'Test',
'published': '2020-12-04T17:52:22.623807+00:00',
"to": "to field",
"cc": "cc field",
"content": "hi",
"id": "bip",
"type": "Test",
"published": "2020-12-04T17:52:22.623807+00:00",
}
# ActivitypubMixin
def test_to_activity(self):
''' model to ActivityPub json '''
""" model to ActivityPub json """
@dataclass(init=False)
class TestActivity(ActivityObject):
''' real simple mock '''
type: str = 'Test'
""" real simple mock """
type: str = "Test"
class TestModel(ActivitypubMixin, base_model.BookWyrmModel):
''' real simple mock model because BookWyrmModel is abstract '''
""" real simple mock model because BookWyrmModel is abstract """
instance = TestModel()
instance.remote_id = 'https://www.example.com/test'
instance.remote_id = "https://www.example.com/test"
instance.activity_serializer = TestActivity
activity = instance.to_activity()
self.assertIsInstance(activity, dict)
self.assertEqual(activity['id'], 'https://www.example.com/test')
self.assertEqual(activity['type'], 'Test')
self.assertEqual(activity["id"], "https://www.example.com/test")
self.assertEqual(activity["type"], "Test")
def test_find_existing_by_remote_id(self):
''' attempt to match a remote id to an object in the db '''
""" attempt to match a remote id to an object in the db """
# uses a different remote id scheme
# this isn't really part of this test directly but it's helpful to state
book = models.Edition.objects.create(
title='Test Edition', remote_id='http://book.com/book')
title="Test Edition", remote_id="http://book.com/book"
)
self.assertEqual(book.origin_id, 'http://book.com/book')
self.assertNotEqual(book.remote_id, 'http://book.com/book')
self.assertEqual(book.origin_id, "http://book.com/book")
self.assertNotEqual(book.remote_id, "http://book.com/book")
# uses subclasses
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Comment.objects.create(
user=self.local_user, content='test status', book=book, \
remote_id='https://comment.net')
user=self.local_user,
content="test status",
book=book,
remote_id="https://comment.net",
)
result = models.User.find_existing_by_remote_id('hi')
result = models.User.find_existing_by_remote_id("hi")
self.assertIsNone(result)
result = models.User.find_existing_by_remote_id(
'http://example.com/a/b')
result = models.User.find_existing_by_remote_id("http://example.com/a/b")
self.assertEqual(result, self.local_user)
# test using origin id
result = models.Edition.find_existing_by_remote_id(
'http://book.com/book')
result = models.Edition.find_existing_by_remote_id("http://book.com/book")
self.assertEqual(result, book)
# test subclass match
result = models.Status.find_existing_by_remote_id(
'https://comment.net')
result = models.Status.find_existing_by_remote_id("https://comment.net")
def test_find_existing(self):
''' match a blob of data to a model '''
""" match a blob of data to a model """
book = models.Edition.objects.create(
title='Test edition',
openlibrary_key='OL1234',
title="Test edition",
openlibrary_key="OL1234",
)
result = models.Edition.find_existing(
{'openlibraryKey': 'OL1234'})
result = models.Edition.find_existing({"openlibraryKey": "OL1234"})
self.assertEqual(result, book)
def test_get_recipients_public_object(self):
''' determines the recipients for an object's broadcast '''
MockSelf = namedtuple('Self', ('privacy'))
mock_self = MockSelf('public')
""" determines the recipients for an object's broadcast """
MockSelf = namedtuple("Self", ("privacy"))
mock_self = MockSelf("public")
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 1)
self.assertEqual(recipients[0], self.remote_user.inbox)
def test_get_recipients_public_user_object_no_followers(self):
''' determines the recipients for a user's object broadcast '''
MockSelf = namedtuple('Self', ('privacy', 'user'))
mock_self = MockSelf('public', self.local_user)
""" determines the recipients for a user's object broadcast """
MockSelf = namedtuple("Self", ("privacy", "user"))
mock_self = MockSelf("public", self.local_user)
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 0)
def test_get_recipients_public_user_object(self):
''' determines the recipients for a user's object broadcast '''
MockSelf = namedtuple('Self', ('privacy', 'user'))
mock_self = MockSelf('public', self.local_user)
""" determines the recipients for a user's object broadcast """
MockSelf = namedtuple("Self", ("privacy", "user"))
mock_self = MockSelf("public", self.local_user)
self.local_user.followers.add(self.remote_user)
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 1)
self.assertEqual(recipients[0], self.remote_user.inbox)
def test_get_recipients_public_user_object_with_mention(self):
''' determines the recipients for a user's object broadcast '''
MockSelf = namedtuple('Self', ('privacy', 'user'))
mock_self = MockSelf('public', self.local_user)
""" determines the recipients for a user's object broadcast """
MockSelf = namedtuple("Self", ("privacy", "user"))
mock_self = MockSelf("public", self.local_user)
self.local_user.followers.add(self.remote_user)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
another_remote_user = models.User.objects.create_user(
'nutria', 'nutria@nutria.com', 'nutriaword',
"nutria",
"nutria@nutria.com",
"nutriaword",
local=False,
remote_id='https://example.com/users/nutria',
inbox='https://example.com/users/nutria/inbox',
outbox='https://example.com/users/nutria/outbox',
remote_id="https://example.com/users/nutria",
inbox="https://example.com/users/nutria/inbox",
outbox="https://example.com/users/nutria/outbox",
)
MockSelf = namedtuple('Self', ('privacy', 'user', 'recipients'))
mock_self = MockSelf('public', self.local_user, [another_remote_user])
MockSelf = namedtuple("Self", ("privacy", "user", "recipients"))
mock_self = MockSelf("public", self.local_user, [another_remote_user])
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 2)
self.assertEqual(recipients[0], another_remote_user.inbox)
self.assertEqual(recipients[1], self.remote_user.inbox)
def test_get_recipients_direct(self):
''' determines the recipients for a user's object broadcast '''
MockSelf = namedtuple('Self', ('privacy', 'user'))
mock_self = MockSelf('public', self.local_user)
""" determines the recipients for a user's object broadcast """
MockSelf = namedtuple("Self", ("privacy", "user"))
mock_self = MockSelf("public", self.local_user)
self.local_user.followers.add(self.remote_user)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
another_remote_user = models.User.objects.create_user(
'nutria', 'nutria@nutria.com', 'nutriaword',
"nutria",
"nutria@nutria.com",
"nutriaword",
local=False,
remote_id='https://example.com/users/nutria',
inbox='https://example.com/users/nutria/inbox',
outbox='https://example.com/users/nutria/outbox',
remote_id="https://example.com/users/nutria",
inbox="https://example.com/users/nutria/inbox",
outbox="https://example.com/users/nutria/outbox",
)
MockSelf = namedtuple('Self', ('privacy', 'user', 'recipients'))
mock_self = MockSelf('direct', self.local_user, [another_remote_user])
MockSelf = namedtuple("Self", ("privacy", "user", "recipients"))
mock_self = MockSelf("direct", self.local_user, [another_remote_user])
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 1)
self.assertEqual(recipients[0], another_remote_user.inbox)
def test_get_recipients_combine_inboxes(self):
''' should combine users with the same shared_inbox '''
self.remote_user.shared_inbox = 'http://example.com/inbox'
""" should combine users with the same shared_inbox """
self.remote_user.shared_inbox = "http://example.com/inbox"
self.remote_user.save(broadcast=False)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
another_remote_user = models.User.objects.create_user(
'nutria', 'nutria@nutria.com', 'nutriaword',
"nutria",
"nutria@nutria.com",
"nutriaword",
local=False,
remote_id='https://example.com/users/nutria',
inbox='https://example.com/users/nutria/inbox',
shared_inbox='http://example.com/inbox',
outbox='https://example.com/users/nutria/outbox',
remote_id="https://example.com/users/nutria",
inbox="https://example.com/users/nutria/inbox",
shared_inbox="http://example.com/inbox",
outbox="https://example.com/users/nutria/outbox",
)
MockSelf = namedtuple('Self', ('privacy', 'user'))
mock_self = MockSelf('public', self.local_user)
MockSelf = namedtuple("Self", ("privacy", "user"))
mock_self = MockSelf("public", self.local_user)
self.local_user.followers.add(self.remote_user)
self.local_user.followers.add(another_remote_user)
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 1)
self.assertEqual(recipients[0], 'http://example.com/inbox')
self.assertEqual(recipients[0], "http://example.com/inbox")
def test_get_recipients_software(self):
''' should differentiate between bookwyrm and other remote users '''
with patch('bookwyrm.models.user.set_remote_server.delay'):
""" should differentiate between bookwyrm and other remote users """
with patch("bookwyrm.models.user.set_remote_server.delay"):
another_remote_user = models.User.objects.create_user(
'nutria', 'nutria@nutria.com', 'nutriaword',
"nutria",
"nutria@nutria.com",
"nutriaword",
local=False,
remote_id='https://example.com/users/nutria',
inbox='https://example.com/users/nutria/inbox',
outbox='https://example.com/users/nutria/outbox',
remote_id="https://example.com/users/nutria",
inbox="https://example.com/users/nutria/inbox",
outbox="https://example.com/users/nutria/outbox",
bookwyrm_user=False,
)
MockSelf = namedtuple('Self', ('privacy', 'user'))
mock_self = MockSelf('public', self.local_user)
MockSelf = namedtuple("Self", ("privacy", "user"))
mock_self = MockSelf("public", self.local_user)
self.local_user.followers.add(self.remote_user)
self.local_user.followers.add(another_remote_user)
recipients = ActivitypubMixin.get_recipients(mock_self)
self.assertEqual(len(recipients), 2)
recipients = ActivitypubMixin.get_recipients(
mock_self, software='bookwyrm')
recipients = ActivitypubMixin.get_recipients(mock_self, software="bookwyrm")
self.assertEqual(len(recipients), 1)
self.assertEqual(recipients[0], self.remote_user.inbox)
recipients = ActivitypubMixin.get_recipients(
mock_self, software='other')
recipients = ActivitypubMixin.get_recipients(mock_self, software="other")
self.assertEqual(len(recipients), 1)
self.assertEqual(recipients[0], another_remote_user.inbox)
# ObjectMixin
def test_object_save_create(self):
''' should save uneventufully when broadcast is disabled '''
""" should save uneventufully when broadcast is disabled """
class Success(Exception):
''' this means we got to the right method '''
""" this means we got to the right method """
class ObjectModel(ObjectMixin, base_model.BookWyrmModel):
''' real simple mock model because BookWyrmModel is abstract '''
user = models.fields.ForeignKey('User', on_delete=db.models.CASCADE)
""" real simple mock model because BookWyrmModel is abstract """
user = models.fields.ForeignKey("User", on_delete=db.models.CASCADE)
def save(self, *args, **kwargs):
with patch('django.db.models.Model.save'):
with patch("django.db.models.Model.save"):
super().save(*args, **kwargs)
def broadcast(self, activity, sender, **kwargs):#pylint: disable=arguments-differ
''' do something '''
def broadcast(
self, activity, sender, **kwargs
): # pylint: disable=arguments-differ
""" do something """
raise Success()
def to_create_activity(self, user):#pylint: disable=arguments-differ
def to_create_activity(self, user): # pylint: disable=arguments-differ
return {}
with self.assertRaises(Success):
@@ -253,20 +264,24 @@ class ActivitypubMixins(TestCase):
ObjectModel(user=self.local_user).save(broadcast=False)
ObjectModel(user=None).save()
def test_object_save_update(self):
''' should save uneventufully when broadcast is disabled '''
""" should save uneventufully when broadcast is disabled """
class Success(Exception):
''' this means we got to the right method '''
""" this means we got to the right method """
class UpdateObjectModel(ObjectMixin, base_model.BookWyrmModel):
''' real simple mock model because BookWyrmModel is abstract '''
user = models.fields.ForeignKey('User', on_delete=db.models.CASCADE)
""" real simple mock model because BookWyrmModel is abstract """
user = models.fields.ForeignKey("User", on_delete=db.models.CASCADE)
last_edited_by = models.fields.ForeignKey(
'User', on_delete=db.models.CASCADE)
"User", on_delete=db.models.CASCADE
)
def save(self, *args, **kwargs):
with patch('django.db.models.Model.save'):
with patch("django.db.models.Model.save"):
super().save(*args, **kwargs)
def to_update_activity(self, user):
raise Success()
@@ -275,87 +290,71 @@ class ActivitypubMixins(TestCase):
with self.assertRaises(Success):
UpdateObjectModel(id=1, last_edited_by=self.local_user).save()
def test_object_save_delete(self):
''' should create delete activities when objects are deleted by flag '''
""" should create delete activities when objects are deleted by flag """
class ActivitySuccess(Exception):
''' this means we got to the right method '''
""" this means we got to the right method """
class DeletableObjectModel(ObjectMixin, base_model.BookWyrmModel):
''' real simple mock model because BookWyrmModel is abstract '''
user = models.fields.ForeignKey('User', on_delete=db.models.CASCADE)
""" real simple mock model because BookWyrmModel is abstract """
user = models.fields.ForeignKey("User", on_delete=db.models.CASCADE)
deleted = models.fields.BooleanField()
def save(self, *args, **kwargs):
with patch('django.db.models.Model.save'):
with patch("django.db.models.Model.save"):
super().save(*args, **kwargs)
def to_delete_activity(self, user):
raise ActivitySuccess()
with self.assertRaises(ActivitySuccess):
DeletableObjectModel(
id=1, user=self.local_user, deleted=True).save()
DeletableObjectModel(id=1, user=self.local_user, deleted=True).save()
def test_to_delete_activity(self):
''' wrapper for Delete activity '''
MockSelf = namedtuple('Self', ('remote_id', 'to_activity'))
""" wrapper for Delete activity """
MockSelf = namedtuple("Self", ("remote_id", "to_activity"))
mock_self = MockSelf(
'https://example.com/status/1',
lambda *args: self.object_mock
"https://example.com/status/1", lambda *args: self.object_mock
)
activity = ObjectMixin.to_delete_activity(
mock_self, self.local_user)
activity = ObjectMixin.to_delete_activity(mock_self, self.local_user)
self.assertEqual(activity["id"], "https://example.com/status/1/activity")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["to"], ["%s/followers" % self.local_user.remote_id])
self.assertEqual(
activity['id'],
'https://example.com/status/1/activity'
activity["cc"], ["https://www.w3.org/ns/activitystreams#Public"]
)
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['type'], 'Delete')
self.assertEqual(
activity['to'],
['%s/followers' % self.local_user.remote_id])
self.assertEqual(
activity['cc'],
['https://www.w3.org/ns/activitystreams#Public'])
def test_to_update_activity(self):
''' ditto above but for Update '''
MockSelf = namedtuple('Self', ('remote_id', 'to_activity'))
""" ditto above but for Update """
MockSelf = namedtuple("Self", ("remote_id", "to_activity"))
mock_self = MockSelf(
'https://example.com/status/1',
lambda *args: self.object_mock
"https://example.com/status/1", lambda *args: self.object_mock
)
activity = ObjectMixin.to_update_activity(
mock_self, self.local_user)
activity = ObjectMixin.to_update_activity(mock_self, self.local_user)
self.assertIsNotNone(
re.match(
r'^https:\/\/example\.com\/status\/1#update\/.*',
activity['id']
)
re.match(r"^https:\/\/example\.com\/status\/1#update\/.*", activity["id"])
)
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['type'], 'Update')
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["type"], "Update")
self.assertEqual(
activity['to'],
['https://www.w3.org/ns/activitystreams#Public'])
self.assertIsInstance(activity['object'], dict)
activity["to"], ["https://www.w3.org/ns/activitystreams#Public"]
)
self.assertIsInstance(activity["object"], dict)
# Activity mixin
def test_to_undo_activity(self):
''' and again, for Undo '''
MockSelf = namedtuple('Self', ('remote_id', 'to_activity', 'user'))
""" and again, for Undo """
MockSelf = namedtuple("Self", ("remote_id", "to_activity", "user"))
mock_self = MockSelf(
'https://example.com/status/1',
"https://example.com/status/1",
lambda *args: self.object_mock,
self.local_user,
)
activity = ActivityMixin.to_undo_activity(mock_self)
self.assertEqual(
activity['id'],
'https://example.com/status/1#undo'
)
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['type'], 'Undo')
self.assertIsInstance(activity['object'], dict)
self.assertEqual(activity["id"], "https://example.com/status/1#undo")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["type"], "Undo")
self.assertIsInstance(activity["object"], dict)

View File

@@ -1,42 +1,41 @@
''' testing models '''
""" testing models """
from django.test import TestCase
from bookwyrm import models
from bookwyrm.models import base_model
from bookwyrm.settings import DOMAIN
class BaseModel(TestCase):
''' functionality shared across models '''
""" functionality shared across models """
def test_remote_id(self):
''' these should be generated '''
""" these should be generated """
instance = base_model.BookWyrmModel()
instance.id = 1
expected = instance.get_remote_id()
self.assertEqual(expected, 'https://%s/bookwyrmmodel/1' % DOMAIN)
self.assertEqual(expected, "https://%s/bookwyrmmodel/1" % DOMAIN)
def test_remote_id_with_user(self):
''' format of remote id when there's a user object '''
""" format of remote id when there's a user object """
user = models.User.objects.create_user(
'mouse', 'mouse@mouse.com', 'mouseword',
local=True, localname='mouse')
"mouse", "mouse@mouse.com", "mouseword", local=True, localname="mouse"
)
instance = base_model.BookWyrmModel()
instance.user = user
instance.id = 1
expected = instance.get_remote_id()
self.assertEqual(
expected,
'https://%s/user/mouse/bookwyrmmodel/1' % DOMAIN)
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmmodel/1" % DOMAIN)
def test_execute_after_save(self):
''' this function sets remote ids after creation '''
""" this function sets remote ids after creation """
# using Work because it BookWrymModel is abstract and this requires save
# Work is a relatively not-fancy model.
instance = models.Work.objects.create(title='work title')
instance = models.Work.objects.create(title="work title")
instance.remote_id = None
base_model.execute_after_save(None, instance, True)
self.assertEqual(
instance.remote_id,
'https://%s/book/%d' % (DOMAIN, instance.id)
instance.remote_id, "https://%s/book/%d" % (DOMAIN, instance.id)
)
# shouldn't set remote_id if it's not created

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
from dateutil.parser import parse
from django.test import TestCase
from django.utils import timezone
@@ -8,88 +8,80 @@ from bookwyrm.models.book import isbn_10_to_13, isbn_13_to_10
class Book(TestCase):
''' not too much going on in the books model but here we are '''
""" not too much going on in the books model but here we are """
def setUp(self):
''' we'll need some books '''
""" we'll need some books """
self.work = models.Work.objects.create(
title='Example Work',
remote_id='https://example.com/book/1'
title="Example Work", remote_id="https://example.com/book/1"
)
self.first_edition = models.Edition.objects.create(
title='Example Edition',
title="Example Edition",
parent_work=self.work,
)
self.second_edition = models.Edition.objects.create(
title='Another Example Edition',
title="Another Example Edition",
parent_work=self.work,
)
def test_remote_id(self):
''' fanciness with remote/origin ids '''
remote_id = 'https://%s/book/%d' % (settings.DOMAIN, self.work.id)
""" fanciness with remote/origin ids """
remote_id = "https://%s/book/%d" % (settings.DOMAIN, self.work.id)
self.assertEqual(self.work.get_remote_id(), remote_id)
self.assertEqual(self.work.remote_id, remote_id)
def test_create_book(self):
''' you shouldn't be able to create Books (only editions and works) '''
self.assertRaises(
ValueError,
models.Book.objects.create,
title='Invalid Book'
)
""" you shouldn't be able to create Books (only editions and works) """
self.assertRaises(ValueError, models.Book.objects.create, title="Invalid Book")
def test_isbn_10_to_13(self):
''' checksums and so on '''
isbn_10 = '178816167X'
""" checksums and so on """
isbn_10 = "178816167X"
isbn_13 = isbn_10_to_13(isbn_10)
self.assertEqual(isbn_13, '9781788161671')
self.assertEqual(isbn_13, "9781788161671")
isbn_10 = '1-788-16167-X'
isbn_10 = "1-788-16167-X"
isbn_13 = isbn_10_to_13(isbn_10)
self.assertEqual(isbn_13, '9781788161671')
self.assertEqual(isbn_13, "9781788161671")
def test_isbn_13_to_10(self):
''' checksums and so on '''
isbn_13 = '9781788161671'
""" checksums and so on """
isbn_13 = "9781788161671"
isbn_10 = isbn_13_to_10(isbn_13)
self.assertEqual(isbn_10, '178816167X')
self.assertEqual(isbn_10, "178816167X")
isbn_13 = '978-1788-16167-1'
isbn_13 = "978-1788-16167-1"
isbn_10 = isbn_13_to_10(isbn_13)
self.assertEqual(isbn_10, '178816167X')
self.assertEqual(isbn_10, "178816167X")
def test_get_edition_info(self):
''' text slug about an edition '''
book = models.Edition.objects.create(title='Test Edition')
self.assertEqual(book.edition_info, '')
""" text slug about an edition """
book = models.Edition.objects.create(title="Test Edition")
self.assertEqual(book.edition_info, "")
book.physical_format = 'worm'
book.physical_format = "worm"
book.save()
self.assertEqual(book.edition_info, 'worm')
self.assertEqual(book.edition_info, "worm")
book.languages = ['English']
book.languages = ["English"]
book.save()
self.assertEqual(book.edition_info, 'worm')
self.assertEqual(book.edition_info, "worm")
book.languages = ['Glorbish', 'English']
book.languages = ["Glorbish", "English"]
book.save()
self.assertEqual(book.edition_info, 'worm, Glorbish language')
self.assertEqual(book.edition_info, "worm, Glorbish language")
book.published_date = timezone.make_aware(parse('2020'))
book.published_date = timezone.make_aware(parse("2020"))
book.save()
self.assertEqual(book.edition_info, 'worm, Glorbish language, 2020')
self.assertEqual(
book.alt_text, 'Test Edition (worm, Glorbish language, 2020)')
self.assertEqual(book.edition_info, "worm, Glorbish language, 2020")
self.assertEqual(book.alt_text, "Test Edition (worm, Glorbish language, 2020)")
def test_get_rank(self):
''' sets the data quality index for the book '''
""" sets the data quality index for the book """
# basic rank
self.assertEqual(self.first_edition.edition_rank, 0)
self.first_edition.description = 'hi'
self.first_edition.description = "hi"
self.first_edition.save()
self.assertEqual(self.first_edition.edition_rank, 1)

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
from io import BytesIO
from collections import namedtuple
from dataclasses import dataclass
@@ -23,408 +23,388 @@ from bookwyrm.models import fields, User, Status
from bookwyrm.models.base_model import BookWyrmModel
from bookwyrm.models.activitypub_mixin import ActivitypubMixin
#pylint: disable=too-many-public-methods
# pylint: disable=too-many-public-methods
class ActivitypubFields(TestCase):
''' overwrites standard model feilds to work with activitypub '''
""" overwrites standard model feilds to work with activitypub """
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'))
self.assertIsNone(fields.validate_remote_id('http://exle.com/dlg-23/x'))
""" 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"))
self.assertIsNone(fields.validate_remote_id("http://exle.com/dlg-23/x"))
self.assertRaises(
ValidationError, fields.validate_remote_id,
'http:/example.com/dlfjg-23/x')
ValidationError, fields.validate_remote_id, "http:/example.com/dlfjg-23/x"
)
self.assertRaises(
ValidationError, fields.validate_remote_id,
'www.example.com/dlfjg-23/x')
ValidationError, fields.validate_remote_id, "www.example.com/dlfjg-23/x"
)
self.assertRaises(
ValidationError, fields.validate_remote_id,
'http://www.example.com/dlfjg 23/x')
ValidationError,
fields.validate_remote_id,
"http://www.example.com/dlfjg 23/x",
)
def test_activitypub_field_mixin(self):
''' generic mixin with super basic to and from functionality '''
""" generic mixin with super basic to and from functionality """
instance = fields.ActivitypubFieldMixin()
self.assertEqual(instance.field_to_activity('fish'), 'fish')
self.assertEqual(instance.field_from_activity('fish'), 'fish')
self.assertEqual(instance.field_to_activity("fish"), "fish")
self.assertEqual(instance.field_from_activity("fish"), "fish")
self.assertFalse(instance.deduplication_field)
instance = fields.ActivitypubFieldMixin(
activitypub_wrapper='endpoints', activitypub_field='outbox'
activitypub_wrapper="endpoints", activitypub_field="outbox"
)
self.assertEqual(
instance.field_to_activity('fish'),
{'outbox': 'fish'}
)
self.assertEqual(
instance.field_from_activity({'outbox': 'fish'}),
'fish'
)
self.assertEqual(instance.get_activitypub_field(), 'endpoints')
self.assertEqual(instance.field_to_activity("fish"), {"outbox": "fish"})
self.assertEqual(instance.field_from_activity({"outbox": "fish"}), "fish")
self.assertEqual(instance.get_activitypub_field(), "endpoints")
instance = fields.ActivitypubFieldMixin()
instance.name = 'snake_case_name'
self.assertEqual(instance.get_activitypub_field(), 'snakeCaseName')
instance.name = "snake_case_name"
self.assertEqual(instance.get_activitypub_field(), "snakeCaseName")
def test_set_field_from_activity(self):
''' setter from entire json blob '''
""" setter from entire json blob """
@dataclass
class TestModel:
''' real simple mock '''
""" real simple mock """
field_name: str
mock_model = TestModel(field_name='bip')
TestActivity = namedtuple('test', ('fieldName', 'unrelated'))
data = TestActivity(fieldName='hi', unrelated='bfkjh')
mock_model = TestModel(field_name="bip")
TestActivity = namedtuple("test", ("fieldName", "unrelated"))
data = TestActivity(fieldName="hi", unrelated="bfkjh")
instance = fields.ActivitypubFieldMixin()
instance.name = 'field_name'
instance.name = "field_name"
instance.set_field_from_activity(mock_model, data)
self.assertEqual(mock_model.field_name, 'hi')
self.assertEqual(mock_model.field_name, "hi")
def test_set_activity_from_field(self):
''' set json field given entire model '''
""" set json field given entire model """
@dataclass
class TestModel:
''' real simple mock '''
""" real simple mock """
field_name: str
unrelated: str
mock_model = TestModel(field_name='bip', unrelated='field')
mock_model = TestModel(field_name="bip", unrelated="field")
instance = fields.ActivitypubFieldMixin()
instance.name = 'field_name'
instance.name = "field_name"
data = {}
instance.set_activity_from_field(data, mock_model)
self.assertEqual(data['fieldName'], 'bip')
self.assertEqual(data["fieldName"], "bip")
def test_remote_id_field(self):
''' just sets some defaults on charfield '''
""" just sets some defaults on charfield """
instance = fields.RemoteIdField()
self.assertEqual(instance.max_length, 255)
self.assertTrue(instance.deduplication_field)
with self.assertRaises(ValidationError):
instance.run_validators('http://www.example.com/dlfjg 23/x')
instance.run_validators("http://www.example.com/dlfjg 23/x")
def test_username_field(self):
''' again, just setting defaults on username field '''
""" again, just setting defaults on username field """
instance = fields.UsernameField()
self.assertEqual(instance.activitypub_field, 'preferredUsername')
self.assertEqual(instance.activitypub_field, "preferredUsername")
self.assertEqual(instance.max_length, 150)
self.assertEqual(instance.unique, True)
with self.assertRaises(ValidationError):
instance.run_validators('mouse')
instance.run_validators('mouseexample.com')
instance.run_validators('mouse@example.c')
instance.run_validators('@example.com')
instance.run_validators('mouse@examplecom')
instance.run_validators('one two@fish.aaaa')
instance.run_validators('a*&@exampke.com')
instance.run_validators('trailingwhite@example.com ')
self.assertIsNone(instance.run_validators('mouse@example.com'))
self.assertIsNone(instance.run_validators('mo-2use@ex3ample.com'))
self.assertIsNone(instance.run_validators('aksdhf@sdkjf-df.cm'))
self.assertEqual(instance.field_to_activity('test@example.com'), 'test')
instance.run_validators("mouse")
instance.run_validators("mouseexample.com")
instance.run_validators("mouse@example.c")
instance.run_validators("@example.com")
instance.run_validators("mouse@examplecom")
instance.run_validators("one two@fish.aaaa")
instance.run_validators("a*&@exampke.com")
instance.run_validators("trailingwhite@example.com ")
self.assertIsNone(instance.run_validators("mouse@example.com"))
self.assertIsNone(instance.run_validators("mo-2use@ex3ample.com"))
self.assertIsNone(instance.run_validators("aksdhf@sdkjf-df.cm"))
self.assertEqual(instance.field_to_activity("test@example.com"), "test")
def test_privacy_field_defaults(self):
''' post privacy field's many default values '''
""" post privacy field's many default values """
instance = fields.PrivacyField()
self.assertEqual(instance.max_length, 255)
self.assertEqual(
[c[0] for c in instance.choices],
['public', 'unlisted', 'followers', 'direct'])
self.assertEqual(instance.default, 'public')
["public", "unlisted", "followers", "direct"],
)
self.assertEqual(instance.default, "public")
self.assertEqual(
instance.public, 'https://www.w3.org/ns/activitystreams#Public')
instance.public, "https://www.w3.org/ns/activitystreams#Public"
)
def test_privacy_field_set_field_from_activity(self):
''' translate between to/cc fields and privacy '''
""" translate between to/cc fields and privacy """
@dataclass(init=False)
class TestActivity(ActivityObject):
''' real simple mock '''
""" real simple mock """
to: List[str]
cc: List[str]
id: str = 'http://hi.com'
type: str = 'Test'
id: str = "http://hi.com"
type: str = "Test"
class TestPrivacyModel(ActivitypubMixin, BookWyrmModel):
''' real simple mock model because BookWyrmModel is abstract '''
""" real simple mock model because BookWyrmModel is abstract """
privacy_field = fields.PrivacyField()
mention_users = fields.TagField(User)
user = fields.ForeignKey(User, on_delete=models.CASCADE)
public = 'https://www.w3.org/ns/activitystreams#Public'
public = "https://www.w3.org/ns/activitystreams#Public"
data = TestActivity(
to=[public],
cc=['bleh'],
cc=["bleh"],
)
model_instance = TestPrivacyModel(privacy_field='direct')
self.assertEqual(model_instance.privacy_field, 'direct')
model_instance = TestPrivacyModel(privacy_field="direct")
self.assertEqual(model_instance.privacy_field, "direct")
instance = fields.PrivacyField()
instance.name = 'privacy_field'
instance.name = "privacy_field"
instance.set_field_from_activity(model_instance, data)
self.assertEqual(model_instance.privacy_field, 'public')
self.assertEqual(model_instance.privacy_field, "public")
data.to = ['bleh']
data.to = ["bleh"]
data.cc = []
instance.set_field_from_activity(model_instance, data)
self.assertEqual(model_instance.privacy_field, 'direct')
self.assertEqual(model_instance.privacy_field, "direct")
data.to = ['bleh']
data.cc = [public, 'waah']
data.to = ["bleh"]
data.cc = [public, "waah"]
instance.set_field_from_activity(model_instance, data)
self.assertEqual(model_instance.privacy_field, 'unlisted')
self.assertEqual(model_instance.privacy_field, "unlisted")
@patch('bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast')
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
def test_privacy_field_set_activity_from_field(self, _):
''' translate between to/cc fields and privacy '''
""" translate between to/cc fields and privacy """
user = User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword',
local=True, localname='rat')
public = 'https://www.w3.org/ns/activitystreams#Public'
followers = '%s/followers' % user.remote_id
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
)
public = "https://www.w3.org/ns/activitystreams#Public"
followers = "%s/followers" % user.remote_id
instance = fields.PrivacyField()
instance.name = 'privacy_field'
instance.name = "privacy_field"
model_instance = Status.objects.create(user=user, content='hi')
model_instance = Status.objects.create(user=user, content="hi")
activity = {}
instance.set_activity_from_field(activity, model_instance)
self.assertEqual(activity['to'], [public])
self.assertEqual(activity['cc'], [followers])
self.assertEqual(activity["to"], [public])
self.assertEqual(activity["cc"], [followers])
model_instance = Status.objects.create(
user=user, content='hi', privacy='unlisted')
user=user, content="hi", privacy="unlisted"
)
activity = {}
instance.set_activity_from_field(activity, model_instance)
self.assertEqual(activity['to'], [followers])
self.assertEqual(activity['cc'], [public])
self.assertEqual(activity["to"], [followers])
self.assertEqual(activity["cc"], [public])
model_instance = Status.objects.create(
user=user, content='hi', privacy='followers')
user=user, content="hi", privacy="followers"
)
activity = {}
instance.set_activity_from_field(activity, model_instance)
self.assertEqual(activity['to'], [followers])
self.assertEqual(activity['cc'], [])
self.assertEqual(activity["to"], [followers])
self.assertEqual(activity["cc"], [])
model_instance = Status.objects.create(
user=user,
content='hi',
privacy='direct',
content="hi",
privacy="direct",
)
model_instance.mention_users.set([user])
activity = {}
instance.set_activity_from_field(activity, model_instance)
self.assertEqual(activity['to'], [user.remote_id])
self.assertEqual(activity['cc'], [])
self.assertEqual(activity["to"], [user.remote_id])
self.assertEqual(activity["cc"], [])
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'))
item = Serializable(lambda: {'a': 'b'}, 'https://e.b/c')
""" should be able to format a related model """
instance = fields.ForeignKey("User", on_delete=models.CASCADE)
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
item = Serializable(lambda: {"a": "b"}, "https://e.b/c")
# returns the remote_id field of the related object
self.assertEqual(instance.field_to_activity(item), 'https://e.b/c')
self.assertEqual(instance.field_to_activity(item), "https://e.b/c")
@responses.activate
def test_foreign_key_from_activity_str(self):
''' create a new object from a foreign key '''
""" 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')
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
userdata = json.loads(datafile.read_bytes())
# don't try to load the user icon
del userdata['icon']
del userdata["icon"]
# it shouldn't match with this unrelated user:
unrelated_user = User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword',
local=True, localname='rat')
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
)
# test receiving an unknown remote id and loading data
responses.add(
responses.GET,
'https://example.com/user/mouse',
json=userdata,
status=200)
with patch('bookwyrm.models.user.set_remote_server.delay'):
value = instance.field_from_activity(
'https://example.com/user/mouse')
responses.GET, "https://example.com/user/mouse", json=userdata, status=200
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
value = instance.field_from_activity("https://example.com/user/mouse")
self.assertIsInstance(value, User)
self.assertNotEqual(value, unrelated_user)
self.assertEqual(value.remote_id, 'https://example.com/user/mouse')
self.assertEqual(value.name, 'MOUSE?? MOUSE!!')
self.assertEqual(value.remote_id, "https://example.com/user/mouse")
self.assertEqual(value.name, "MOUSE?? MOUSE!!")
def test_foreign_key_from_activity_dict(self):
''' test recieving activity json '''
""" test recieving activity json """
instance = fields.ForeignKey(User, on_delete=models.CASCADE)
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ap_user.json')
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
userdata = json.loads(datafile.read_bytes())
# don't try to load the user icon
del userdata['icon']
del userdata["icon"]
# it shouldn't match with this unrelated user:
unrelated_user = User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword',
local=True, localname='rat')
with patch('bookwyrm.models.user.set_remote_server.delay'):
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
value = instance.field_from_activity(activitypub.Person(**userdata))
self.assertIsInstance(value, User)
self.assertNotEqual(value, unrelated_user)
self.assertEqual(value.remote_id, 'https://example.com/user/mouse')
self.assertEqual(value.name, 'MOUSE?? MOUSE!!')
self.assertEqual(value.remote_id, "https://example.com/user/mouse")
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):
''' test receiving a dict of an existing object in the db '''
""" 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'
)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
userdata = json.loads(datafile.read_bytes())
user = User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse')
user.remote_id = 'https://example.com/user/mouse'
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
user.remote_id = "https://example.com/user/mouse"
user.save(broadcast=False)
User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword',
local=True, localname='rat')
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
)
with patch('bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast'):
with patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast"):
value = instance.field_from_activity(activitypub.Person(**userdata))
self.assertEqual(value, user)
def test_foreign_key_from_activity_str_existing(self):
''' test receiving a remote id of an existing object in the db '''
""" 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(
'mouse', 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse')
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword',
local=True, localname='rat')
"rat", "rat@rat.rat", "ratword", local=True, localname="rat"
)
value = instance.field_from_activity(user.remote_id)
self.assertEqual(value, user)
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'})
""" 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):
''' lists! '''
instance = fields.ManyToManyField('User')
""" lists! """
instance = fields.ManyToManyField("User")
Serializable = namedtuple('Serializable', ('to_activity', 'remote_id'))
Queryset = namedtuple('Queryset', ('all', 'instance'))
item = Serializable(lambda: {'a': 'b'}, 'https://e.b/c')
another_item = Serializable(lambda: {}, 'example.com')
Serializable = namedtuple("Serializable", ("to_activity", "remote_id"))
Queryset = namedtuple("Queryset", ("all", "instance"))
item = Serializable(lambda: {"a": "b"}, "https://e.b/c")
another_item = Serializable(lambda: {}, "example.com")
items = Queryset(lambda: [item], another_item)
self.assertEqual(instance.field_to_activity(items), ['https://e.b/c'])
self.assertEqual(instance.field_to_activity(items), ["https://e.b/c"])
instance = fields.ManyToManyField('User', link_only=True)
instance.name = 'snake_case'
self.assertEqual(
instance.field_to_activity(items),
'example.com/snake_case'
)
instance = fields.ManyToManyField("User", link_only=True)
instance.name = "snake_case"
self.assertEqual(instance.field_to_activity(items), "example.com/snake_case")
@responses.activate
def test_many_to_many_field_from_activity(self):
''' resolve related fields for a list, takes a list of remote ids '''
""" 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'
)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
userdata = json.loads(datafile.read_bytes())
# don't try to load the user icon
del userdata['icon']
del userdata["icon"]
# test receiving an unknown remote id and loading data
responses.add(
responses.GET,
'https://example.com/user/mouse',
json=userdata,
status=200)
with patch('bookwyrm.models.user.set_remote_server.delay'):
responses.GET, "https://example.com/user/mouse", json=userdata, status=200
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
value = instance.field_from_activity(
['https://example.com/user/mouse', 'bleh']
["https://example.com/user/mouse", "bleh"]
)
self.assertIsInstance(value, list)
self.assertEqual(len(value), 1)
self.assertIsInstance(value[0], User)
def test_tag_field(self):
''' a special type of many to many field '''
instance = fields.TagField('User')
""" a special type of many to many field """
instance = fields.TagField("User")
Serializable = namedtuple(
'Serializable',
('to_activity', 'remote_id', 'name_field', 'name')
"Serializable", ("to_activity", "remote_id", "name_field", "name")
)
Queryset = namedtuple('Queryset', ('all', 'instance'))
item = Serializable(
lambda: {'a': 'b'}, 'https://e.b/c', 'name', 'Name')
another_item = Serializable(
lambda: {}, 'example.com', '', '')
Queryset = namedtuple("Queryset", ("all", "instance"))
item = Serializable(lambda: {"a": "b"}, "https://e.b/c", "name", "Name")
another_item = Serializable(lambda: {}, "example.com", "", "")
items = Queryset(lambda: [item], another_item)
result = instance.field_to_activity(items)
self.assertIsInstance(result, list)
self.assertEqual(len(result), 1)
self.assertEqual(result[0].href, 'https://e.b/c')
self.assertEqual(result[0].name, 'Name')
self.assertEqual(result[0].type, 'Serializable')
self.assertEqual(result[0].href, "https://e.b/c")
self.assertEqual(result[0].name, "Name")
self.assertEqual(result[0].type, "Serializable")
def test_tag_field_from_activity(self):
''' loadin' a list of items from Links '''
""" loadin' a list of items from Links """
# TODO
@responses.activate
@patch('bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast')
@patch("bookwyrm.models.activitypub_mixin.ObjectMixin.broadcast")
def test_image_field(self, _):
''' storing images '''
""" storing images """
user = User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse')
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
image_file = pathlib.Path(__file__).parent.joinpath(
'../../static/images/default_avi.jpg')
"../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
image.save(output, format=image.format)
user.avatar.save(
'test.jpg',
ContentFile(output.getvalue())
)
user.avatar.save("test.jpg", ContentFile(output.getvalue()))
output = fields.image_serializer(user.avatar, alt='alt text')
output = fields.image_serializer(user.avatar, alt="alt text")
self.assertIsNotNone(
re.match(
r'.*\.jpg',
r".*\.jpg",
output.url,
)
)
self.assertEqual(output.name, 'alt text')
self.assertEqual(output.type, 'Image')
self.assertEqual(output.name, "alt text")
self.assertEqual(output.type, "Image")
instance = fields.ImageField()
@@ -433,36 +413,30 @@ class ActivitypubFields(TestCase):
responses.add(
responses.GET,
'http://www.example.com/image.jpg',
"http://www.example.com/image.jpg",
body=user.avatar.file.read(),
status=200)
loaded_image = instance.field_from_activity(
'http://www.example.com/image.jpg')
status=200,
)
loaded_image = instance.field_from_activity("http://www.example.com/image.jpg")
self.assertIsInstance(loaded_image, list)
self.assertIsInstance(loaded_image[1], ContentFile)
def test_datetime_field(self):
''' this one is pretty simple, it just has to use isoformat '''
""" this one is pretty simple, it just has to use isoformat """
instance = fields.DateTimeField()
now = timezone.now()
self.assertEqual(instance.field_to_activity(now), now.isoformat())
self.assertEqual(
instance.field_from_activity(now.isoformat()), now
)
self.assertEqual(instance.field_from_activity('bip'), None)
self.assertEqual(instance.field_from_activity(now.isoformat()), now)
self.assertEqual(instance.field_from_activity("bip"), None)
def test_array_field(self):
''' idk why it makes them strings but probably for a good reason '''
""" 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'])
self.assertEqual(instance.field_to_activity([0, 1]), ["0", "1"])
def test_html_field(self):
''' sanitizes html, the sanitizer has its own tests '''
""" sanitizes html, the sanitizer has its own tests """
instance = fields.HtmlField()
self.assertEqual(
instance.field_from_activity('<marquee><p>hi</p></marquee>'),
'<p>hi</p>'
instance.field_from_activity("<marquee><p>hi</p></marquee>"), "<p>hi</p>"
)

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
import datetime
import json
import pathlib
@@ -14,165 +14,166 @@ from bookwyrm.connectors.abstract_connector import SearchResult
class ImportJob(TestCase):
''' this is a fancy one!!! '''
""" this is a fancy one!!! """
def setUp(self):
''' data is from a goodreads export of The Raven Tower '''
""" data is from a goodreads export of The Raven Tower """
read_data = {
'Book Id': 39395857,
'Title': 'The Raven Tower',
'Author': 'Ann Leckie',
'Author l-f': 'Leckie, Ann',
'Additional Authors': '',
'ISBN': '="0356506991"',
'ISBN13': '="9780356506999"',
'My Rating': 0,
'Average Rating': 4.06,
'Publisher': 'Orbit',
'Binding': 'Hardcover',
'Number of Pages': 416,
'Year Published': 2019,
'Original Publication Year': 2019,
'Date Read': '2019/04/12',
'Date Added': '2019/04/09',
'Bookshelves': '',
'Bookshelves with positions': '',
'Exclusive Shelf': 'read',
'My Review': '',
'Spoiler': '',
'Private Notes': '',
'Read Count': 1,
'Recommended For': '',
'Recommended By': '',
'Owned Copies': 0,
'Original Purchase Date': '',
'Original Purchase Location': '',
'Condition': '',
'Condition Description': '',
'BCID': ''
"Book Id": 39395857,
"Title": "The Raven Tower",
"Author": "Ann Leckie",
"Author l-f": "Leckie, Ann",
"Additional Authors": "",
"ISBN": '="0356506991"',
"ISBN13": '="9780356506999"',
"My Rating": 0,
"Average Rating": 4.06,
"Publisher": "Orbit",
"Binding": "Hardcover",
"Number of Pages": 416,
"Year Published": 2019,
"Original Publication Year": 2019,
"Date Read": "2019/04/12",
"Date Added": "2019/04/09",
"Bookshelves": "",
"Bookshelves with positions": "",
"Exclusive Shelf": "read",
"My Review": "",
"Spoiler": "",
"Private Notes": "",
"Read Count": 1,
"Recommended For": "",
"Recommended By": "",
"Owned Copies": 0,
"Original Purchase Date": "",
"Original Purchase Location": "",
"Condition": "",
"Condition Description": "",
"BCID": "",
}
currently_reading_data = read_data.copy()
currently_reading_data['Exclusive Shelf'] = 'currently-reading'
currently_reading_data['Date Read'] = ''
currently_reading_data["Exclusive Shelf"] = "currently-reading"
currently_reading_data["Date Read"] = ""
unknown_read_data = currently_reading_data.copy()
unknown_read_data['Exclusive Shelf'] = 'read'
unknown_read_data['Date Read'] = ''
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')
"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)
self.item_2 = models.ImportItem.objects.create(
job=job, index=2, data=read_data)
job=job, index=1, data=currently_reading_data
)
self.item_2 = models.ImportItem.objects.create(job=job, index=2, data=read_data)
self.item_3 = models.ImportItem.objects.create(
job=job, index=3, data=unknown_read_data)
job=job, index=3, data=unknown_read_data
)
def test_isbn(self):
''' it unquotes the isbn13 field from data '''
expected = '9780356506999'
""" it unquotes the isbn13 field from data """
expected = "9780356506999"
item = models.ImportItem.objects.get(index=1)
self.assertEqual(item.isbn, expected)
def test_shelf(self):
''' converts to the local shelf typology '''
expected = 'reading'
""" converts to the local shelf typology """
expected = "reading"
self.assertEqual(self.item_1.shelf, expected)
def test_date_added(self):
''' converts to the local shelf typology '''
""" converts to the local shelf typology """
expected = datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc)
item = models.ImportItem.objects.get(index=1)
self.assertEqual(item.date_added, expected)
def test_date_read(self):
''' converts to the local shelf typology '''
""" converts to the local shelf typology """
expected = datetime.datetime(2019, 4, 12, 0, 0, tzinfo=timezone.utc)
item = models.ImportItem.objects.get(index=2)
self.assertEqual(item.date_read, expected)
def test_currently_reading_reads(self):
''' infer currently reading dates where available '''
expected = [models.ReadThrough(
start_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc)
)]
""" infer currently reading dates where available """
expected = [
models.ReadThrough(
start_date=datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc)
)
]
actual = models.ImportItem.objects.get(index=1)
self.assertEqual(actual.reads[0].start_date, expected[0].start_date)
self.assertEqual(actual.reads[0].finish_date, expected[0].finish_date)
def test_read_reads(self):
''' infer read dates where available '''
""" infer read dates where available """
actual = self.item_2
self.assertEqual(
actual.reads[0].start_date,
datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc))
datetime.datetime(2019, 4, 9, 0, 0, tzinfo=timezone.utc),
)
self.assertEqual(
actual.reads[0].finish_date,
datetime.datetime(2019, 4, 12, 0, 0, tzinfo=timezone.utc))
datetime.datetime(2019, 4, 12, 0, 0, tzinfo=timezone.utc),
)
def test_unread_reads(self):
''' handle books with no read dates '''
""" handle books with no read dates """
expected = []
actual = models.ImportItem.objects.get(index=3)
self.assertEqual(actual.reads, expected)
@responses.activate
def test_get_book_from_isbn(self):
''' search and load books by isbn (9780356506999) '''
""" search and load books by isbn (9780356506999) """
connector_info = models.Connector.objects.create(
identifier='openlibrary.org',
name='OpenLibrary',
connector_file='openlibrary',
base_url='https://openlibrary.org',
books_url='https://openlibrary.org',
covers_url='https://covers.openlibrary.org',
search_url='https://openlibrary.org/search?q=',
identifier="openlibrary.org",
name="OpenLibrary",
connector_file="openlibrary",
base_url="https://openlibrary.org",
books_url="https://openlibrary.org",
covers_url="https://covers.openlibrary.org",
search_url="https://openlibrary.org/search?q=",
priority=3,
)
connector = connector_manager.load_connector(connector_info)
result = SearchResult(
title='Test Result',
key='https://openlibrary.org/works/OL1234W',
author='An Author',
year='1980',
title="Test Result",
key="https://openlibrary.org/works/OL1234W",
author="An Author",
year="1980",
connector=connector,
)
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ol_edition.json')
datafile = pathlib.Path(__file__).parent.joinpath("../data/ol_edition.json")
bookdata = json.loads(datafile.read_bytes())
responses.add(
responses.GET,
'https://openlibrary.org/works/OL1234W',
"https://openlibrary.org/works/OL1234W",
json=bookdata,
status=200)
status=200,
)
responses.add(
responses.GET,
'https://openlibrary.org/works/OL15832982W',
"https://openlibrary.org/works/OL15832982W",
json=bookdata,
status=200)
status=200,
)
responses.add(
responses.GET,
'https://openlibrary.org/authors/OL382982A',
json={'name': 'test author'},
status=200)
"https://openlibrary.org/authors/OL382982A",
json={"name": "test author"},
status=200,
)
with patch(
'bookwyrm.connectors.abstract_connector.load_more_data.delay'):
with patch("bookwyrm.connectors.abstract_connector.load_more_data.delay"):
with patch(
'bookwyrm.connectors.connector_manager.first_search_result'
) as search:
"bookwyrm.connectors.connector_manager.first_search_result"
) as search:
search.return_value = result
with patch('bookwyrm.connectors.openlibrary.Connector.' \
'get_authors_from_data'):
with patch(
"bookwyrm.connectors.openlibrary.Connector." "get_authors_from_data"
):
book = self.item_1.get_book_from_isbn()
self.assertEqual(book.title, 'Sabriel')
self.assertEqual(book.title, "Sabriel")

View File

@@ -1,43 +1,41 @@
''' testing models '''
""" 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')
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class List(TestCase):
''' some activitypub oddness ahead '''
""" some activitypub oddness ahead """
def setUp(self):
''' look, a list '''
""" look, a list """
self.user = models.User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse')
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
self.list = models.List.objects.create(
name='Test List', user=self.user)
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.list = models.List.objects.create(name="Test List", user=self.user)
def test_remote_id(self, _):
''' shelves use custom remote ids '''
expected_id = 'https://%s/list/%d' % \
(settings.DOMAIN, self.list.id)
""" shelves use custom remote ids """
expected_id = "https://%s/list/%d" % (settings.DOMAIN, self.list.id)
self.assertEqual(self.list.get_remote_id(), expected_id)
def test_to_activity(self, _):
''' jsonify it '''
""" jsonify it """
activity_json = self.list.to_activity()
self.assertIsInstance(activity_json, dict)
self.assertEqual(activity_json['id'], self.list.remote_id)
self.assertEqual(activity_json['totalItems'], 0)
self.assertEqual(activity_json['type'], 'BookList')
self.assertEqual(activity_json['name'], 'Test List')
self.assertEqual(activity_json['owner'], self.user.remote_id)
self.assertEqual(activity_json["id"], self.list.remote_id)
self.assertEqual(activity_json["totalItems"], 0)
self.assertEqual(activity_json["type"], "BookList")
self.assertEqual(activity_json["name"], "Test List")
self.assertEqual(activity_json["owner"], self.user.remote_id)
def test_list_item(self, _):
''' a list entry '''
work = models.Work.objects.create(title='hello')
book = models.Edition.objects.create(title='hi', parent_work=work)
""" a list entry """
work = models.Work.objects.create(title="hello")
book = models.Edition.objects.create(title="hi", parent_work=work)
item = models.ListItem.objects.create(
book_list=self.list,
book=book,
@@ -47,11 +45,11 @@ class List(TestCase):
self.assertTrue(item.approved)
add_activity = item.to_add_activity()
self.assertEqual(add_activity['actor'], self.user.remote_id)
self.assertEqual(add_activity['object']['id'], book.remote_id)
self.assertEqual(add_activity['target'], self.list.remote_id)
self.assertEqual(add_activity["actor"], self.user.remote_id)
self.assertEqual(add_activity["object"]["id"], book.remote_id)
self.assertEqual(add_activity["target"], self.list.remote_id)
remove_activity = item.to_remove_activity()
self.assertEqual(remove_activity['actor'], self.user.remote_id)
self.assertEqual(remove_activity['object']['id'], book.remote_id)
self.assertEqual(remove_activity['target'], self.list.remote_id)
self.assertEqual(remove_activity["actor"], self.user.remote_id)
self.assertEqual(remove_activity["object"]["id"], book.remote_id)
self.assertEqual(remove_activity["target"], self.list.remote_id)

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
from django.test import TestCase
from django.core.exceptions import ValidationError
@@ -6,39 +6,36 @@ from bookwyrm import models, settings
class ReadThrough(TestCase):
''' some activitypub oddness ahead '''
def setUp(self):
''' look, a shelf '''
self.user = models.User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse')
""" some activitypub oddness ahead """
self.work = models.Work.objects.create(
title='Example Work'
def setUp(self):
""" look, a shelf """
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
title="Example Edition", parent_work=self.work
)
self.work.default_edition = self.edition
self.work.save()
self.readthrough = models.ReadThrough.objects.create(
user=self.user,
book=self.edition)
user=self.user, book=self.edition
)
def test_progress_update(self):
''' Test progress updates '''
self.readthrough.create_update() # No-op, no progress yet
""" 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()
updates = self.readthrough.progressupdate_set \
.order_by('created_date').all()
updates = self.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)

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
from unittest.mock import patch
from django.test import TestCase
@@ -6,87 +6,79 @@ from bookwyrm import models
class Relationship(TestCase):
''' following, blocking, stuff like that '''
""" following, blocking, stuff like that """
def setUp(self):
''' we need some users for this '''
with patch('bookwyrm.models.user.set_remote_server.delay'):
""" we need some users for this """
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@rat.com', 'ratword',
"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',
remote_id="https://example.com/users/rat",
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')
self.local_user.remote_id = 'http://local.com/user/mouse'
"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)
def test_user_follows_from_request(self):
''' convert a follow request into a follow '''
""" convert a follow request into a follow """
real_broadcast = models.UserFollowRequest.broadcast
def mock_broadcast(_, activity, user):
''' introspect what's being sent out '''
""" introspect what's being sent out """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Follow')
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
user_subject=self.local_user, user_object=self.remote_user
)
self.assertEqual(
request.remote_id,
'http://local.com/user/mouse#follows/%d' % request.id
request.remote_id, "http://local.com/user/mouse#follows/%d" % request.id
)
self.assertEqual(request.status, 'follow_request')
self.assertEqual(request.status, "follow_request")
rel = models.UserFollows.from_request(request)
self.assertEqual(
rel.remote_id,
'http://local.com/user/mouse#follows/%d' % request.id
rel.remote_id, "http://local.com/user/mouse#follows/%d" % request.id
)
self.assertEqual(rel.status, 'follows')
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):
''' store a specific remote id for a relationship provided by remote '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" 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(
user_subject=self.local_user,
user_object=self.remote_user,
remote_id='http://antoher.server/sdkfhskdjf/23'
remote_id="http://antoher.server/sdkfhskdjf/23",
)
self.assertEqual(
request.remote_id,
'http://antoher.server/sdkfhskdjf/23'
)
self.assertEqual(request.status, 'follow_request')
self.assertEqual(request.remote_id, "http://antoher.server/sdkfhskdjf/23")
self.assertEqual(request.status, "follow_request")
rel = models.UserFollows.from_request(request)
self.assertEqual(
rel.remote_id,
'http://antoher.server/sdkfhskdjf/23'
)
self.assertEqual(rel.status, 'follows')
self.assertEqual(rel.remote_id, "http://antoher.server/sdkfhskdjf/23")
self.assertEqual(rel.status, "follows")
self.assertEqual(rel.user_subject, self.local_user)
self.assertEqual(rel.user_object, self.remote_user)
def test_follow_request_activity(self):
''' accept a request and make it a relationship '''
""" 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')
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(
@@ -95,15 +87,15 @@ class Relationship(TestCase):
)
models.UserFollowRequest.broadcast = real_broadcast
def test_follow_request_accept(self):
''' accept a request and make it a relationship '''
""" 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.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)
@@ -111,7 +103,7 @@ class Relationship(TestCase):
request = models.UserFollowRequest.objects.create(
user_subject=self.remote_user,
user_object=self.local_user,
remote_id='https://www.hi.com/'
remote_id="https://www.hi.com/",
)
request.accept()
@@ -122,16 +114,15 @@ class Relationship(TestCase):
self.assertEqual(rel.user_object, self.local_user)
models.UserFollowRequest.broadcast = real_broadcast
def test_follow_request_reject(self):
''' accept a request and make it a relationship '''
""" 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)
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

View File

@@ -1,116 +1,120 @@
''' testing models '''
""" testing models """
from django.test import TestCase
from bookwyrm import models, settings
#pylint: disable=unused-argument
# pylint: disable=unused-argument
class Shelf(TestCase):
''' some activitypub oddness ahead '''
""" some activitypub oddness ahead """
def setUp(self):
''' look, a shelf '''
""" look, a shelf """
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)
"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):
''' shelves use custom remote ids '''
""" shelves use custom remote ids """
real_broadcast = models.Shelf.broadcast
def broadcast_mock(_, activity, user, **kwargs):
''' nah '''
""" nah """
models.Shelf.broadcast = broadcast_mock
shelf = models.Shelf.objects.create(
name='Test Shelf', identifier='test-shelf',
user=self.local_user)
expected_id = 'https://%s/user/mouse/shelf/test-shelf' % settings.DOMAIN
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
expected_id = "https://%s/user/mouse/shelf/test-shelf" % settings.DOMAIN
self.assertEqual(shelf.get_remote_id(), expected_id)
models.Shelf.broadcast = real_broadcast
def test_to_activity(self):
''' jsonify it '''
""" jsonify it """
real_broadcast = models.Shelf.broadcast
def empty_mock(_, activity, user, **kwargs):
''' nah '''
""" nah """
models.Shelf.broadcast = empty_mock
shelf = models.Shelf.objects.create(
name='Test Shelf', identifier='test-shelf',
user=self.local_user)
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
activity_json = shelf.to_activity()
self.assertIsInstance(activity_json, dict)
self.assertEqual(activity_json['id'], shelf.remote_id)
self.assertEqual(activity_json['totalItems'], 0)
self.assertEqual(activity_json['type'], 'Shelf')
self.assertEqual(activity_json['name'], 'Test Shelf')
self.assertEqual(activity_json['owner'], self.local_user.remote_id)
self.assertEqual(activity_json["id"], shelf.remote_id)
self.assertEqual(activity_json["totalItems"], 0)
self.assertEqual(activity_json["type"], "Shelf")
self.assertEqual(activity_json["name"], "Test Shelf")
self.assertEqual(activity_json["owner"], self.local_user.remote_id)
models.Shelf.broadcast = real_broadcast
def test_create_update_shelf(self):
''' create and broadcast shelf creation '''
""" create and broadcast shelf creation """
real_broadcast = models.Shelf.broadcast
def create_mock(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Create')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['object']['name'], 'Test Shelf')
self.assertEqual(activity["type"], "Create")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["name"], "Test Shelf")
models.Shelf.broadcast = create_mock
shelf = models.Shelf.objects.create(
name='Test Shelf', identifier='test-shelf', user=self.local_user)
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
def update_mock(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Update')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['object']['name'], 'arthur russel')
self.assertEqual(activity["type"], "Update")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["name"], "arthur russel")
models.Shelf.broadcast = update_mock
shelf.name = 'arthur russel'
shelf.name = "arthur russel"
shelf.save()
self.assertEqual(shelf.name, 'arthur russel')
self.assertEqual(shelf.name, "arthur russel")
models.Shelf.broadcast = real_broadcast
def test_shelve(self):
''' create and broadcast shelf creation '''
""" create and broadcast shelf creation """
real_broadcast = models.Shelf.broadcast
real_shelfbook_broadcast = models.ShelfBook.broadcast
def add_mock(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Add')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['object']['id'], self.book.remote_id)
self.assertEqual(activity['target'], shelf.remote_id)
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], self.book.remote_id)
self.assertEqual(activity["target"], shelf.remote_id)
def remove_mock(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Remove')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['object']['id'], self.book.remote_id)
self.assertEqual(activity['target'], shelf.remote_id)
self.assertEqual(activity["type"], "Remove")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], self.book.remote_id)
self.assertEqual(activity["target"], shelf.remote_id)
def empty_mock(_, activity, user, **kwargs):
''' nah '''
""" nah """
models.Shelf.broadcast = empty_mock
shelf = models.Shelf.objects.create(
name='Test Shelf', identifier='test-shelf', user=self.local_user)
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
models.ShelfBook.broadcast = add_mock
shelf_book = models.ShelfBook.objects.create(
shelf=shelf,
user=self.local_user,
book=self.book)
shelf=shelf, user=self.local_user, book=self.book
)
self.assertEqual(shelf.books.first(), self.book)
models.ShelfBook.broadcast = remove_mock

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
from unittest.mock import patch
from io import BytesIO
import pathlib
@@ -12,44 +12,45 @@ from django.utils import timezone
from bookwyrm import models, settings
@patch('bookwyrm.models.Status.broadcast')
@patch("bookwyrm.models.Status.broadcast")
class Status(TestCase):
''' lotta types of statuses '''
""" lotta types of statuses """
def setUp(self):
''' useful things for creating a status '''
""" useful things for creating a status """
self.user = models.User.objects.create_user(
'mouse', 'mouse@mouse.mouse', 'mouseword',
local=True, localname='mouse')
self.book = models.Edition.objects.create(title='Test Edition')
"mouse", "mouse@mouse.mouse", "mouseword", local=True, localname="mouse"
)
self.book = models.Edition.objects.create(title="Test Edition")
image_file = pathlib.Path(__file__).parent.joinpath(
'../../static/images/default_avi.jpg')
"../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
with patch('bookwyrm.models.Status.broadcast'):
with patch("bookwyrm.models.Status.broadcast"):
image.save(output, format=image.format)
self.book.cover.save(
'test.jpg',
ContentFile(output.getvalue())
)
self.book.cover.save("test.jpg", ContentFile(output.getvalue()))
def test_status_generated_fields(self, _):
''' setting remote id '''
status = models.Status.objects.create(content='bleh', user=self.user)
expected_id = 'https://%s/user/mouse/status/%d' % \
(settings.DOMAIN, status.id)
""" setting remote id """
status = models.Status.objects.create(content="bleh", user=self.user)
expected_id = "https://%s/user/mouse/status/%d" % (settings.DOMAIN, status.id)
self.assertEqual(status.remote_id, expected_id)
self.assertEqual(status.privacy, 'public')
self.assertEqual(status.privacy, "public")
def test_replies(self, _):
''' get a list of replies '''
parent = models.Status.objects.create(content='hi', user=self.user)
""" get a list of replies """
parent = models.Status.objects.create(content="hi", user=self.user)
child = models.Status.objects.create(
content='hello', reply_parent=parent, user=self.user)
content="hello", reply_parent=parent, user=self.user
)
models.Review.objects.create(
content='hey', reply_parent=parent, user=self.user, book=self.book)
content="hey", reply_parent=parent, user=self.user, book=self.book
)
models.Status.objects.create(
content='hi hello', reply_parent=child, user=self.user)
content="hi hello", reply_parent=child, user=self.user
)
replies = models.Status.replies(parent)
self.assertEqual(replies.count(), 2)
@@ -58,199 +59,228 @@ class Status(TestCase):
self.assertIsInstance(replies.last(), models.Review)
def test_status_type(self, _):
''' class name '''
self.assertEqual(models.Status().status_type, 'Note')
self.assertEqual(models.Review().status_type, 'Review')
self.assertEqual(models.Quotation().status_type, 'Quotation')
self.assertEqual(models.Comment().status_type, 'Comment')
self.assertEqual(models.Boost().status_type, 'Announce')
""" class name """
self.assertEqual(models.Status().status_type, "Note")
self.assertEqual(models.Review().status_type, "Review")
self.assertEqual(models.Quotation().status_type, "Quotation")
self.assertEqual(models.Comment().status_type, "Comment")
self.assertEqual(models.Boost().status_type, "Announce")
def test_boostable(self, _):
''' can a status be boosted, based on privacy '''
self.assertTrue(models.Status(privacy='public').boostable)
self.assertTrue(models.Status(privacy='unlisted').boostable)
self.assertFalse(models.Status(privacy='followers').boostable)
self.assertFalse(models.Status(privacy='direct').boostable)
""" can a status be boosted, based on privacy """
self.assertTrue(models.Status(privacy="public").boostable)
self.assertTrue(models.Status(privacy="unlisted").boostable)
self.assertFalse(models.Status(privacy="followers").boostable)
self.assertFalse(models.Status(privacy="direct").boostable)
def test_to_replies(self, _):
''' activitypub replies collection '''
parent = models.Status.objects.create(content='hi', user=self.user)
""" activitypub replies collection """
parent = models.Status.objects.create(content="hi", user=self.user)
child = models.Status.objects.create(
content='hello', reply_parent=parent, user=self.user)
content="hello", reply_parent=parent, user=self.user
)
models.Review.objects.create(
content='hey', reply_parent=parent, user=self.user, book=self.book)
content="hey", reply_parent=parent, user=self.user, book=self.book
)
models.Status.objects.create(
content='hi hello', reply_parent=child, user=self.user)
content="hi hello", reply_parent=child, user=self.user
)
replies = parent.to_replies()
self.assertEqual(replies['id'], '%s/replies' % parent.remote_id)
self.assertEqual(replies['totalItems'], 2)
self.assertEqual(replies["id"], "%s/replies" % parent.remote_id)
self.assertEqual(replies["totalItems"], 2)
def test_status_to_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
status = models.Status.objects.create(
content='test content', user=self.user)
""" subclass of the base model version with a "pure" serializer """
status = models.Status.objects.create(content="test content", user=self.user)
activity = status.to_activity()
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Note')
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['sensitive'], False)
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Note")
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["sensitive"], False)
def test_status_to_activity_tombstone(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Status.objects.create(
content='test content', user=self.user,
deleted=True, deleted_date=timezone.now())
content="test content",
user=self.user,
deleted=True,
deleted_date=timezone.now(),
)
activity = status.to_activity()
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Tombstone')
self.assertFalse(hasattr(activity, 'content'))
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Tombstone")
self.assertFalse(hasattr(activity, "content"))
def test_status_to_pure_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
status = models.Status.objects.create(
content='test content', user=self.user)
""" subclass of the base model version with a "pure" serializer """
status = models.Status.objects.create(content="test content", user=self.user)
activity = status.to_activity(pure=True)
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Note')
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['sensitive'], False)
self.assertEqual(activity['attachment'], [])
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Note")
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["sensitive"], False)
self.assertEqual(activity["attachment"], [])
def test_generated_note_to_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.GeneratedNote.objects.create(
content='test content', user=self.user)
content="test content", user=self.user
)
status.mention_books.set([self.book])
status.mention_users.set([self.user])
activity = status.to_activity()
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'GeneratedNote')
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['sensitive'], False)
self.assertEqual(len(activity['tag']), 2)
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "GeneratedNote")
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["sensitive"], False)
self.assertEqual(len(activity["tag"]), 2)
def test_generated_note_to_pure_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.GeneratedNote.objects.create(
content='test content', user=self.user)
content="test content", user=self.user
)
status.mention_books.set([self.book])
status.mention_users.set([self.user])
activity = status.to_activity(pure=True)
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(
activity['content'],
'mouse test content <a href="%s">"Test Edition"</a>' % \
self.book.remote_id)
self.assertEqual(len(activity['tag']), 2)
self.assertEqual(activity['type'], 'Note')
self.assertEqual(activity['sensitive'], False)
self.assertIsInstance(activity['attachment'], list)
self.assertEqual(activity['attachment'][0].type, 'Image')
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
(settings.DOMAIN, self.book.cover.url))
activity["content"],
'mouse test content <a href="%s">"Test Edition"</a>' % self.book.remote_id,
)
self.assertEqual(len(activity["tag"]), 2)
self.assertEqual(activity["type"], "Note")
self.assertEqual(activity["sensitive"], False)
self.assertIsInstance(activity["attachment"], list)
self.assertEqual(activity["attachment"][0].type, "Image")
self.assertEqual(
activity['attachment'][0].name, 'Test Edition')
activity["attachment"][0].url,
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
def test_comment_to_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Comment.objects.create(
content='test content', user=self.user, book=self.book)
content="test content", user=self.user, book=self.book
)
activity = status.to_activity()
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Comment')
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['inReplyToBook'], self.book.remote_id)
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Comment")
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["inReplyToBook"], self.book.remote_id)
def test_comment_to_pure_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Comment.objects.create(
content='test content', user=self.user, book=self.book)
content="test content", user=self.user, book=self.book
)
activity = status.to_activity(pure=True)
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Note')
self.assertEqual(activity["id"], status.remote_id)
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)
self.assertEqual(activity['attachment'][0].type, 'Image')
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
(settings.DOMAIN, self.book.cover.url))
activity["content"],
'test content<p>(comment on <a href="%s">"Test Edition"</a>)</p>'
% self.book.remote_id,
)
self.assertEqual(activity["attachment"][0].type, "Image")
self.assertEqual(
activity['attachment'][0].name, 'Test Edition')
activity["attachment"][0].url,
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
def test_quotation_to_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Quotation.objects.create(
quote='a sickening sense', content='test content',
user=self.user, book=self.book)
quote="a sickening sense",
content="test content",
user=self.user,
book=self.book,
)
activity = status.to_activity()
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Quotation')
self.assertEqual(activity['quote'], 'a sickening sense')
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['inReplyToBook'], self.book.remote_id)
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Quotation")
self.assertEqual(activity["quote"], "a sickening sense")
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["inReplyToBook"], self.book.remote_id)
def test_quotation_to_pure_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Quotation.objects.create(
quote='a sickening sense', content='test content',
user=self.user, book=self.book)
quote="a sickening sense",
content="test content",
user=self.user,
book=self.book,
)
activity = status.to_activity(pure=True)
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Note')
self.assertEqual(activity["id"], status.remote_id)
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)
self.assertEqual(activity['attachment'][0].type, 'Image')
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
(settings.DOMAIN, self.book.cover.url))
activity["content"],
'a sickening sense <p>-- <a href="%s">"Test Edition"</a></p>'
"test content" % self.book.remote_id,
)
self.assertEqual(activity["attachment"][0].type, "Image")
self.assertEqual(
activity['attachment'][0].name, 'Test Edition')
activity["attachment"][0].url,
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
def test_review_to_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Review.objects.create(
name='Review name', content='test content', rating=3,
user=self.user, book=self.book)
name="Review name",
content="test content",
rating=3,
user=self.user,
book=self.book,
)
activity = status.to_activity()
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Review')
self.assertEqual(activity['rating'], 3)
self.assertEqual(activity['name'], 'Review name')
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['inReplyToBook'], self.book.remote_id)
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Review")
self.assertEqual(activity["rating"], 3)
self.assertEqual(activity["name"], "Review name")
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["inReplyToBook"], self.book.remote_id)
def test_review_to_pure_activity(self, _):
''' subclass of the base model version with a "pure" serializer '''
""" subclass of the base model version with a "pure" serializer """
status = models.Review.objects.create(
name='Review name', content='test content', rating=3,
user=self.user, book=self.book)
name="Review name",
content="test content",
rating=3,
user=self.user,
book=self.book,
)
activity = status.to_activity(pure=True)
self.assertEqual(activity['id'], status.remote_id)
self.assertEqual(activity['type'], 'Article')
self.assertEqual(activity["id"], status.remote_id)
self.assertEqual(activity["type"], "Article")
self.assertEqual(
activity['name'], 'Review of "%s" (3 stars): Review name' \
% self.book.title)
self.assertEqual(activity['content'], 'test content')
self.assertEqual(activity['attachment'][0].type, 'Image')
self.assertEqual(activity['attachment'][0].url, 'https://%s%s' % \
(settings.DOMAIN, self.book.cover.url))
activity["name"], 'Review of "%s" (3 stars): Review name' % self.book.title
)
self.assertEqual(activity["content"], "test content")
self.assertEqual(activity["attachment"][0].type, "Image")
self.assertEqual(
activity['attachment'][0].name, 'Test Edition')
activity["attachment"][0].url,
"https://%s%s" % (settings.DOMAIN, self.book.cover.url),
)
self.assertEqual(activity["attachment"][0].name, "Test Edition")
def test_favorite(self, _):
''' fav a status '''
""" fav a status """
real_broadcast = models.Favorite.broadcast
def fav_broadcast_mock(_, activity, user):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.user.remote_id)
self.assertEqual(activity['type'], 'Like')
self.assertEqual(activity["type"], "Like")
models.Favorite.broadcast = fav_broadcast_mock
status = models.Status.objects.create(
content='test content', user=self.user)
status = models.Status.objects.create(content="test content", user=self.user)
fav = models.Favorite.objects.create(status=status, user=self.user)
# can't fav a status twice
@@ -258,50 +288,47 @@ class Status(TestCase):
models.Favorite.objects.create(status=status, user=self.user)
activity = fav.to_activity()
self.assertEqual(activity['type'], 'Like')
self.assertEqual(activity['actor'], self.user.remote_id)
self.assertEqual(activity['object'], status.remote_id)
self.assertEqual(activity["type"], "Like")
self.assertEqual(activity["actor"], self.user.remote_id)
self.assertEqual(activity["object"], status.remote_id)
models.Favorite.broadcast = real_broadcast
def test_boost(self, _):
''' boosting, this one's a bit fussy '''
status = models.Status.objects.create(
content='test content', user=self.user)
boost = models.Boost.objects.create(
boosted_status=status, user=self.user)
""" boosting, this one's a bit fussy """
status = models.Status.objects.create(content="test content", user=self.user)
boost = models.Boost.objects.create(boosted_status=status, user=self.user)
activity = boost.to_activity()
self.assertEqual(activity['actor'], self.user.remote_id)
self.assertEqual(activity['object'], status.remote_id)
self.assertEqual(activity['type'], 'Announce')
self.assertEqual(activity["actor"], self.user.remote_id)
self.assertEqual(activity["object"], status.remote_id)
self.assertEqual(activity["type"], "Announce")
self.assertEqual(activity, boost.to_activity(pure=True))
def test_notification(self, _):
''' a simple model '''
""" a simple model """
notification = models.Notification.objects.create(
user=self.user, notification_type='FAVORITE')
user=self.user, notification_type="FAVORITE"
)
self.assertFalse(notification.read)
with self.assertRaises(IntegrityError):
models.Notification.objects.create(
user=self.user, notification_type='GLORB')
user=self.user, notification_type="GLORB"
)
def test_create_broadcast(self, broadcast_mock):
''' should send out two verions of a status on create '''
models.Comment.objects.create(
content='hi', user=self.user, book=self.book)
""" should send out two verions of a status on create """
models.Comment.objects.create(content="hi", user=self.user, book=self.book)
self.assertEqual(broadcast_mock.call_count, 2)
pure_call = broadcast_mock.call_args_list[0]
bw_call = broadcast_mock.call_args_list[1]
self.assertEqual(pure_call[1]['software'], 'other')
self.assertEqual(pure_call[1]["software"], "other")
args = pure_call[0][0]
self.assertEqual(args['type'], 'Create')
self.assertEqual(args['object']['type'], 'Note')
self.assertTrue('content' in args['object'])
self.assertEqual(args["type"], "Create")
self.assertEqual(args["object"]["type"], "Note")
self.assertTrue("content" in args["object"])
self.assertEqual(bw_call[1]['software'], 'bookwyrm')
self.assertEqual(bw_call[1]["software"], "bookwyrm")
args = bw_call[0][0]
self.assertEqual(args['type'], 'Create')
self.assertEqual(args['object']['type'], 'Comment')
self.assertEqual(args["type"], "Create")
self.assertEqual(args["object"]["type"], "Comment")

View File

@@ -1,4 +1,4 @@
''' testing models '''
""" testing models """
from unittest.mock import patch
from django.test import TestCase
import responses
@@ -11,75 +11,84 @@ from bookwyrm.settings import DOMAIN
class User(TestCase):
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)
"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
""" username instead of id here """
expected_id = "https://%s/user/mouse" % DOMAIN
self.assertEqual(self.user.remote_id, expected_id)
self.assertEqual(self.user.username, 'mouse@%s' % 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.username, "mouse@%s" % 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.assertIsNotNone(self.user.key_pair.private_key)
self.assertIsNotNone(self.user.key_pair.public_key)
def test_remote_user(self):
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
user = models.User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword', local=False,
remote_id='https://example.com/dfjkg', bookwyrm_user=False)
self.assertEqual(user.username, 'rat@example.com')
"rat",
"rat@rat.rat",
"ratword",
local=False,
remote_id="https://example.com/dfjkg",
bookwyrm_user=False,
)
self.assertEqual(user.username, "rat@example.com")
def test_user_shelves(self):
shelves = models.Shelf.objects.filter(user=self.user).all()
self.assertEqual(len(shelves), 3)
names = [s.name for s in shelves]
self.assertTrue('To Read' in names)
self.assertTrue('Currently Reading' in names)
self.assertTrue('Read' in names)
self.assertTrue("To Read" in names)
self.assertTrue("Currently Reading" in names)
self.assertTrue("Read" in names)
ids = [s.identifier for s in shelves]
self.assertTrue('to-read' in ids)
self.assertTrue('reading' in ids)
self.assertTrue('read' in ids)
self.assertTrue("to-read" in ids)
self.assertTrue("reading" in ids)
self.assertTrue("read" in ids)
def test_activitypub_serialize(self):
activity = self.user.to_activity()
self.assertEqual(activity['id'], self.user.remote_id)
self.assertEqual(activity['@context'], [
'https://www.w3.org/ns/activitystreams',
'https://w3id.org/security/v1',
{
'manuallyApprovesFollowers': 'as:manuallyApprovesFollowers',
'schema': 'http://schema.org#',
'PropertyValue': 'schema:PropertyValue',
'value': 'schema:value',
}
])
self.assertEqual(activity['preferredUsername'], self.user.localname)
self.assertEqual(activity['name'], self.user.name)
self.assertEqual(activity['inbox'], self.user.inbox)
self.assertEqual(activity['outbox'], self.user.outbox)
self.assertEqual(activity['bookwyrmUser'], False)
self.assertEqual(activity['discoverable'], True)
self.assertEqual(activity['type'], 'Person')
self.assertEqual(activity["id"], self.user.remote_id)
self.assertEqual(
activity["@context"],
[
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"schema": "http://schema.org#",
"PropertyValue": "schema:PropertyValue",
"value": "schema:value",
},
],
)
self.assertEqual(activity["preferredUsername"], self.user.localname)
self.assertEqual(activity["name"], self.user.name)
self.assertEqual(activity["inbox"], self.user.inbox)
self.assertEqual(activity["outbox"], self.user.outbox)
self.assertEqual(activity["bookwyrmUser"], False)
self.assertEqual(activity["discoverable"], True)
self.assertEqual(activity["type"], "Person")
def test_activitypub_outbox(self):
activity = self.user.to_outbox()
self.assertEqual(activity['type'], 'OrderedCollection')
self.assertEqual(activity['id'], self.user.outbox)
self.assertEqual(activity['totalItems'], 0)
self.assertEqual(activity["type"], "OrderedCollection")
self.assertEqual(activity["id"], self.user.outbox)
self.assertEqual(activity["totalItems"], 0)
def test_set_remote_server(self):
server = models.FederatedServer.objects.create(
server_name=DOMAIN,
application_type='test type',
application_version=3
server_name=DOMAIN, application_type="test type", application_version=3
)
models.user.set_remote_server(self.user.id)
@@ -91,26 +100,24 @@ class User(TestCase):
def test_get_or_create_remote_server(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
json={'links': [{'href': 'http://www.example.com'}, {}]}
"https://%s/.well-known/nodeinfo" % DOMAIN,
json={"links": [{"href": "http://www.example.com"}, {}]},
)
responses.add(
responses.GET,
'http://www.example.com',
json={'software': {'name': 'hi', 'version': '2'}},
"http://www.example.com",
json={"software": {"name": "hi", "version": "2"}},
)
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)
self.assertEqual(server.application_type, 'hi')
self.assertEqual(server.application_version, '2')
self.assertEqual(server.application_type, "hi")
self.assertEqual(server.application_version, "2")
@responses.activate
def test_get_or_create_remote_server_no_wellknown(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
status=404
responses.GET, "https://%s/.well-known/nodeinfo" % DOMAIN, status=404
)
server = models.user.get_or_create_remote_server(DOMAIN)
@@ -122,14 +129,10 @@ class User(TestCase):
def test_get_or_create_remote_server_no_links(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
json={'links': [{'href': 'http://www.example.com'}, {}]}
)
responses.add(
responses.GET,
'http://www.example.com',
status=404
"https://%s/.well-known/nodeinfo" % DOMAIN,
json={"links": [{"href": "http://www.example.com"}, {}]},
)
responses.add(responses.GET, "http://www.example.com", status=404)
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)
@@ -140,14 +143,10 @@ class User(TestCase):
def test_get_or_create_remote_server_unknown_format(self):
responses.add(
responses.GET,
'https://%s/.well-known/nodeinfo' % DOMAIN,
json={'links': [{'href': 'http://www.example.com'}, {}]}
)
responses.add(
responses.GET,
'http://www.example.com',
json={'fish': 'salmon'}
"https://%s/.well-known/nodeinfo" % DOMAIN,
json={"links": [{"href": "http://www.example.com"}, {}]},
)
responses.add(responses.GET, "http://www.example.com", json={"fish": "salmon"})
server = models.user.get_or_create_remote_server(DOMAIN)
self.assertEqual(server.server_name, DOMAIN)

View File

@@ -1,4 +1,4 @@
''' testing import '''
""" testing import """
from collections import namedtuple
import csv
import pathlib
@@ -12,125 +12,117 @@ from bookwyrm.goodreads_import import GoodreadsImporter
from bookwyrm import importer
from bookwyrm.settings import DOMAIN
class GoodreadsImport(TestCase):
''' importing from goodreads csv '''
""" importing from goodreads csv """
def setUp(self):
self.importer = GoodreadsImporter()
''' use a test csv '''
datafile = pathlib.Path(__file__).parent.joinpath(
'data/goodreads.csv')
self.csv = open(datafile, 'r', encoding=self.importer.encoding)
""" use a test csv """
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)
"mouse", "mouse@mouse.mouse", "password", local=True
)
models.Connector.objects.create(
identifier=DOMAIN,
name='Local',
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,
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')
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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
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')
""" 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)
self.assertEqual(import_job.include_reviews, False)
self.assertEqual(import_job.privacy, 'public')
self.assertEqual(import_job.privacy, "public")
import_items = models.ImportItem.objects.filter(job=import_job).all()
self.assertEqual(len(import_items), 3)
self.assertEqual(import_items[0].index, 0)
self.assertEqual(import_items[0].data['Book Id'], '42036538')
self.assertEqual(import_items[0].data["Book Id"], "42036538")
self.assertEqual(import_items[1].index, 1)
self.assertEqual(import_items[1].data['Book Id'], '52691223')
self.assertEqual(import_items[1].data["Book Id"], "52691223")
self.assertEqual(import_items[2].index, 2)
self.assertEqual(import_items[2].data['Book Id'], '28694510')
self.assertEqual(import_items[2].data["Book Id"], "28694510")
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]
""" 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]
retry = self.importer.create_retry_job(
self.user, import_job, import_items)
retry = self.importer.create_retry_job(self.user, import_job, import_items)
self.assertNotEqual(import_job, retry)
self.assertEqual(retry.user, self.user)
self.assertEqual(retry.include_reviews, False)
self.assertEqual(retry.privacy, 'unlisted')
self.assertEqual(retry.privacy, "unlisted")
retry_items = models.ImportItem.objects.filter(job=retry).all()
self.assertEqual(len(retry_items), 2)
self.assertEqual(retry_items[0].index, 0)
self.assertEqual(retry_items[0].data['Book Id'], '42036538')
self.assertEqual(retry_items[0].data["Book Id"], "42036538")
self.assertEqual(retry_items[1].index, 1)
self.assertEqual(retry_items[1].data['Book Id'], '52691223')
self.assertEqual(retry_items[1].data["Book Id"], "52691223")
def test_start_import(self):
''' begin loading books '''
import_job = self.importer.create_job(
self.user, self.csv, False, 'unlisted')
MockTask = namedtuple('Task', ('id'))
""" begin loading books """
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
MockTask = namedtuple("Task", ("id"))
mock_task = MockTask(7)
with patch('bookwyrm.importer.import_data.delay') as start:
with patch("bookwyrm.importer.import_data.delay") as start:
start.return_value = mock_task
self.importer.start_import(import_job)
import_job.refresh_from_db()
self.assertEqual(import_job.task_id, '7')
self.assertEqual(import_job.task_id, "7")
@responses.activate
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')
""" resolve entry """
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
book = models.Edition.objects.create(title="Test Book")
with patch(
'bookwyrm.models.import_job.ImportItem.get_book_from_isbn'
) as resolve:
"bookwyrm.models.import_job.ImportItem.get_book_from_isbn"
) as resolve:
resolve.return_value = book
with patch('bookwyrm.importer.handle_imported_book'):
with patch("bookwyrm.importer.handle_imported_book"):
importer.import_data(self.importer.service, import_job.id)
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):
''' goodreads import added a book, this adds related connections '''
shelf = self.user.shelf_set.filter(identifier='read').first()
""" 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')
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
csv_file = open(datafile, "r")
for index, entry in enumerate(list(csv.DictReader(csv_file))):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=index, data=entry, book=self.book)
job_id=import_job.id, index=index, data=entry, book=self.book
)
break
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
shelf.refresh_from_db()
self.assertEqual(shelf.books.first(), self.book)
@@ -145,31 +137,30 @@ class GoodreadsImport(TestCase):
self.assertEqual(readthrough.finish_date.month, 10)
self.assertEqual(readthrough.finish_date.day, 25)
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()
models.ShelfBook.objects.create(
shelf=shelf, user=self.user, book=self.book)
""" 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()
models.ShelfBook.objects.create(shelf=shelf, user=self.user, book=self.book)
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath('data/goodreads.csv')
csv_file = open(datafile, 'r')
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
csv_file = open(datafile, "r")
for index, entry in enumerate(list(csv.DictReader(csv_file))):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=index, data=entry, book=self.book)
job_id=import_job.id, index=index, data=entry, book=self.book
)
break
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
shelf.refresh_from_db()
self.assertEqual(shelf.books.first(), self.book)
self.assertIsNone(
self.user.shelf_set.get(identifier='read').books.first())
self.assertIsNone(self.user.shelf_set.get(identifier="read").books.first())
readthrough = models.ReadThrough.objects.get(user=self.user)
self.assertEqual(readthrough.book, self.book)
self.assertEqual(readthrough.start_date.year, 2020)
@@ -179,24 +170,26 @@ class GoodreadsImport(TestCase):
self.assertEqual(readthrough.finish_date.month, 10)
self.assertEqual(readthrough.finish_date.day, 25)
def test_handle_import_twice(self):
''' re-importing books '''
shelf = self.user.shelf_set.filter(identifier='read').first()
""" 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')
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
csv_file = open(datafile, "r")
for index, entry in enumerate(list(csv.DictReader(csv_file))):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=index, data=entry, book=self.book)
job_id=import_job.id, index=index, data=entry, book=self.book
)
break
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
shelf.refresh_from_db()
self.assertEqual(shelf.books.first(), self.book)
@@ -211,42 +204,44 @@ class GoodreadsImport(TestCase):
self.assertEqual(readthrough.finish_date.month, 10)
self.assertEqual(readthrough.finish_date.day, 25)
def test_handle_imported_book_review(self):
''' goodreads review import '''
""" 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')
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
csv_file = open(datafile, "r")
entry = list(csv.DictReader(csv_file))[2]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=0, data=entry, book=self.book)
job_id=import_job.id, index=0, data=entry, book=self.book
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, True, 'unlisted')
self.importer.service, self.user, import_item, True, "unlisted"
)
review = models.Review.objects.get(book=self.book, user=self.user)
self.assertEqual(review.content, 'mixed feelings')
self.assertEqual(review.content, "mixed feelings")
self.assertEqual(review.rating, 2)
self.assertEqual(review.published_date.year, 2019)
self.assertEqual(review.published_date.month, 7)
self.assertEqual(review.published_date.day, 8)
self.assertEqual(review.privacy, 'unlisted')
self.assertEqual(review.privacy, "unlisted")
def test_handle_imported_book_reviews_disabled(self):
''' goodreads review import '''
""" 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')
datafile = pathlib.Path(__file__).parent.joinpath("data/goodreads.csv")
csv_file = open(datafile, "r")
entry = list(csv.DictReader(csv_file))[2]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=0, data=entry, book=self.book)
job_id=import_job.id, index=0, data=entry, book=self.book
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'unlisted')
self.assertFalse(models.Review.objects.filter(
book=self.book, user=self.user
).exists())
self.importer.service, self.user, import_item, False, "unlisted"
)
self.assertFalse(
models.Review.objects.filter(book=self.book, user=self.user).exists()
)

View File

@@ -1,4 +1,4 @@
''' testing import '''
""" testing import """
from collections import namedtuple
import csv
import pathlib
@@ -11,114 +11,110 @@ from bookwyrm import models, importer
from bookwyrm.librarything_import import LibrarythingImporter
from bookwyrm.settings import DOMAIN
class LibrarythingImport(TestCase):
''' importing from librarything tsv '''
""" importing from librarything tsv """
def setUp(self):
self.importer = LibrarythingImporter()
''' use a test tsv '''
datafile = pathlib.Path(__file__).parent.joinpath(
'data/librarything.tsv')
""" use a test tsv """
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
# Librarything generates latin encoded exports...
self.csv = open(datafile, 'r', encoding=self.importer.encoding)
self.csv = open(datafile, "r", encoding=self.importer.encoding)
self.user = models.User.objects.create_user(
'mmai', 'mmai@mmai.mmai', 'password', local=True)
"mmai", "mmai@mmai.mmai", "password", local=True
)
models.Connector.objects.create(
identifier=DOMAIN,
name='Local',
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,
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')
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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
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')
""" 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)
self.assertEqual(import_job.include_reviews, False)
self.assertEqual(import_job.privacy, 'public')
self.assertEqual(import_job.privacy, "public")
import_items = models.ImportItem.objects.filter(job=import_job).all()
self.assertEqual(len(import_items), 3)
self.assertEqual(import_items[0].index, 0)
self.assertEqual(import_items[0].data['Book Id'], '5498194')
self.assertEqual(import_items[0].data["Book Id"], "5498194")
self.assertEqual(import_items[1].index, 1)
self.assertEqual(import_items[1].data['Book Id'], '5015319')
self.assertEqual(import_items[1].data["Book Id"], "5015319")
self.assertEqual(import_items[2].index, 2)
self.assertEqual(import_items[2].data['Book Id'], '5015399')
self.assertEqual(import_items[2].data["Book Id"], "5015399")
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]
""" 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]
retry = self.importer.create_retry_job(
self.user, import_job, import_items)
retry = self.importer.create_retry_job(self.user, import_job, import_items)
self.assertNotEqual(import_job, retry)
self.assertEqual(retry.user, self.user)
self.assertEqual(retry.include_reviews, False)
self.assertEqual(retry.privacy, 'unlisted')
self.assertEqual(retry.privacy, "unlisted")
retry_items = models.ImportItem.objects.filter(job=retry).all()
self.assertEqual(len(retry_items), 2)
self.assertEqual(retry_items[0].index, 0)
self.assertEqual(import_items[0].data['Book Id'], '5498194')
self.assertEqual(import_items[0].data["Book Id"], "5498194")
self.assertEqual(retry_items[1].index, 1)
self.assertEqual(retry_items[1].data['Book Id'], '5015319')
self.assertEqual(retry_items[1].data["Book Id"], "5015319")
@responses.activate
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')
""" resolve entry """
import_job = self.importer.create_job(self.user, self.csv, False, "unlisted")
book = models.Edition.objects.create(title="Test Book")
with patch(
'bookwyrm.models.import_job.ImportItem.get_book_from_isbn'
) as resolve:
"bookwyrm.models.import_job.ImportItem.get_book_from_isbn"
) as resolve:
resolve.return_value = book
with patch('bookwyrm.importer.handle_imported_book'):
with patch("bookwyrm.importer.handle_imported_book"):
importer.import_data(self.importer.service, import_job.id)
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):
''' librarything import added a book, this adds related connections '''
shelf = self.user.shelf_set.filter(identifier='read').first()
""" librarything 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/librarything.tsv')
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
for index, entry in enumerate(list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))):
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
csv_file = open(datafile, "r", encoding=self.importer.encoding)
for index, entry in enumerate(
list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))
):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=index, data=entry, book=self.book)
job_id=import_job.id, index=index, data=entry, book=self.book
)
break
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
shelf.refresh_from_db()
self.assertEqual(shelf.books.first(), self.book)
@@ -133,31 +129,32 @@ class LibrarythingImport(TestCase):
self.assertEqual(readthrough.finish_date.month, 5)
self.assertEqual(readthrough.finish_date.day, 8)
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()
models.ShelfBook.objects.create(
shelf=shelf, user=self.user, book=self.book)
""" 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()
models.ShelfBook.objects.create(shelf=shelf, user=self.user, book=self.book)
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
for index, entry in enumerate(list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))):
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
csv_file = open(datafile, "r", encoding=self.importer.encoding)
for index, entry in enumerate(
list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))
):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=index, data=entry, book=self.book)
job_id=import_job.id, index=index, data=entry, book=self.book
)
break
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
shelf.refresh_from_db()
self.assertEqual(shelf.books.first(), self.book)
self.assertIsNone(
self.user.shelf_set.get(identifier='read').books.first())
self.assertIsNone(self.user.shelf_set.get(identifier="read").books.first())
readthrough = models.ReadThrough.objects.get(user=self.user)
self.assertEqual(readthrough.book, self.book)
self.assertEqual(readthrough.start_date.year, 2007)
@@ -167,24 +164,28 @@ class LibrarythingImport(TestCase):
self.assertEqual(readthrough.finish_date.month, 5)
self.assertEqual(readthrough.finish_date.day, 8)
def test_handle_import_twice(self):
''' re-importing books '''
shelf = self.user.shelf_set.filter(identifier='read').first()
""" 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/librarything.tsv')
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
for index, entry in enumerate(list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))):
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
csv_file = open(datafile, "r", encoding=self.importer.encoding)
for index, entry in enumerate(
list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))
):
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=index, data=entry, book=self.book)
job_id=import_job.id, index=index, data=entry, book=self.book
)
break
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'public')
self.importer.service, self.user, import_item, False, "public"
)
shelf.refresh_from_db()
self.assertEqual(shelf.books.first(), self.book)
@@ -199,42 +200,44 @@ class LibrarythingImport(TestCase):
self.assertEqual(readthrough.finish_date.month, 5)
self.assertEqual(readthrough.finish_date.day, 8)
def test_handle_imported_book_review(self):
''' librarything review import '''
""" librarything review import """
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
csv_file = open(datafile, "r", encoding=self.importer.encoding)
entry = list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))[0]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=0, data=entry, book=self.book)
job_id=import_job.id, index=0, data=entry, book=self.book
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, True, 'unlisted')
self.importer.service, self.user, import_item, True, "unlisted"
)
review = models.Review.objects.get(book=self.book, user=self.user)
self.assertEqual(review.content, 'chef d\'oeuvre')
self.assertEqual(review.content, "chef d'oeuvre")
self.assertEqual(review.rating, 5)
self.assertEqual(review.published_date.year, 2007)
self.assertEqual(review.published_date.month, 5)
self.assertEqual(review.published_date.day, 8)
self.assertEqual(review.privacy, 'unlisted')
self.assertEqual(review.privacy, "unlisted")
def test_handle_imported_book_reviews_disabled(self):
''' librarything review import '''
""" librarything review import """
import_job = models.ImportJob.objects.create(user=self.user)
datafile = pathlib.Path(__file__).parent.joinpath('data/librarything.tsv')
csv_file = open(datafile, 'r', encoding=self.importer.encoding)
datafile = pathlib.Path(__file__).parent.joinpath("data/librarything.tsv")
csv_file = open(datafile, "r", encoding=self.importer.encoding)
entry = list(csv.DictReader(csv_file, delimiter=self.importer.delimiter))[2]
entry = self.importer.parse_fields(entry)
import_item = models.ImportItem.objects.create(
job_id=import_job.id, index=0, data=entry, book=self.book)
job_id=import_job.id, index=0, data=entry, book=self.book
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
importer.handle_imported_book(
self.importer.service, self.user, import_item, False, 'unlisted')
self.assertFalse(models.Review.objects.filter(
book=self.book, user=self.user
).exists())
self.importer.service, self.user, import_item, False, "unlisted"
)
self.assertFalse(
models.Review.objects.filter(book=self.book, user=self.user).exists()
)

View File

@@ -1,28 +1,30 @@
''' make sure only valid html gets to the app '''
""" make sure only valid html gets to the app """
from django.test import TestCase
from bookwyrm.sanitize_html import InputHtmlParser
class Sanitizer(TestCase):
''' sanitizer tests '''
""" sanitizer tests """
def test_no_html(self):
''' just text '''
input_text = 'no html '
""" just text """
input_text = "no html "
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual(input_text, output)
def test_valid_html(self):
''' leave the html untouched '''
input_text = '<b>yes </b> <i>html</i>'
""" leave the html untouched """
input_text = "<b>yes </b> <i>html</i>"
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual(input_text, output)
def test_valid_html_attrs(self):
''' and don't remove attributes '''
""" and don't remove attributes """
input_text = '<a href="fish.com">yes </a> <i>html</i>'
parser = InputHtmlParser()
parser.feed(input_text)
@@ -30,23 +32,23 @@ class Sanitizer(TestCase):
self.assertEqual(input_text, output)
def test_invalid_html(self):
''' remove all html when the html is malformed '''
input_text = '<b>yes <i>html</i>'
""" remove all html when the html is malformed """
input_text = "<b>yes <i>html</i>"
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual('yes html', output)
self.assertEqual("yes html", output)
input_text = 'yes <i></b>html </i>'
input_text = "yes <i></b>html </i>"
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual('yes html ', output)
self.assertEqual("yes html ", output)
def test_disallowed_html(self):
''' remove disallowed html but keep allowed html '''
input_text = '<div> yes <i>html</i></div>'
""" remove disallowed html but keep allowed html """
input_text = "<div> yes <i>html</i></div>"
parser = InputHtmlParser()
parser.feed(input_text)
output = parser.get_output()
self.assertEqual(' yes <i>html</i>', output)
self.assertEqual(" yes <i>html</i>", output)

View File

@@ -1,4 +1,4 @@
''' getting and verifying signatures '''
""" getting and verifying signatures """
import time
from collections import namedtuple
from urllib.parse import urlsplit
@@ -18,141 +18,125 @@ from bookwyrm.activitypub import Follow
from bookwyrm.settings import DOMAIN
from bookwyrm.signatures import create_key_pair, make_signature, make_digest
def get_follow_activity(follower, followee):
''' generates a test activity '''
""" generates a test activity """
return Follow(
id='https://test.com/user/follow/id',
id="https://test.com/user/follow/id",
actor=follower.remote_id,
object=followee.remote_id,
).serialize()
KeyPair = namedtuple('KeyPair', ('private_key', 'public_key'))
Sender = namedtuple('Sender', ('remote_id', 'key_pair'))
KeyPair = namedtuple("KeyPair", ("private_key", "public_key"))
Sender = namedtuple("Sender", ("remote_id", "key_pair"))
class Signature(TestCase):
''' signature test '''
""" signature test """
def setUp(self):
''' create users and test data '''
""" create users and test data """
self.mouse = models.User.objects.create_user(
'mouse@%s' % DOMAIN, 'mouse@example.com', '',
local=True, localname='mouse')
"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')
"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')
"cat@%s" % DOMAIN, "cat@example.com", "", local=True, localname="cat"
)
private_key, public_key = create_key_pair()
self.fake_remote = Sender(
'http://localhost/user/remote',
KeyPair(private_key, public_key)
"http://localhost/user/remote", KeyPair(private_key, public_key)
)
models.SiteSettings.objects.create()
def send(self, signature, now, data, digest):
''' test request '''
""" test request """
c = Client()
return c.post(
urlsplit(self.rat.inbox).path,
data=data,
content_type='application/json',
content_type="application/json",
**{
'HTTP_DATE': now,
'HTTP_SIGNATURE': signature,
'HTTP_DIGEST': digest,
'HTTP_CONTENT_TYPE': 'application/activity+json; charset=utf-8',
'HTTP_HOST': DOMAIN,
"HTTP_DATE": now,
"HTTP_SIGNATURE": signature,
"HTTP_DIGEST": digest,
"HTTP_CONTENT_TYPE": "application/activity+json; charset=utf-8",
"HTTP_HOST": DOMAIN,
}
)
def send_test_request(#pylint: disable=too-many-arguments
self,
sender,
signer=None,
send_data=None,
digest=None,
date=None):
''' sends a follow request to the "rat" user '''
def send_test_request( # pylint: disable=too-many-arguments
self, sender, signer=None, send_data=None, digest=None, date=None
):
""" sends a follow request to the "rat" user """
now = date or http_date()
data = json.dumps(get_follow_activity(sender, self.rat))
digest = digest or make_digest(data)
signature = make_signature(
signer or sender, self.rat.inbox, now, digest)
with patch('bookwyrm.views.inbox.activity_task.delay'):
with patch('bookwyrm.models.user.set_remote_server.delay'):
signature = make_signature(signer or sender, self.rat.inbox, now, digest)
with patch("bookwyrm.views.inbox.activity_task.delay"):
with patch("bookwyrm.models.user.set_remote_server.delay"):
return self.send(signature, now, send_data or data, digest)
def test_correct_signature(self):
''' this one should just work '''
""" this one should just work """
response = self.send_test_request(sender=self.mouse)
self.assertEqual(response.status_code, 200)
def test_wrong_signature(self):
''' Messages must be signed by the right actor.
(cat cannot sign messages on behalf of mouse) '''
"""Messages must be signed by the right actor.
(cat cannot sign messages on behalf of mouse)"""
response = self.send_test_request(sender=self.mouse, signer=self.cat)
self.assertEqual(response.status_code, 401)
@responses.activate
def test_remote_signer(self):
''' signtures for remote users '''
datafile = pathlib.Path(__file__).parent.joinpath('data/ap_user.json')
""" signtures for remote users """
datafile = pathlib.Path(__file__).parent.joinpath("data/ap_user.json")
data = json.loads(datafile.read_bytes())
data['id'] = self.fake_remote.remote_id
data['publicKey']['publicKeyPem'] = self.fake_remote.key_pair.public_key
del data['icon'] # Avoid having to return an avatar.
data["id"] = self.fake_remote.remote_id
data["publicKey"]["publicKeyPem"] = self.fake_remote.key_pair.public_key
del data["icon"] # Avoid having to return an avatar.
responses.add(responses.GET, self.fake_remote.remote_id, json=data, status=200)
responses.add(
responses.GET, "https://localhost/.well-known/nodeinfo", status=404
)
responses.add(
responses.GET,
self.fake_remote.remote_id,
json=data,
status=200)
responses.add(
responses.GET,
'https://localhost/.well-known/nodeinfo',
status=404)
responses.add(
responses.GET,
'https://example.com/user/mouse/outbox?page=true',
json={'orderedItems': []},
status=200
"https://example.com/user/mouse/outbox?page=true",
json={"orderedItems": []},
status=200,
)
with patch('bookwyrm.models.user.get_remote_reviews.delay'):
with patch("bookwyrm.models.user.get_remote_reviews.delay"):
response = self.send_test_request(sender=self.fake_remote)
self.assertEqual(response.status_code, 200)
@responses.activate
def test_key_needs_refresh(self):
''' an out of date key should be updated and the new key work '''
datafile = pathlib.Path(__file__).parent.joinpath('data/ap_user.json')
""" an out of date key should be updated and the new key work """
datafile = pathlib.Path(__file__).parent.joinpath("data/ap_user.json")
data = json.loads(datafile.read_bytes())
data['id'] = self.fake_remote.remote_id
data['publicKey']['publicKeyPem'] = self.fake_remote.key_pair.public_key
del data['icon'] # Avoid having to return an avatar.
data["id"] = self.fake_remote.remote_id
data["publicKey"]["publicKeyPem"] = self.fake_remote.key_pair.public_key
del data["icon"] # Avoid having to return an avatar.
responses.add(responses.GET, self.fake_remote.remote_id, json=data, status=200)
responses.add(
responses.GET,
self.fake_remote.remote_id,
json=data,
status=200)
responses.add(
responses.GET,
'https://localhost/.well-known/nodeinfo',
status=404)
responses.GET, "https://localhost/.well-known/nodeinfo", status=404
)
# Second and subsequent fetches get a different key:
key_pair = KeyPair(*create_key_pair())
new_sender = Sender(self.fake_remote.remote_id, key_pair)
data['publicKey']['publicKeyPem'] = key_pair.public_key
responses.add(
responses.GET,
self.fake_remote.remote_id,
json=data,
status=200)
data["publicKey"]["publicKeyPem"] = key_pair.public_key
responses.add(responses.GET, self.fake_remote.remote_id, json=data, status=200)
with patch('bookwyrm.models.user.get_remote_reviews.delay'):
with patch("bookwyrm.models.user.get_remote_reviews.delay"):
# Key correct:
response = self.send_test_request(sender=self.fake_remote)
self.assertEqual(response.status_code, 200)
@@ -169,43 +153,42 @@ class Signature(TestCase):
response = self.send_test_request(sender=self.fake_remote)
self.assertEqual(response.status_code, 401)
@responses.activate
def test_nonexistent_signer(self):
''' fail when unable to look up signer '''
""" fail when unable to look up signer """
responses.add(
responses.GET,
self.fake_remote.remote_id,
json={'error': 'not found'},
status=404)
json={"error": "not found"},
status=404,
)
response = self.send_test_request(sender=self.fake_remote)
self.assertEqual(response.status_code, 401)
@pytest.mark.integration
def test_changed_data(self):
'''Message data must match the digest header.'''
with patch('bookwyrm.activitypub.resolve_remote_id'):
"""Message data must match the digest header."""
with patch("bookwyrm.activitypub.resolve_remote_id"):
response = self.send_test_request(
self.mouse,
send_data=get_follow_activity(self.mouse, self.cat))
self.mouse, send_data=get_follow_activity(self.mouse, self.cat)
)
self.assertEqual(response.status_code, 401)
@pytest.mark.integration
def test_invalid_digest(self):
''' signature digest must be valid '''
with patch('bookwyrm.activitypub.resolve_remote_id'):
""" signature digest must be valid """
with patch("bookwyrm.activitypub.resolve_remote_id"):
response = self.send_test_request(
self.mouse,
digest='SHA-256=AAAAAAAAAAAAAAAAAA')
self.mouse, digest="SHA-256=AAAAAAAAAAAAAAAAAA"
)
self.assertEqual(response.status_code, 401)
@pytest.mark.integration
def test_old_message(self):
'''Old messages should be rejected to prevent replay attacks.'''
with patch('bookwyrm.activitypub.resolve_remote_id'):
"""Old messages should be rejected to prevent replay attacks."""
with patch("bookwyrm.activitypub.resolve_remote_id"):
response = self.send_test_request(
self.mouse,
date=http_date(time.time() - 301)
self.mouse, date=http_date(time.time() - 301)
)
self.assertEqual(response.status_code, 401)

View File

@@ -1,4 +1,4 @@
''' style fixes and lookups for templates '''
""" style fixes and lookups for templates """
import re
from unittest.mock import patch
@@ -11,82 +11,85 @@ from bookwyrm.templatetags import bookwyrm_tags
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.models.user.set_remote_server.delay'):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@rat.rat', 'ratword',
remote_id='http://example.com/rat', local=False)
self.book = models.Edition.objects.create(title='Test Book')
""" 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.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
"rat",
"rat@rat.rat",
"ratword",
remote_id="http://example.com/rat",
local=False,
)
self.book = models.Edition.objects.create(title="Test Book")
def test_dict_key(self):
''' just getting a value out of a dict '''
test_dict = {'a': 1, 'b': 3}
self.assertEqual(
bookwyrm_tags.dict_key(test_dict, 'a'), 1)
self.assertEqual(
bookwyrm_tags.dict_key(test_dict, 'c'), 0)
""" just getting a value out of a dict """
test_dict = {"a": 1, "b": 3}
self.assertEqual(bookwyrm_tags.dict_key(test_dict, "a"), 1)
self.assertEqual(bookwyrm_tags.dict_key(test_dict, "c"), 0)
def test_get_user_rating(self):
''' get a user's most recent rating of a book '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.Review.objects.create(
user=self.user, book=self.book, rating=3)
self.assertEqual(
bookwyrm_tags.get_user_rating(self.book, self.user), 3)
""" get a user's most recent rating of a book """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Review.objects.create(user=self.user, book=self.book, rating=3)
self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 3)
def test_get_user_rating_doesnt_exist(self):
''' there is no rating available '''
self.assertEqual(
bookwyrm_tags.get_user_rating(self.book, self.user), 0)
""" there is no rating available """
self.assertEqual(bookwyrm_tags.get_user_rating(self.book, self.user), 0)
def test_get_user_identifer_local(self):
''' fall back to the simplest uid available '''
""" fall back to the simplest uid available """
self.assertNotEqual(self.user.username, self.user.localname)
self.assertEqual(
bookwyrm_tags.get_user_identifier(self.user), 'mouse')
self.assertEqual(bookwyrm_tags.get_user_identifier(self.user), "mouse")
def test_get_user_identifer_remote(self):
''' for a remote user, should be their full username '''
""" for a remote user, should be their full username """
self.assertEqual(
bookwyrm_tags.get_user_identifier(self.remote_user),
'rat@example.com')
bookwyrm_tags.get_user_identifier(self.remote_user), "rat@example.com"
)
def test_get_notification_count(self):
''' just countin' '''
""" just countin' """
self.assertEqual(bookwyrm_tags.get_notification_count(self.user), 0)
models.Notification.objects.create(
user=self.user, notification_type='FAVORITE')
models.Notification.objects.create(
user=self.user, notification_type='MENTION')
models.Notification.objects.create(user=self.user, notification_type="FAVORITE")
models.Notification.objects.create(user=self.user, notification_type="MENTION")
models.Notification.objects.create(
user=self.remote_user, notification_type='FOLLOW')
user=self.remote_user, notification_type="FOLLOW"
)
self.assertEqual(bookwyrm_tags.get_notification_count(self.user), 2)
def test_get_replies(self):
''' direct replies to a status '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" direct replies to a status """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
parent = models.Review.objects.create(
user=self.user, book=self.book, content='hi')
user=self.user, book=self.book, content="hi"
)
first_child = models.Status.objects.create(
reply_parent=parent, user=self.user, content='hi')
reply_parent=parent, user=self.user, content="hi"
)
second_child = models.Status.objects.create(
reply_parent=parent, user=self.user, content='hi')
reply_parent=parent, user=self.user, content="hi"
)
third_child = models.Status.objects.create(
reply_parent=parent, user=self.user,
deleted=True, deleted_date=timezone.now())
reply_parent=parent,
user=self.user,
deleted=True,
deleted_date=timezone.now(),
)
replies = bookwyrm_tags.get_replies(parent)
self.assertEqual(len(replies), 2)
@@ -94,181 +97,162 @@ class TemplateTags(TestCase):
self.assertTrue(second_child in replies)
self.assertFalse(third_child in replies)
def test_get_parent(self):
''' get the reply parent of a status '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" get the reply parent of a status """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
parent = models.Review.objects.create(
user=self.user, book=self.book, content='hi')
user=self.user, book=self.book, content="hi"
)
child = models.Status.objects.create(
reply_parent=parent, user=self.user, content='hi')
reply_parent=parent, user=self.user, content="hi"
)
result = bookwyrm_tags.get_parent(child)
self.assertEqual(result, parent)
self.assertIsInstance(result, models.Review)
def test_get_user_liked(self):
''' did a user like a status '''
status = models.Review.objects.create(
user=self.remote_user, book=self.book)
""" did a user like a status """
status = models.Review.objects.create(user=self.remote_user, book=self.book)
self.assertFalse(bookwyrm_tags.get_user_liked(self.user, status))
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.Favorite.objects.create(
user=self.user,
status=status
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Favorite.objects.create(user=self.user, status=status)
self.assertTrue(bookwyrm_tags.get_user_liked(self.user, status))
def test_get_user_boosted(self):
''' did a user boost a status '''
status = models.Review.objects.create(
user=self.remote_user, book=self.book)
""" did a user boost a status """
status = models.Review.objects.create(user=self.remote_user, book=self.book)
self.assertFalse(bookwyrm_tags.get_user_boosted(self.user, status))
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.Boost.objects.create(
user=self.user,
boosted_status=status
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Boost.objects.create(user=self.user, boosted_status=status)
self.assertTrue(bookwyrm_tags.get_user_boosted(self.user, status))
def test_follow_request_exists(self):
''' does a user want to follow '''
""" does a user want to follow """
self.assertFalse(
bookwyrm_tags.follow_request_exists(self.user, self.remote_user))
bookwyrm_tags.follow_request_exists(self.user, self.remote_user)
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.UserFollowRequest.objects.create(
user_subject=self.user,
user_object=self.remote_user)
user_subject=self.user, user_object=self.remote_user
)
self.assertFalse(
bookwyrm_tags.follow_request_exists(self.user, self.remote_user))
bookwyrm_tags.follow_request_exists(self.user, self.remote_user)
)
self.assertTrue(
bookwyrm_tags.follow_request_exists(self.remote_user, self.user))
bookwyrm_tags.follow_request_exists(self.remote_user, self.user)
)
def test_get_boosted(self):
''' load a boosted status '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Review.objects.create(
user=self.remote_user, book=self.book)
boost = models.Boost.objects.create(
user=self.user,
boosted_status=status
)
""" load a boosted status """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Review.objects.create(user=self.remote_user, book=self.book)
boost = models.Boost.objects.create(user=self.user, boosted_status=status)
boosted = bookwyrm_tags.get_boosted(boost)
self.assertIsInstance(boosted, models.Review)
self.assertEqual(boosted, status)
def test_get_book_description(self):
''' grab it from the edition or the parent '''
work = models.Work.objects.create(title='Test Work')
""" grab it from the edition or the parent """
work = models.Work.objects.create(title="Test Work")
self.book.parent_work = work
self.book.save()
self.assertIsNone(bookwyrm_tags.get_book_description(self.book))
work.description = 'hi'
work.description = "hi"
work.save()
self.assertEqual(bookwyrm_tags.get_book_description(self.book), 'hi')
self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hi")
self.book.description = 'hello'
self.book.description = "hello"
self.book.save()
self.assertEqual(bookwyrm_tags.get_book_description(self.book), 'hello')
self.assertEqual(bookwyrm_tags.get_book_description(self.book), "hello")
def test_get_uuid(self):
''' uuid functionality '''
uuid = bookwyrm_tags.get_uuid('hi')
self.assertTrue(re.match(r'hi[A-Za-z0-9\-]', uuid))
""" uuid functionality """
uuid = bookwyrm_tags.get_uuid("hi")
self.assertTrue(re.match(r"hi[A-Za-z0-9\-]", uuid))
def test_time_since(self):
''' ultraconcise timestamps '''
self.assertEqual(bookwyrm_tags.time_since('bleh'), '')
""" ultraconcise timestamps """
self.assertEqual(bookwyrm_tags.time_since("bleh"), "")
now = timezone.now()
self.assertEqual(bookwyrm_tags.time_since(now), '0s')
self.assertEqual(bookwyrm_tags.time_since(now), "0s")
seconds_ago = now - relativedelta(seconds=4)
self.assertEqual(bookwyrm_tags.time_since(seconds_ago), '4s')
self.assertEqual(bookwyrm_tags.time_since(seconds_ago), "4s")
minutes_ago = now - relativedelta(minutes=8)
self.assertEqual(bookwyrm_tags.time_since(minutes_ago), '8m')
self.assertEqual(bookwyrm_tags.time_since(minutes_ago), "8m")
hours_ago = now - relativedelta(hours=9)
self.assertEqual(bookwyrm_tags.time_since(hours_ago), '9h')
self.assertEqual(bookwyrm_tags.time_since(hours_ago), "9h")
days_ago = now - relativedelta(days=3)
self.assertEqual(bookwyrm_tags.time_since(days_ago), '3d')
self.assertEqual(bookwyrm_tags.time_since(days_ago), "3d")
# I am not going to figure out how to mock dates tonight.
months_ago = now - relativedelta(months=5)
self.assertTrue(re.match(
r'[A-Z][a-z]{2} \d?\d',
bookwyrm_tags.time_since(months_ago)
))
self.assertTrue(
re.match(r"[A-Z][a-z]{2} \d?\d", bookwyrm_tags.time_since(months_ago))
)
years_ago = now - relativedelta(years=10)
self.assertTrue(re.match(
r'[A-Z][a-z]{2} \d?\d \d{4}',
bookwyrm_tags.time_since(years_ago)
))
self.assertTrue(
re.match(r"[A-Z][a-z]{2} \d?\d \d{4}", bookwyrm_tags.time_since(years_ago))
)
def test_get_markdown(self):
''' mardown format data '''
result = bookwyrm_tags.get_markdown('_hi_')
self.assertEqual(result, '<p><em>hi</em></p>')
result = bookwyrm_tags.get_markdown('<marquee>_hi_</marquee>')
self.assertEqual(result, '<p><em>hi</em></p>')
""" mardown format data """
result = bookwyrm_tags.get_markdown("_hi_")
self.assertEqual(result, "<p><em>hi</em></p>")
result = bookwyrm_tags.get_markdown("<marquee>_hi_</marquee>")
self.assertEqual(result, "<p><em>hi</em></p>")
def test_get_mentions(self):
''' list of people mentioned '''
status = models.Status.objects.create(
content='hi', user=self.remote_user)
""" list of people mentioned """
status = models.Status.objects.create(content="hi", user=self.remote_user)
result = bookwyrm_tags.get_mentions(status, self.user)
self.assertEqual(result, '@rat@example.com ')
self.assertEqual(result, "@rat@example.com ")
def test_get_status_preview_name(self):
''' status context string '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(content='hi', user=self.user)
""" status context string """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(content="hi", user=self.user)
result = bookwyrm_tags.get_status_preview_name(status)
self.assertEqual(result, 'status')
self.assertEqual(result, "status")
status = models.Review.objects.create(
content='hi', user=self.user, book=self.book)
content="hi", user=self.user, book=self.book
)
result = bookwyrm_tags.get_status_preview_name(status)
self.assertEqual(result, 'review of <em>Test Book</em>')
self.assertEqual(result, "review of <em>Test Book</em>")
status = models.Comment.objects.create(
content='hi', user=self.user, book=self.book)
content="hi", user=self.user, book=self.book
)
result = bookwyrm_tags.get_status_preview_name(status)
self.assertEqual(result, 'comment on <em>Test Book</em>')
self.assertEqual(result, "comment on <em>Test Book</em>")
status = models.Quotation.objects.create(
content='hi', user=self.user, book=self.book)
content="hi", user=self.user, book=self.book
)
result = bookwyrm_tags.get_status_preview_name(status)
self.assertEqual(result, 'quotation from <em>Test Book</em>')
self.assertEqual(result, "quotation from <em>Test Book</em>")
def test_related_status(self):
''' gets the subclass model for a notification status '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(content='hi', user=self.user)
""" gets the subclass model for a notification status """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(content="hi", user=self.user)
notification = models.Notification.objects.create(
user=self.user, notification_type='MENTION',
related_status=status)
user=self.user, notification_type="MENTION", related_status=status
)
result = bookwyrm_tags.related_status(notification)
self.assertIsInstance(result, models.Status)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
@@ -14,21 +14,26 @@ from bookwyrm.settings import DOMAIN
# pylint: disable=too-many-public-methods
class AuthenticationViews(TestCase):
''' login and password management '''
""" login and password management """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"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 '''
""" there are so many views, this just makes sure it LOADS """
login = views.Login.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.anonymous_user
result = login(request)
@@ -38,135 +43,117 @@ class AuthenticationViews(TestCase):
request.user = self.local_user
result = login(request)
self.assertEqual(result.url, '/')
self.assertEqual(result.url, "/")
self.assertEqual(result.status_code, 302)
def test_register(self):
''' create a user '''
""" create a user """
view = views.Register.as_view()
self.assertEqual(models.User.objects.count(), 1)
request = self.factory.post(
'register/',
"register/",
{
'localname': 'nutria-user.user_nutria',
'password': 'mouseword',
'email': 'aa@bb.cccc'
})
with patch('bookwyrm.views.authentication.login'):
"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.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 '''
""" 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'):
"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.username, "nutria@%s" % DOMAIN)
self.assertEqual(nutria.localname, "nutria")
self.assertEqual(nutria.local, True)
def test_register_invalid_email(self):
''' gotta have an email '''
""" 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'
})
"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 '''
""" 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'
})
"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'
})
"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'
})
"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 '''
""" 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'
})
"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 '''
""" 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)
code="testcode", user=self.local_user, use_limit=1
)
self.assertEqual(models.SiteInvite.objects.get().times_used, 0)
request = self.factory.post(
'register/',
"register/",
{
'localname': 'nutria',
'password': 'mouseword',
'email': 'aa@bb.ccc',
'invite_code': 'testcode'
})
with patch('bookwyrm.views.authentication.login'):
"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)
@@ -174,26 +161,28 @@ class AuthenticationViews(TestCase):
# invite already used to max capacity
request = self.factory.post(
'register/',
"register/",
{
'localname': 'nutria2',
'password': 'mouseword',
'email': 'aa@bb.ccc',
'invite_code': 'testcode'
})
"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/',
"register/",
{
'localname': 'nutria3',
'password': 'mouseword',
'email': 'aa@bb.ccc',
'invite_code': 'dkfkdjgdfkjgkdfj'
})
"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

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
@@ -12,37 +12,41 @@ from bookwyrm.activitypub import ActivitypubResponse
class AuthorViews(TestCase):
''' author views'''
""" author views"""
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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 = 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
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.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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
models.SiteSettings.objects.create()
def test_author_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Author.as_view()
author = models.Author.objects.create(name='Jessica')
request = self.factory.get('')
with patch('bookwyrm.views.author.is_api_request') as is_api:
author = models.Author.objects.create(name="Jessica")
request = self.factory.get("")
with patch("bookwyrm.views.author.is_api_request") as is_api:
is_api.return_value = False
result = view(request, author.id)
self.assertIsInstance(result, TemplateResponse)
@@ -50,19 +54,18 @@ class AuthorViews(TestCase):
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 200)
request = self.factory.get('')
with patch('bookwyrm.views.author.is_api_request') as is_api:
request = self.factory.get("")
with patch("bookwyrm.views.author.is_api_request") as is_api:
is_api.return_value = True
result = view(request, author.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_edit_author_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.EditAuthor.as_view()
author = models.Author.objects.create(name='Test Author')
request = self.factory.get('')
author = models.Author.objects.create(name="Test Author")
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
@@ -72,52 +75,51 @@ class AuthorViews(TestCase):
self.assertEqual(result.status_code, 200)
self.assertEqual(result.status_code, 200)
def test_edit_author(self):
''' edit an author '''
""" edit an author """
view = views.EditAuthor.as_view()
author = models.Author.objects.create(name='Test Author')
author = models.Author.objects.create(name="Test Author")
self.local_user.groups.add(self.group)
form = forms.AuthorForm(instance=author)
form.data['name'] = 'New Name'
form.data['last_edited_by'] = self.local_user.id
request = self.factory.post('', form.data)
form.data["name"] = "New Name"
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, author.id)
author.refresh_from_db()
self.assertEqual(author.name, 'New Name')
self.assertEqual(author.name, "New Name")
self.assertEqual(author.last_edited_by, self.local_user)
def test_edit_author_non_editor(self):
''' edit an author with invalid post data'''
""" edit an author with invalid post data"""
view = views.EditAuthor.as_view()
author = models.Author.objects.create(name='Test Author')
author = models.Author.objects.create(name="Test Author")
form = forms.AuthorForm(instance=author)
form.data['name'] = 'New Name'
form.data['last_edited_by'] = self.local_user.id
request = self.factory.post('', form.data)
form.data["name"] = "New Name"
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
with self.assertRaises(PermissionDenied):
view(request, author.id)
author.refresh_from_db()
self.assertEqual(author.name, 'Test Author')
self.assertEqual(author.name, "Test Author")
def test_edit_author_invalid_form(self):
''' edit an author with invalid post data'''
""" edit an author with invalid post data"""
view = views.EditAuthor.as_view()
author = models.Author.objects.create(name='Test Author')
author = models.Author.objects.create(name="Test Author")
self.local_user.groups.add(self.group)
form = forms.AuthorForm(instance=author)
form.data['name'] = ''
form.data['last_edited_by'] = self.local_user.id
request = self.factory.post('', form.data)
form.data["name"] = ""
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
resp = view(request, author.id)
author.refresh_from_db()
self.assertEqual(author.name, 'Test Author')
self.assertEqual(author.name, "Test Author")
resp.render()
self.assertEqual(resp.status_code, 200)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
@@ -8,28 +8,34 @@ from bookwyrm import models, views
class BlockViews(TestCase):
''' view user and edit profile '''
""" view user and edit profile """
def setUp(self):
''' we need basic test data and mocks '''
""" 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.models.user.set_remote_server.delay'):
"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', 'rat@rat.com', 'ratword',
"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',
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
models.SiteSettings.objects.create()
def test_block_get(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Block.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
@@ -37,19 +43,19 @@ class BlockViews(TestCase):
self.assertEqual(result.status_code, 200)
def test_block_post(self):
''' create a "block" database entry from an activity '''
""" create a "block" database entry from an activity """
view = views.Block.as_view()
self.local_user.followers.add(self.remote_user)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.UserFollowRequest.objects.create(
user_subject=self.local_user,
user_object=self.remote_user)
user_subject=self.local_user, user_object=self.remote_user
)
self.assertTrue(models.UserFollows.objects.exists())
self.assertTrue(models.UserFollowRequest.objects.exists())
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.remote_user.id)
block = models.UserBlocks.objects.get()
self.assertEqual(block.user_subject, self.local_user)
@@ -59,12 +65,12 @@ class BlockViews(TestCase):
self.assertFalse(models.UserFollowRequest.objects.exists())
def test_unblock(self):
''' undo a block '''
""" undo a block """
self.local_user.blocks.add(self.remote_user)
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.block.unblock(request, self.remote_user.id)
self.assertFalse(models.UserBlocks.objects.exists())

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
@@ -11,55 +11,58 @@ from bookwyrm.activitypub import ActivitypubResponse
class BookViews(TestCase):
''' books books books '''
""" books books books """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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 = 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
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.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
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 '''
""" there are so many views, this just makes sure it LOADS """
view = views.Book.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.books.is_api_request') as is_api:
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)
request = self.factory.get('')
with patch('bookwyrm.views.books.is_api_request') as is_api:
request = self.factory.get("")
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 '''
""" there are so many views, this just makes sure it LOADS """
view = views.EditBook.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request, self.book.id)
@@ -67,21 +70,19 @@ class BookViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_edit_book(self):
''' lets a user edit a book '''
""" lets a user edit a book """
view = views.EditBook.as_view()
self.local_user.groups.add(self.group)
form = forms.EditionForm(instance=self.book)
form.data['title'] = 'New Title'
form.data['last_edited_by'] = self.local_user.id
request = self.factory.post('', form.data)
form.data["title"] = "New Title"
form.data["last_edited_by"] = self.local_user.id
request = self.factory.post("", form.data)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.book.id)
self.book.refresh_from_db()
self.assertEqual(self.book.title, 'New Title')
self.assertEqual(self.book.title, "New Title")
def test_edit_book_add_author(self):
''' lets a user edit a book with new authors '''
@@ -141,49 +142,42 @@ class BookViews(TestCase):
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)
""" 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)
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 = self.factory.post("", {"edition": edition2.id})
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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 '''
""" 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:
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:
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)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@@ -8,20 +8,24 @@ from bookwyrm import views
class FederationViews(TestCase):
''' every response to a get request, html or json '''
""" every response to a get request, html or json """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_federation_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Federation.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
@@ -10,95 +10,93 @@ from bookwyrm.activitypub import ActivitypubResponse
class FeedMessageViews(TestCase):
''' dms '''
""" dms """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"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',
parent_work=models.Work.objects.create(title="hi"),
title="Example Edition",
remote_id="https://example.com/book/1",
)
models.SiteSettings.objects.create()
def test_feed(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Feed.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request, 'local')
result = view(request, "local")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_status_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Status.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
content='hi', user=self.local_user)
request = self.factory.get('')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(content="hi", user=self.local_user)
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.feed.is_api_request') as is_api:
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'mouse', status.id)
result = view(request, "mouse", status.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch('bookwyrm.views.feed.is_api_request') as is_api:
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = True
result = view(request, 'mouse', status.id)
result = view(request, "mouse", status.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_replies_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Replies.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
content='hi', user=self.local_user)
request = self.factory.get('')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(content="hi", user=self.local_user)
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.feed.is_api_request') as is_api:
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'mouse', status.id)
result = view(request, "mouse", status.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch('bookwyrm.views.feed.is_api_request') as is_api:
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = True
result = view(request, 'mouse', status.id)
result = view(request, "mouse", status.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_direct_messages_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.DirectMessage.as_view()
request = self.factory.get('')
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_get_suggested_book(self):
''' gets books the ~*~ algorithm ~*~ thinks you want to post about '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" 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')
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)
self.assertEqual(suggestions[0]["name"], "Currently Reading")
self.assertEqual(suggestions[0]["books"][0], self.book)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
@@ -9,148 +9,147 @@ from bookwyrm import models, views
class BookViews(TestCase):
''' books books books '''
""" books books books """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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'):
with patch("bookwyrm.models.user.set_remote_server"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@email.com', 'ratword',
"rat",
"rat@email.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',
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
self.group = Group.objects.create(name='editor')
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
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.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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
def test_handle_follow_remote(self):
''' send a follow request '''
request = self.factory.post('', {'user': self.remote_user.username})
""" send a follow request """
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.follow(request)
rel = models.UserFollowRequest.objects.get()
self.assertEqual(rel.user_subject, self.local_user)
self.assertEqual(rel.user_object, self.remote_user)
self.assertEqual(rel.status, 'follow_request')
self.assertEqual(rel.status, "follow_request")
def test_handle_follow_local_manually_approves(self):
''' send a follow request '''
""" 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',
"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 = self.factory.post("", {"user": rat})
request.user = self.local_user
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.follow(request)
rel = models.UserFollowRequest.objects.get()
self.assertEqual(rel.user_subject, self.local_user)
self.assertEqual(rel.user_object, rat)
self.assertEqual(rel.status, 'follow_request')
self.assertEqual(rel.status, "follow_request")
def test_handle_follow_local(self):
''' send a follow request '''
""" 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',
"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 = self.factory.post("", {"user": rat})
request.user = self.local_user
self.assertEqual(models.UserFollowRequest.objects.count(), 0)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.follow(request)
rel = models.UserFollows.objects.get()
self.assertEqual(rel.user_subject, self.local_user)
self.assertEqual(rel.user_object, rat)
self.assertEqual(rel.status, 'follows')
self.assertEqual(rel.status, "follows")
def test_handle_unfollow(self):
''' send an unfollow '''
request = self.factory.post('', {'user': self.remote_user.username})
""" send an unfollow """
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
self.remote_user.followers.add(self.local_user)
self.assertEqual(self.remote_user.followers.count(), 1)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
as mock:
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
views.unfollow(request)
self.assertEqual(mock.call_count, 1)
self.assertEqual(self.remote_user.followers.count(), 0)
def test_handle_accept(self):
''' accept a follow request '''
""" accept a follow request """
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
request = self.factory.post('', {'user': self.remote_user.username})
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
rel = models.UserFollowRequest.objects.create(
user_subject=self.remote_user,
user_object=self.local_user
user_subject=self.remote_user, user_object=self.local_user
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.accept_follow_request(request)
# request should be deleted
self.assertEqual(
models.UserFollowRequest.objects.filter(id=rel.id).count(), 0
)
self.assertEqual(models.UserFollowRequest.objects.filter(id=rel.id).count(), 0)
# follow relationship should exist
self.assertEqual(self.local_user.followers.first(), self.remote_user)
def test_handle_reject(self):
''' reject a follow request '''
""" reject a follow request """
self.local_user.manually_approves_followers = True
self.local_user.save(broadcast=False)
request = self.factory.post('', {'user': self.remote_user.username})
request = self.factory.post("", {"user": self.remote_user.username})
request.user = self.local_user
rel = models.UserFollowRequest.objects.create(
user_subject=self.remote_user,
user_object=self.local_user
user_subject=self.remote_user, user_object=self.local_user
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.delete_follow_request(request)
# request should be deleted
self.assertEqual(
models.UserFollowRequest.objects.filter(id=rel.id).count(), 0
)
self.assertEqual(models.UserFollowRequest.objects.filter(id=rel.id).count(), 0)
# follow relationship should not exist
self.assertEqual(
models.UserFollows.objects.filter(id=rel.id).count(), 0
)
self.assertEqual(models.UserFollows.objects.filter(id=rel.id).count(), 0)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.utils import timezone
@@ -11,60 +11,65 @@ from bookwyrm import models, views
class GoalViews(TestCase):
''' viewing and creating statuses '''
""" viewing and creating statuses """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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',
"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',
title="Example Edition",
remote_id="https://example.com/book/1",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_goal_page_no_goal(self):
''' view a reading goal page for another's unset goal '''
""" view a reading goal page for another's unset goal """
view = views.Goal.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.rat
result = view(request, self.local_user.localname, 2020)
self.assertEqual(result.status_code, 404)
def test_goal_page_no_goal_self(self):
''' view a reading goal page for your own unset goal '''
""" view a reading goal page for your own unset goal """
view = views.Goal.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request, self.local_user.localname, 2020)
result.render()
self.assertIsInstance(result, TemplateResponse)
def test_goal_page_anonymous(self):
''' can't view it without login '''
""" can't view it without login """
view = views.Goal.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request, self.local_user.localname, 2020)
self.assertEqual(result.status_code, 302)
def test_goal_page_public(self):
''' view a user's public goal '''
""" view a user's public goal """
models.ReadThrough.objects.create(
finish_date=timezone.now(),
user=self.local_user,
@@ -75,9 +80,10 @@ class GoalViews(TestCase):
user=self.local_user,
year=timezone.now().year,
goal=128937123,
privacy='public')
privacy="public",
)
view = views.Goal.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.rat
result = view(request, self.local_user.localname, timezone.now().year)
@@ -85,40 +91,40 @@ class GoalViews(TestCase):
self.assertIsInstance(result, TemplateResponse)
def test_goal_page_private(self):
''' view a user's private goal '''
""" 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=2020, goal=15, privacy="followers"
)
view = views.Goal.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.rat
result = view(request, self.local_user.localname, 2020)
self.assertEqual(result.status_code, 404)
def test_create_goal(self):
''' create a new goal '''
""" create a new goal """
view = views.Goal.as_view()
request = self.factory.post('', {
'user': self.local_user.id,
'goal': 10,
'year': 2020,
'privacy': 'unlisted',
'post-status': True
})
request = self.factory.post(
"",
{
"user": self.local_user.id,
"goal": 10,
"year": 2020,
"privacy": "unlisted",
"post-status": True,
},
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.local_user.localname, 2020)
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.privacy, 'unlisted')
self.assertEqual(goal.privacy, "unlisted")
status = models.GeneratedNote.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.privacy, 'unlisted')
self.assertEqual(status.privacy, "unlisted")

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
import json
from unittest.mock import patch
import pathlib
@@ -9,127 +9,129 @@ import responses
from bookwyrm import models, views
from bookwyrm.settings import USER_AGENT
class ViewsHelpers(TestCase):
''' viewing and creating statuses '''
""" viewing and creating statuses """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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.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
title="Test Book",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@rat.com', 'ratword',
"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',
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
datafile = pathlib.Path(__file__).parent.joinpath(
'../data/ap_user.json'
)
datafile = pathlib.Path(__file__).parent.joinpath("../data/ap_user.json")
self.userdata = json.loads(datafile.read_bytes())
del self.userdata['icon']
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
del self.userdata["icon"]
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
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
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)
""" 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):
''' works for either localname or username '''
""" works for either localname or username """
self.assertEqual(
views.helpers.get_user_from_username(
self.local_user, 'mouse'), self.local_user)
views.helpers.get_user_from_username(self.local_user, "mouse"),
self.local_user,
)
self.assertEqual(
views.helpers.get_user_from_username(
self.local_user, 'mouse@local.com'), self.local_user)
views.helpers.get_user_from_username(self.local_user, "mouse@local.com"),
self.local_user,
)
with self.assertRaises(models.User.DoesNotExist):
views.helpers.get_user_from_username(
self.local_user, 'mojfse@example.com')
views.helpers.get_user_from_username(self.local_user, "mojfse@example.com")
def test_is_api_request(self):
''' should it return html or json '''
request = self.factory.get('/path')
request.headers = {'Accept': 'application/json'}
""" should it return html or json """
request = self.factory.get("/path")
request.headers = {"Accept": "application/json"}
self.assertTrue(views.helpers.is_api_request(request))
request = self.factory.get('/path.json')
request.headers = {'Accept': 'Praise'}
request = self.factory.get("/path.json")
request.headers = {"Accept": "Praise"}
self.assertTrue(views.helpers.is_api_request(request))
request = self.factory.get('/path')
request.headers = {'Accept': 'Praise'}
request = self.factory.get("/path")
request.headers = {"Accept": "Praise"}
self.assertFalse(views.helpers.is_api_request(request))
def test_get_activity_feed(self):
''' loads statuses '''
""" loads statuses """
rat = models.User.objects.create_user(
'rat', 'rat@rat.rat', 'password', local=True)
"rat", "rat@rat.rat", "password", local=True
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
public_status = models.Comment.objects.create(
content='public status', book=self.book, user=self.local_user)
content="public status", book=self.book, user=self.local_user
)
direct_status = models.Status.objects.create(
content='direct', user=self.local_user, privacy='direct')
content="direct", user=self.local_user, privacy="direct"
)
rat_public = models.Status.objects.create(
content='blah blah', user=rat)
rat_public = models.Status.objects.create(content="blah blah", user=rat)
rat_unlisted = models.Status.objects.create(
content='blah blah', user=rat, privacy='unlisted')
content="blah blah", user=rat, privacy="unlisted"
)
remote_status = models.Status.objects.create(
content='blah blah', user=self.remote_user)
content="blah blah", user=self.remote_user
)
followers_status = models.Status.objects.create(
content='blah', user=rat, privacy='followers')
content="blah", user=rat, privacy="followers"
)
rat_mention = models.Status.objects.create(
content='blah blah blah', user=rat, privacy='followers')
content="blah blah blah", user=rat, privacy="followers"
)
rat_mention.mention_users.set([self.local_user])
statuses = views.helpers.get_activity_feed(
self.local_user,
privacy=['public', 'unlisted', 'followers'],
privacy=["public", "unlisted", "followers"],
following_only=True,
queryset=models.Comment.objects
queryset=models.Comment.objects,
)
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], public_status)
statuses = views.helpers.get_activity_feed(
self.local_user,
privacy=['public', 'followers'],
local_only=True
self.local_user, privacy=["public", "followers"], local_only=True
)
self.assertEqual(len(statuses), 2)
self.assertEqual(statuses[1], public_status)
self.assertEqual(statuses[0], rat_public)
statuses = views.helpers.get_activity_feed(
self.local_user, privacy=['direct'])
statuses = views.helpers.get_activity_feed(self.local_user, privacy=["direct"])
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], direct_status)
statuses = views.helpers.get_activity_feed(
self.local_user,
privacy=['public', 'followers'],
privacy=["public", "followers"],
)
self.assertEqual(len(statuses), 3)
self.assertEqual(statuses[2], public_status)
@@ -138,8 +140,8 @@ class ViewsHelpers(TestCase):
statuses = views.helpers.get_activity_feed(
self.local_user,
privacy=['public', 'unlisted', 'followers'],
following_only=True
privacy=["public", "unlisted", "followers"],
following_only=True,
)
self.assertEqual(len(statuses), 2)
self.assertEqual(statuses[1], public_status)
@@ -148,8 +150,8 @@ class ViewsHelpers(TestCase):
rat.followers.add(self.local_user)
statuses = views.helpers.get_activity_feed(
self.local_user,
privacy=['public', 'unlisted', 'followers'],
following_only=True
privacy=["public", "unlisted", "followers"],
following_only=True,
)
self.assertEqual(len(statuses), 5)
self.assertEqual(statuses[4], public_status)
@@ -158,187 +160,187 @@ class ViewsHelpers(TestCase):
self.assertEqual(statuses[1], followers_status)
self.assertEqual(statuses[0], rat_mention)
def test_get_activity_feed_blocks(self):
''' feed generation with blocked users '''
""" feed generation with blocked users """
rat = models.User.objects.create_user(
'rat', 'rat@rat.rat', 'password', local=True)
"rat", "rat@rat.rat", "password", local=True
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
public_status = models.Comment.objects.create(
content='public status', book=self.book, user=self.local_user)
rat_public = models.Status.objects.create(
content='blah blah', user=rat)
content="public status", book=self.book, user=self.local_user
)
rat_public = models.Status.objects.create(content="blah blah", user=rat)
statuses = views.helpers.get_activity_feed(
self.local_user, privacy=['public'])
self.local_user, privacy=["public"]
)
self.assertEqual(len(statuses), 2)
# block relationship
rat.blocks.add(self.local_user)
statuses = views.helpers.get_activity_feed(
self.local_user, privacy=['public'])
statuses = views.helpers.get_activity_feed(self.local_user, privacy=["public"])
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], public_status)
statuses = views.helpers.get_activity_feed(
rat, privacy=['public'])
statuses = views.helpers.get_activity_feed(rat, privacy=["public"])
self.assertEqual(len(statuses), 1)
self.assertEqual(statuses[0], rat_public)
def test_is_bookwyrm_request(self):
''' checks if a request came from a bookwyrm instance '''
request = self.factory.get('', {'q': 'Test Book'})
""" checks if a request came from a bookwyrm instance """
request = self.factory.get("", {"q": "Test Book"})
self.assertFalse(views.helpers.is_bookwyrm_request(request))
request = self.factory.get(
'', {'q': 'Test Book'},
HTTP_USER_AGENT=\
"http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)"
"",
{"q": "Test Book"},
HTTP_USER_AGENT="http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)",
)
self.assertFalse(views.helpers.is_bookwyrm_request(request))
request = self.factory.get(
'', {'q': 'Test Book'}, HTTP_USER_AGENT=USER_AGENT)
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):
''' simple database lookup by username '''
result = views.helpers.handle_remote_webfinger('@mouse@local.com')
""" simple database lookup by username """
result = views.helpers.handle_remote_webfinger("@mouse@local.com")
self.assertEqual(result, self.local_user)
result = views.helpers.handle_remote_webfinger('mouse@local.com')
result = views.helpers.handle_remote_webfinger("mouse@local.com")
self.assertEqual(result, self.local_user)
@responses.activate
def test_load_user(self):
''' find a remote user using webfinger '''
username = 'mouse@example.com'
""" find a remote user using webfinger """
username = "mouse@example.com"
wellknown = {
"subject": "acct:mouse@example.com",
"links": [{
"rel": "self",
"type": "application/activity+json",
"href": "https://example.com/user/mouse"
}]
"links": [
{
"rel": "self",
"type": "application/activity+json",
"href": "https://example.com/user/mouse",
}
],
}
responses.add(
responses.GET,
'https://example.com/.well-known/webfinger?resource=acct:%s' \
% username,
"https://example.com/.well-known/webfinger?resource=acct:%s" % username,
json=wellknown,
status=200)
status=200,
)
responses.add(
responses.GET,
'https://example.com/user/mouse',
"https://example.com/user/mouse",
json=self.userdata,
status=200)
with patch('bookwyrm.models.user.set_remote_server.delay'):
result = views.helpers.handle_remote_webfinger('@mouse@example.com')
status=200,
)
with patch("bookwyrm.models.user.set_remote_server.delay"):
result = views.helpers.handle_remote_webfinger("@mouse@example.com")
self.assertIsInstance(result, models.User)
self.assertEqual(result.username, 'mouse@example.com')
self.assertEqual(result.username, "mouse@example.com")
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'):
""" posts shelve activities """
shelf = self.local_user.shelf_set.get(identifier="to-read")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.helpers.handle_reading_status(
self.local_user, shelf, self.book, 'public')
self.local_user, shelf, self.book, "public"
)
status = models.GeneratedNote.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.mention_books.first(), self.book)
self.assertEqual(status.content, 'wants to read')
self.assertEqual(status.content, "wants to read")
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'):
""" posts shelve activities """
shelf = self.local_user.shelf_set.get(identifier="reading")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.helpers.handle_reading_status(
self.local_user, shelf, self.book, 'public')
self.local_user, shelf, self.book, "public"
)
status = models.GeneratedNote.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.mention_books.first(), self.book)
self.assertEqual(status.content, 'started reading')
self.assertEqual(status.content, "started reading")
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'):
""" posts shelve activities """
shelf = self.local_user.shelf_set.get(identifier="read")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.helpers.handle_reading_status(
self.local_user, shelf, self.book, 'public')
self.local_user, shelf, self.book, "public"
)
status = models.GeneratedNote.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.mention_books.first(), self.book)
self.assertEqual(status.content, 'finished reading')
self.assertEqual(status.content, "finished reading")
def test_handle_reading_status_other(self):
''' posts shelve activities '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" 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.local_user, self.shelf, self.book, "public"
)
self.assertFalse(models.GeneratedNote.objects.exists())
def test_object_visible_to_user(self):
''' does a user have permission to view an object '''
""" does a user have permission to view an object """
obj = models.Status.objects.create(
content='hi', user=self.remote_user, privacy='public')
self.assertTrue(
views.helpers.object_visible_to_user(self.local_user, obj))
content="hi", user=self.remote_user, privacy="public"
)
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Shelf.objects.create(
name='test', user=self.remote_user, privacy='unlisted')
self.assertTrue(
views.helpers.object_visible_to_user(self.local_user, obj))
name="test", user=self.remote_user, privacy="unlisted"
)
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Status.objects.create(
content='hi', user=self.remote_user, privacy='followers')
self.assertFalse(
views.helpers.object_visible_to_user(self.local_user, obj))
content="hi", user=self.remote_user, privacy="followers"
)
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Status.objects.create(
content='hi', user=self.remote_user, privacy='direct')
self.assertFalse(
views.helpers.object_visible_to_user(self.local_user, obj))
content="hi", user=self.remote_user, privacy="direct"
)
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Status.objects.create(
content='hi', user=self.remote_user, privacy='direct')
content="hi", user=self.remote_user, privacy="direct"
)
obj.mention_users.add(self.local_user)
self.assertTrue(
views.helpers.object_visible_to_user(self.local_user, obj))
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
def test_object_visible_to_user_follower(self):
''' what you can see if you follow a user '''
""" 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(
views.helpers.object_visible_to_user(self.local_user, obj))
content="hi", user=self.remote_user, privacy="followers"
)
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Status.objects.create(
content='hi', user=self.remote_user, privacy='direct')
self.assertFalse(
views.helpers.object_visible_to_user(self.local_user, obj))
content="hi", user=self.remote_user, privacy="direct"
)
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Status.objects.create(
content='hi', user=self.remote_user, privacy='direct')
content="hi", user=self.remote_user, privacy="direct"
)
obj.mention_users.add(self.local_user)
self.assertTrue(
views.helpers.object_visible_to_user(self.local_user, obj))
self.assertTrue(views.helpers.object_visible_to_user(self.local_user, obj))
def test_object_visible_to_user_blocked(self):
''' you can't see it if they block you '''
""" 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(
views.helpers.object_visible_to_user(self.local_user, obj))
content="hi", user=self.remote_user, privacy="public"
)
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))
obj = models.Shelf.objects.create(
name='test', user=self.remote_user, privacy='unlisted')
self.assertFalse(
views.helpers.object_visible_to_user(self.local_user, obj))
name="test", user=self.remote_user, privacy="unlisted"
)
self.assertFalse(views.helpers.object_visible_to_user(self.local_user, obj))

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
@@ -9,34 +9,37 @@ from bookwyrm import views
class ImportViews(TestCase):
''' goodreads import views '''
""" goodreads import views """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_import_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Import.as_view()
request = self.factory.get('')
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_import_status(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.ImportStatus.as_view()
import_job = models.ImportJob.objects.create(user=self.local_user)
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.tasks.app.AsyncResult') as async_result:
with patch("bookwyrm.tasks.app.AsyncResult") as async_result:
async_result.return_value = []
result = view(request, import_job.id)
self.assertIsInstance(result, TemplateResponse)

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.test import TestCase
from django.test.client import RequestFactory
@@ -7,40 +7,44 @@ from bookwyrm import models, views
class InteractionViews(TestCase):
''' viewing and creating statuses '''
""" viewing and creating statuses """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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'):
with patch("bookwyrm.models.user.set_remote_server"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@email.com', 'ratword',
"rat",
"rat@email.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',
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')
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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
def test_handle_favorite(self):
''' create and broadcast faving a status '''
""" create and broadcast faving a status """
view = views.Favorite.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.remote_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
user=self.local_user, content='hi')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
view(request, status.id)
fav = models.Favorite.objects.get()
@@ -48,106 +52,100 @@ class InteractionViews(TestCase):
self.assertEqual(fav.user, self.remote_user)
notification = models.Notification.objects.get()
self.assertEqual(notification.notification_type, 'FAVORITE')
self.assertEqual(notification.notification_type, "FAVORITE")
self.assertEqual(notification.user, self.local_user)
self.assertEqual(notification.related_user, self.remote_user)
def test_handle_unfavorite(self):
''' unfav a status '''
""" unfav a status """
view = views.Unfavorite.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.remote_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
user=self.local_user, content='hi')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
views.Favorite.as_view()(request, status.id)
self.assertEqual(models.Favorite.objects.count(), 1)
self.assertEqual(models.Notification.objects.count(), 1)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, status.id)
self.assertEqual(models.Favorite.objects.count(), 0)
self.assertEqual(models.Notification.objects.count(), 0)
def test_handle_boost(self):
''' boost a status '''
""" boost a status """
view = views.Boost.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.remote_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
user=self.local_user, content='hi')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
view(request, status.id)
boost = models.Boost.objects.get()
self.assertEqual(boost.boosted_status, status)
self.assertEqual(boost.user, self.remote_user)
self.assertEqual(boost.privacy, 'public')
self.assertEqual(boost.privacy, "public")
notification = models.Notification.objects.get()
self.assertEqual(notification.notification_type, 'BOOST')
self.assertEqual(notification.notification_type, "BOOST")
self.assertEqual(notification.user, self.local_user)
self.assertEqual(notification.related_user, self.remote_user)
self.assertEqual(notification.related_status, status)
def test_handle_boost_unlisted(self):
''' boost a status '''
""" boost a status """
view = views.Boost.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(
user=self.local_user, content='hi', privacy='unlisted')
user=self.local_user, content="hi", privacy="unlisted"
)
view(request, status.id)
boost = models.Boost.objects.get()
self.assertEqual(boost.privacy, 'unlisted')
self.assertEqual(boost.privacy, "unlisted")
def test_handle_boost_private(self):
''' boost a status '''
""" boost a status """
view = views.Boost.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(
user=self.local_user, content='hi', privacy='followers')
user=self.local_user, content="hi", privacy="followers"
)
view(request, status.id)
self.assertFalse(models.Boost.objects.exists())
def test_handle_boost_twice(self):
''' boost a status '''
""" boost a status """
view = views.Boost.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
user=self.local_user, content='hi')
with patch("bookwyrm.models.activitypub_mixin.broadcast_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)
def test_handle_unboost(self):
''' undo a boost '''
""" undo a boost """
view = views.Unboost.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
user=self.local_user, content='hi')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
views.Boost.as_view()(request, status.id)
self.assertEqual(models.Boost.objects.count(), 1)
self.assertEqual(models.Notification.objects.count(), 1)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
as mock:
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
view(request, status.id)
self.assertEqual(mock.call_count, 1)
self.assertEqual(models.Boost.objects.count(), 0)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
@@ -11,36 +11,39 @@ from bookwyrm import views
class InviteViews(TestCase):
''' every response to a get request, html or json '''
""" every response to a get request, html or json """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_invite_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Invite.as_view()
models.SiteInvite.objects.create(code='hi', user=self.local_user)
request = self.factory.get('')
models.SiteInvite.objects.create(code="hi", user=self.local_user)
request = self.factory.get("")
request.user = AnonymousUser
# why?? this is annoying.
request.user.is_authenticated = False
with patch('bookwyrm.models.site.SiteInvite.valid') as invite:
with patch("bookwyrm.models.site.SiteInvite.valid") as invite:
invite.return_value = True
result = view(request, 'hi')
result = view(request, "hi")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_manage_invites(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.ManageInvites.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
import json
from unittest.mock import patch
@@ -13,42 +13,41 @@ from bookwyrm.settings import DOMAIN
class IsbnViews(TestCase):
''' tag views'''
""" tag views"""
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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.work = models.Work.objects.create(title="Test Work")
self.book = models.Edition.objects.create(
title='Test Book',
isbn_13='1234567890123',
remote_id='https://example.com/book/1',
parent_work=self.work
title="Test Book",
isbn_13="1234567890123",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
models.Connector.objects.create(
identifier='self',
connector_file='self_connector',
local=True
identifier="self", connector_file="self_connector", local=True
)
models.SiteSettings.objects.create()
def test_isbn_json_response(self):
''' searches local data only and returns book data in json format '''
""" searches local data only and returns book data in json format """
view = views.Isbn.as_view()
request = self.factory.get('')
with patch('bookwyrm.views.isbn.is_api_request') as is_api:
request = self.factory.get("")
with patch("bookwyrm.views.isbn.is_api_request") as is_api:
is_api.return_value = True
response = view(request, isbn='1234567890123')
response = view(request, isbn="1234567890123")
self.assertIsInstance(response, JsonResponse)
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]["title"], "Test Book")
self.assertEqual(data[0]["key"], "https://%s/book/%d" % (DOMAIN, self.book.id))

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from django.contrib.auth.models import AnonymousUser
from django.template.response import TemplateResponse
from django.test import TestCase
@@ -9,22 +9,26 @@ from bookwyrm import views
class LandingViews(TestCase):
''' pages you land on without really trying '''
""" pages you land on without really trying """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"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):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Home.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertEqual(result.status_code, 200)
@@ -36,21 +40,19 @@ class LandingViews(TestCase):
self.assertEqual(result.status_code, 200)
result.render()
def test_about_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.About.as_view()
request = self.factory.get('')
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_discover(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Discover.as_view()
request = self.factory.get('')
request = self.factory.get("")
result = view(request)
self.assertIsInstance(result, TemplateResponse)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
@@ -9,44 +9,52 @@ from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm.activitypub import ActivitypubResponse
#pylint: disable=unused-argument
# pylint: disable=unused-argument
class ListViews(TestCase):
''' tag views'''
""" tag views"""
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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',
"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')
work = models.Work.objects.create(title="Work")
self.book = models.Edition.objects.create(
title='Example Edition',
remote_id='https://example.com/book/1',
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.models.activitypub_mixin.broadcast_task.delay"):
self.list = models.List.objects.create(
name='Test List', user=self.local_user)
name="Test List", user=self.local_user
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
models.SiteSettings.objects.create()
def test_lists_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Lists.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.List.objects.create(name='Public list', user=self.local_user)
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('')
name="Private list", privacy="direct", user=self.local_user
)
request = self.factory.get("")
request.user = self.local_user
result = view(request)
@@ -61,42 +69,45 @@ class ListViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_lists_create(self):
''' create list view '''
""" create list view """
real_broadcast = models.List.broadcast
def mock_broadcast(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Create')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity["type"], "Create")
self.assertEqual(activity["actor"], self.local_user.remote_id)
models.List.broadcast = mock_broadcast
view = views.Lists.as_view()
request = self.factory.post('', {
'name': 'A list',
'description': 'wow',
'privacy': 'unlisted',
'curation': 'open',
'user': self.local_user.id,
})
request = self.factory.post(
"",
{
"name": "A list",
"description": "wow",
"privacy": "unlisted",
"curation": "open",
"user": self.local_user.id,
},
)
request.user = self.local_user
result = view(request)
self.assertEqual(result.status_code, 302)
new_list = models.List.objects.filter(name='A list').get()
self.assertEqual(new_list.description, 'wow')
self.assertEqual(new_list.privacy, 'unlisted')
self.assertEqual(new_list.curation, 'open')
new_list = models.List.objects.filter(name="A list").get()
self.assertEqual(new_list.description, "wow")
self.assertEqual(new_list.privacy, "unlisted")
self.assertEqual(new_list.curation, "open")
models.List.broadcast = real_broadcast
def test_list_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.List.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.list.is_api_request') as is_api:
with patch("bookwyrm.views.list.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.list.id)
self.assertIsInstance(result, TemplateResponse)
@@ -104,68 +115,72 @@ class ListViews(TestCase):
self.assertEqual(result.status_code, 200)
request.user = self.anonymous_user
with patch('bookwyrm.views.list.is_api_request') as is_api:
with patch("bookwyrm.views.list.is_api_request") as is_api:
is_api.return_value = False
result = view(request, self.list.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch('bookwyrm.views.list.is_api_request') as is_api:
with patch("bookwyrm.views.list.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.list.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
request = self.factory.get('/?page=1')
request = self.factory.get("/?page=1")
request.user = self.local_user
with patch('bookwyrm.views.list.is_api_request') as is_api:
with patch("bookwyrm.views.list.is_api_request") as is_api:
is_api.return_value = True
result = view(request, self.list.id)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_list_edit(self):
''' edit a list '''
""" edit a list """
real_broadcast = models.List.broadcast
def mock_broadcast(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Update')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['object']['id'], self.list.remote_id)
self.assertEqual(activity["type"], "Update")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["object"]["id"], self.list.remote_id)
models.List.broadcast = mock_broadcast
view = views.List.as_view()
request = self.factory.post('', {
'name': 'New Name',
'description': 'wow',
'privacy': 'direct',
'curation': 'curated',
'user': self.local_user.id,
})
request = self.factory.post(
"",
{
"name": "New Name",
"description": "wow",
"privacy": "direct",
"curation": "curated",
"user": self.local_user.id,
},
)
request.user = self.local_user
result = view(request, self.list.id)
self.assertEqual(result.status_code, 302)
self.list.refresh_from_db()
self.assertEqual(self.list.name, 'New Name')
self.assertEqual(self.list.description, 'wow')
self.assertEqual(self.list.privacy, 'direct')
self.assertEqual(self.list.curation, 'curated')
self.assertEqual(self.list.name, "New Name")
self.assertEqual(self.list.description, "wow")
self.assertEqual(self.list.privacy, "direct")
self.assertEqual(self.list.curation, "curated")
models.List.broadcast = real_broadcast
def test_curate_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Curate.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
models.List.objects.create(name='Public list', user=self.local_user)
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('')
name="Private list", privacy="direct", user=self.local_user
)
request = self.factory.get("")
request.user = self.local_user
result = view(request, self.list.id)
@@ -177,31 +192,35 @@ class ListViews(TestCase):
result = view(request, self.list.id)
self.assertEqual(result.status_code, 302)
def test_curate_approve(self):
''' approve a pending item '''
""" approve a pending item """
real_broadcast = models.List.broadcast
def mock_broadcast(_, activity, user, **kwargs):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Add')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['target'], self.list.remote_id)
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
models.ListItem.broadcast = mock_broadcast
view = views.Curate.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
pending = models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=False
approved=False,
)
request = self.factory.post('', {
'item': pending.id,
'approved': 'true',
})
request = self.factory.post(
"",
{
"item": pending.id,
"approved": "true",
},
)
request.user = self.local_user
view(request, self.list.id)
@@ -211,43 +230,49 @@ class ListViews(TestCase):
self.assertTrue(pending.approved)
models.ListItem.broadcast = real_broadcast
def test_curate_reject(self):
''' approve a pending item '''
""" approve a pending item """
view = views.Curate.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
pending = models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
approved=False
approved=False,
)
request = self.factory.post('', {
'item': pending.id,
'approved': 'false',
})
request = self.factory.post(
"",
{
"item": pending.id,
"approved": "false",
},
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, self.list.id)
self.assertFalse(self.list.books.exists())
self.assertFalse(models.ListItem.objects.exists())
def test_add_book(self):
''' put a book on a list '''
""" put a book on a list """
real_broadcast = models.List.broadcast
def mock_broadcast(_, activity, user):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Add')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['target'], self.list.remote_id)
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
models.ListItem.broadcast = mock_broadcast
request = self.factory.post('', {
'book': self.book.id,
})
request = self.factory.post(
"",
{
"book": self.book.id,
},
)
request.user = self.local_user
views.list.add_book(request, self.list.id)
@@ -257,22 +282,26 @@ class ListViews(TestCase):
self.assertTrue(item.approved)
models.ListItem.broadcast = real_broadcast
def test_add_book_outsider(self):
''' put a book on a list '''
""" put a book on a list """
real_broadcast = models.List.broadcast
def mock_broadcast(_, activity, user):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.rat.remote_id)
self.assertEqual(activity['type'], 'Add')
self.assertEqual(activity['actor'], self.rat.remote_id)
self.assertEqual(activity['target'], self.list.remote_id)
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.rat.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
models.ListItem.broadcast = mock_broadcast
self.list.curation = 'open'
self.list.curation = "open"
self.list.save(broadcast=False)
request = self.factory.post('', {
'book': self.book.id,
})
request = self.factory.post(
"",
{
"book": self.book.id,
},
)
request.user = self.rat
views.list.add_book(request, self.list.id)
@@ -282,23 +311,27 @@ class ListViews(TestCase):
self.assertTrue(item.approved)
models.ListItem.broadcast = real_broadcast
def test_add_book_pending(self):
''' put a book on a list awaiting approval '''
""" put a book on a list awaiting approval """
real_broadcast = models.List.broadcast
def mock_broadcast(_, activity, user):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.rat.remote_id)
self.assertEqual(activity['type'], 'Add')
self.assertEqual(activity['actor'], self.rat.remote_id)
self.assertEqual(activity['target'], self.list.remote_id)
self.assertEqual(activity['object']['id'], self.book.remote_id)
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.rat.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
self.assertEqual(activity["object"]["id"], self.book.remote_id)
models.ListItem.broadcast = mock_broadcast
self.list.curation = 'curated'
self.list.curation = "curated"
self.list.save(broadcast=False)
request = self.factory.post('', {
'book': self.book.id,
})
request = self.factory.post(
"",
{
"book": self.book.id,
},
)
request.user = self.rat
views.list.add_book(request, self.list.id)
@@ -308,23 +341,27 @@ class ListViews(TestCase):
self.assertFalse(item.approved)
models.ListItem.broadcast = real_broadcast
def test_add_book_self_curated(self):
''' put a book on a list automatically approved '''
""" put a book on a list automatically approved """
real_broadcast = models.ListItem.broadcast
def mock_broadcast(_, activity, user):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Add')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['target'], self.list.remote_id)
self.assertEqual(activity["type"], "Add")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
models.ListItem.broadcast = mock_broadcast
self.list.curation = 'curated'
self.list.curation = "curated"
self.list.save(broadcast=False)
request = self.factory.post('', {
'book': self.book.id,
})
request = self.factory.post(
"",
{
"book": self.book.id,
},
)
request.user = self.local_user
views.list.add_book(request, self.list.id)
@@ -334,12 +371,11 @@ class ListViews(TestCase):
self.assertTrue(item.approved)
models.ListItem.broadcast = real_broadcast
def test_remove_book(self):
''' take an item off a list '''
""" take an item off a list """
real_broadcast = models.ListItem.broadcast
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
item = models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
@@ -348,15 +384,19 @@ class ListViews(TestCase):
self.assertTrue(self.list.listitem_set.exists())
def mock_broadcast(_, activity, user):
''' ok '''
""" ok """
self.assertEqual(user.remote_id, self.local_user.remote_id)
self.assertEqual(activity['type'], 'Remove')
self.assertEqual(activity['actor'], self.local_user.remote_id)
self.assertEqual(activity['target'], self.list.remote_id)
self.assertEqual(activity["type"], "Remove")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(activity["target"], self.list.remote_id)
models.ListItem.broadcast = mock_broadcast
request = self.factory.post('', {
'item': item.id,
})
request = self.factory.post(
"",
{
"item": item.id,
},
)
request.user = self.local_user
views.list.remove_book(request, self.list.id)
@@ -364,19 +404,21 @@ class ListViews(TestCase):
self.assertFalse(self.list.listitem_set.exists())
models.ListItem.broadcast = real_broadcast
def test_remove_book_unauthorized(self):
''' take an item off a list '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" take an item off a list """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
item = models.ListItem.objects.create(
book_list=self.list,
user=self.local_user,
book=self.book,
)
self.assertTrue(self.list.listitem_set.exists())
request = self.factory.post('', {
'item': item.id,
})
request = self.factory.post(
"",
{
"item": item.id,
},
)
request.user = self.rat
views.list.remove_book(request, self.list.id)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@@ -8,19 +8,24 @@ from bookwyrm import views
class NotificationViews(TestCase):
''' notifications '''
""" notifications """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_notifications_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Notifications.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
@@ -28,14 +33,16 @@ class NotificationViews(TestCase):
self.assertEqual(result.status_code, 200)
def test_clear_notifications(self):
''' erase notifications '''
""" erase notifications """
models.Notification.objects.create(
user=self.local_user, notification_type='FAVORITE')
user=self.local_user, notification_type="FAVORITE"
)
models.Notification.objects.create(
user=self.local_user, notification_type='MENTION', read=True)
user=self.local_user, notification_type="MENTION", read=True
)
self.assertEqual(models.Notification.objects.count(), 2)
view = views.Notifications.as_view()
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
result = view(request)
self.assertEqual(result.status_code, 302)

View File

@@ -1,4 +1,4 @@
''' sending out activities '''
""" sending out activities """
from unittest.mock import patch
import json
@@ -12,118 +12,127 @@ from bookwyrm.settings import USER_AGENT
# pylint: disable=too-many-public-methods
class OutboxView(TestCase):
''' sends out activities '''
""" sends out activities """
def setUp(self):
''' we'll need some data '''
""" 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',
"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')
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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
def test_outbox(self):
''' returns user's statuses '''
request = self.factory.get('')
result = views.Outbox.as_view()(request, 'mouse')
""" returns user's statuses """
request = self.factory.get("")
result = views.Outbox.as_view()(request, "mouse")
self.assertIsInstance(result, JsonResponse)
def test_outbox_bad_method(self):
''' can't POST to outbox '''
request = self.factory.post('')
result = views.Outbox.as_view()(request, 'mouse')
""" can't POST to outbox """
request = self.factory.post("")
result = views.Outbox.as_view()(request, "mouse")
self.assertEqual(result.status_code, 405)
def test_outbox_unknown_user(self):
''' should 404 for unknown and remote users '''
request = self.factory.post('')
result = views.Outbox.as_view()(request, 'beepboop')
""" should 404 for unknown and remote users """
request = self.factory.post("")
result = views.Outbox.as_view()(request, "beepboop")
self.assertEqual(result.status_code, 405)
result = views.Outbox.as_view()(request, 'rat')
result = views.Outbox.as_view()(request, "rat")
self.assertEqual(result.status_code, 405)
def test_outbox_privacy(self):
''' don't show dms et cetera in outbox '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" don't show dms et cetera in outbox """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Status.objects.create(
content='PRIVATE!!', user=self.local_user, privacy='direct')
content="PRIVATE!!", user=self.local_user, privacy="direct"
)
models.Status.objects.create(
content='bffs ONLY', user=self.local_user, privacy='followers')
content="bffs ONLY", user=self.local_user, privacy="followers"
)
models.Status.objects.create(
content='unlisted status', user=self.local_user,
privacy='unlisted')
content="unlisted status", user=self.local_user, privacy="unlisted"
)
models.Status.objects.create(
content='look at this', user=self.local_user, privacy='public')
content="look at this", user=self.local_user, privacy="public"
)
request = self.factory.get('')
result = views.Outbox.as_view()(request, 'mouse')
request = self.factory.get("")
result = views.Outbox.as_view()(request, "mouse")
self.assertIsInstance(result, JsonResponse)
data = json.loads(result.content)
self.assertEqual(data['type'], 'OrderedCollection')
self.assertEqual(data['totalItems'], 2)
self.assertEqual(data["type"], "OrderedCollection")
self.assertEqual(data["totalItems"], 2)
def test_outbox_filter(self):
''' if we only care about reviews, only get reviews '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" if we only care about reviews, only get reviews """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Review.objects.create(
content='look at this', name='hi', rating=1,
book=self.book, user=self.local_user)
models.Status.objects.create(
content='look at this', user=self.local_user)
content="look at this",
name="hi",
rating=1,
book=self.book,
user=self.local_user,
)
models.Status.objects.create(content="look at this", user=self.local_user)
request = self.factory.get('', {'type': 'bleh'})
result = views.Outbox.as_view()(request, 'mouse')
request = self.factory.get("", {"type": "bleh"})
result = views.Outbox.as_view()(request, "mouse")
self.assertIsInstance(result, JsonResponse)
data = json.loads(result.content)
self.assertEqual(data['type'], 'OrderedCollection')
self.assertEqual(data['totalItems'], 2)
self.assertEqual(data["type"], "OrderedCollection")
self.assertEqual(data["totalItems"], 2)
request = self.factory.get('', {'type': 'Review'})
result = views.Outbox.as_view()(request, 'mouse')
request = self.factory.get("", {"type": "Review"})
result = views.Outbox.as_view()(request, "mouse")
self.assertIsInstance(result, JsonResponse)
data = json.loads(result.content)
self.assertEqual(data['type'], 'OrderedCollection')
self.assertEqual(data['totalItems'], 1)
self.assertEqual(data["type"], "OrderedCollection")
self.assertEqual(data["totalItems"], 1)
def test_outbox_bookwyrm_request_true(self):
''' should differentiate between bookwyrm and outside requests '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" should differentiate between bookwyrm and outside requests """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Review.objects.create(
name='hi',
content='look at this',
name="hi",
content="look at this",
user=self.local_user,
book=self.book,
privacy='public',
privacy="public",
)
request = self.factory.get('', {'page': 1}, HTTP_USER_AGENT=USER_AGENT)
result = views.Outbox.as_view()(request, 'mouse')
request = self.factory.get("", {"page": 1}, HTTP_USER_AGENT=USER_AGENT)
result = views.Outbox.as_view()(request, "mouse")
data = json.loads(result.content)
self.assertEqual(len(data['orderedItems']), 1)
self.assertEqual(data['orderedItems'][0]['type'], 'Review')
self.assertEqual(len(data["orderedItems"]), 1)
self.assertEqual(data["orderedItems"][0]["type"], "Review")
def test_outbox_bookwyrm_request_false(self):
''' should differentiate between bookwyrm and outside requests '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" should differentiate between bookwyrm and outside requests """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.Review.objects.create(
name='hi',
content='look at this',
name="hi",
content="look at this",
user=self.local_user,
book=self.book,
privacy='public',
privacy="public",
)
request = self.factory.get('', {'page': 1})
result = views.Outbox.as_view()(request, 'mouse')
request = self.factory.get("", {"page": 1})
result = views.Outbox.as_view()(request, "mouse")
data = json.loads(result.content)
self.assertEqual(len(data['orderedItems']), 1)
self.assertEqual(data['orderedItems'][0]['type'], 'Article')
self.assertEqual(len(data["orderedItems"]), 1)
self.assertEqual(data["orderedItems"][0]["type"], "Article")

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
@@ -10,22 +10,26 @@ from bookwyrm import models, views
class PasswordViews(TestCase):
''' view user and edit profile '''
""" view user and edit profile """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"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)
def test_password_reset_request(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.PasswordResetRequest.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request)
@@ -33,76 +37,63 @@ class PasswordViews(TestCase):
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'})
""" send 'em an email """
request = self.factory.post("", {"email": "aa@bb.ccc"})
view = views.PasswordResetRequest.as_view()
resp = view(request)
self.assertEqual(resp.status_code, 302)
request = self.factory.post('', {'email': 'mouse@mouse.com'})
with patch('bookwyrm.emailing.send_email.delay'):
request = self.factory.post("", {"email": "mouse@mouse.com"})
with patch("bookwyrm.emailing.send_email.delay"):
resp = view(request)
resp.render()
self.assertEqual(
models.PasswordReset.objects.get().user, self.local_user)
self.assertEqual(models.PasswordReset.objects.get().user, self.local_user)
def test_password_reset(self):
''' there are so many views, this just makes sure it LOADS '''
""" 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)
request = self.factory.get('')
request = self.factory.get("")
request.user = self.anonymous_user
result = view(request, code.code)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_password_reset_post(self):
''' reset from code '''
""" 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'):
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
with patch("bookwyrm.views.password.login"):
resp = view(request, code.code)
self.assertEqual(resp.status_code, 302)
self.assertFalse(models.PasswordReset.objects.exists())
def test_password_reset_wrong_code(self):
''' reset from code '''
""" reset from code """
view = views.PasswordReset.as_view()
models.PasswordReset.objects.create(user=self.local_user)
request = self.factory.post('', {
'password': 'hi',
'confirm-password': 'hi'
})
resp = view(request, 'jhgdkfjgdf')
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
resp = view(request, "jhgdkfjgdf")
resp.render()
self.assertTrue(models.PasswordReset.objects.exists())
def test_password_reset_mismatch(self):
''' reset from code '''
""" 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': 'hihi'
})
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
resp = view(request, code.code)
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 '''
""" there are so many views, this just makes sure it LOADS """
view = views.ChangePassword.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
result = view(request)
@@ -110,28 +101,21 @@ class PasswordViews(TestCase):
result.render()
self.assertEqual(result.status_code, 200)
def test_password_change(self):
''' change password '''
""" change password """
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post('', {
'password': 'hi',
'confirm-password': 'hi'
})
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
request.user = self.local_user
with patch('bookwyrm.views.password.login'):
with patch("bookwyrm.views.password.login"):
view(request)
self.assertNotEqual(self.local_user.password, password_hash)
def test_password_change_mismatch(self):
''' change password '''
""" change password """
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post('', {
'password': 'hi',
'confirm-password': 'hihi'
})
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

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
import dateutil
from django.test import TestCase
@@ -7,45 +7,54 @@ from django.utils import timezone
from bookwyrm import models, views
class ReadingViews(TestCase):
''' viewing and creating statuses '''
""" viewing and creating statuses """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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.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
title="Test Book",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
with patch('bookwyrm.models.user.set_remote_server.delay'):
with patch("bookwyrm.models.user.set_remote_server.delay"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@rat.com', 'ratword',
"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',
remote_id="https://example.com/users/rat",
inbox="https://example.com/users/rat/inbox",
outbox="https://example.com/users/rat/outbox",
)
def test_start_reading(self):
''' begin a book '''
shelf = self.local_user.shelf_set.get(identifier='reading')
""" begin a book """
shelf = self.local_user.shelf_set.get(identifier="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',
})
request = self.factory.post(
"",
{
"post-status": True,
"privacy": "followers",
"start_date": "2020-01-05",
},
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.start_reading(request, self.book.id)
self.assertEqual(shelf.books.get(), self.book)
@@ -53,7 +62,7 @@ class ReadingViews(TestCase):
status = models.GeneratedNote.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.mention_books.get(), self.book)
self.assertEqual(status.privacy, 'followers')
self.assertEqual(status.privacy, "followers")
readthrough = models.ReadThrough.objects.get()
self.assertIsNotNone(readthrough.start_date)
@@ -61,45 +70,47 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.user, self.local_user)
self.assertEqual(readthrough.book, self.book)
def test_start_reading_reshelf(self):
''' begin a book '''
to_read_shelf = self.local_user.shelf_set.get(identifier='to-read')
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" begin a book """
to_read_shelf = self.local_user.shelf_set.get(identifier="to-read")
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
shelf=to_read_shelf, book=self.book, user=self.local_user)
shelf = self.local_user.shelf_set.get(identifier='reading')
shelf=to_read_shelf, book=self.book, user=self.local_user
)
shelf = self.local_user.shelf_set.get(identifier="reading")
self.assertEqual(to_read_shelf.books.get(), self.book)
self.assertFalse(shelf.books.exists())
self.assertFalse(models.Status.objects.exists())
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.start_reading(request, self.book.id)
self.assertFalse(to_read_shelf.books.exists())
self.assertEqual(shelf.books.get(), self.book)
def test_finish_reading(self):
''' begin a book '''
shelf = self.local_user.shelf_set.get(identifier='read')
""" begin a book """
shelf = self.local_user.shelf_set.get(identifier="read")
self.assertFalse(shelf.books.exists())
self.assertFalse(models.Status.objects.exists())
readthrough = models.ReadThrough.objects.create(
user=self.local_user,
start_date=timezone.now(),
book=self.book)
user=self.local_user, start_date=timezone.now(), book=self.book
)
request = self.factory.post('', {
'post-status': True,
'privacy': 'followers',
'finish_date': '2020-01-07',
'id': readthrough.id,
})
request = self.factory.post(
"",
{
"post-status": True,
"privacy": "followers",
"finish_date": "2020-01-07",
"id": readthrough.id,
},
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.finish_reading(request, self.book.id)
self.assertEqual(shelf.books.get(), self.book)
@@ -107,7 +118,7 @@ class ReadingViews(TestCase):
status = models.GeneratedNote.objects.get()
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.mention_books.get(), self.book)
self.assertEqual(status.privacy, 'followers')
self.assertEqual(status.privacy, "followers")
readthrough = models.ReadThrough.objects.get()
self.assertIsNotNone(readthrough.start_date)
@@ -115,19 +126,21 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.user, self.local_user)
self.assertEqual(readthrough.book, self.book)
def test_edit_readthrough(self):
''' adding dates to an ongoing readthrough '''
start = timezone.make_aware(dateutil.parser.parse('2021-01-03'))
""" adding dates to an ongoing readthrough """
start = timezone.make_aware(dateutil.parser.parse("2021-01-03"))
readthrough = models.ReadThrough.objects.create(
book=self.book, user=self.local_user, start_date=start)
book=self.book, user=self.local_user, start_date=start
)
request = self.factory.post(
'', {
'start_date': '2017-01-01',
'finish_date': '2018-03-07',
'book': '',
'id': readthrough.id,
})
"",
{
"start_date": "2017-01-01",
"finish_date": "2018-03-07",
"book": "",
"id": readthrough.id,
},
)
request.user = self.local_user
views.edit_readthrough(request)
@@ -140,33 +153,34 @@ class ReadingViews(TestCase):
self.assertEqual(readthrough.finish_date.day, 7)
self.assertEqual(readthrough.book, self.book)
def test_delete_readthrough(self):
''' remove a readthrough '''
""" remove a readthrough """
readthrough = models.ReadThrough.objects.create(
book=self.book, user=self.local_user)
models.ReadThrough.objects.create(
book=self.book, user=self.local_user)
book=self.book, user=self.local_user
)
models.ReadThrough.objects.create(book=self.book, user=self.local_user)
request = self.factory.post(
'', {
'id': readthrough.id,
})
"",
{
"id": readthrough.id,
},
)
request.user = self.local_user
views.delete_readthrough(request)
self.assertFalse(
models.ReadThrough.objects.filter(id=readthrough.id).exists())
self.assertFalse(models.ReadThrough.objects.filter(id=readthrough.id).exists())
def test_create_readthrough(self):
''' adding new read dates '''
""" adding new read dates """
request = self.factory.post(
'', {
'start_date': '2017-01-01',
'finish_date': '2018-03-07',
'book': self.book.id,
'id': '',
})
"",
{
"start_date": "2017-01-01",
"finish_date": "2018-03-07",
"book": self.book.id,
"id": "",
},
)
request.user = self.local_user
views.create_readthrough(request)

View File

@@ -1,4 +1,4 @@
''' tests updating reading progress '''
""" tests updating reading progress """
from datetime import datetime
from unittest.mock import patch
from django.test import TestCase, Client
@@ -6,63 +6,68 @@ from django.utils import timezone
from bookwyrm import models
@patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay')
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class ReadThrough(TestCase):
''' readthrough tests '''
""" readthrough tests """
def setUp(self):
''' basic user and book data '''
""" basic user and book data """
self.client = Client()
self.work = models.Work.objects.create(
title='Example Work'
)
self.work = models.Work.objects.create(title="Example Work")
self.edition = models.Edition.objects.create(
title='Example Edition',
parent_work=self.work
title="Example Edition", parent_work=self.work
)
self.work.default_edition = self.edition
self.work.save()
self.user = models.User.objects.create_user(
'cinco', 'cinco@example.com', 'seissiete',
local=True, localname='cinco')
"cinco", "cinco@example.com", "seissiete", local=True, localname="cinco"
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
self.client.force_login(self.user)
def test_create_basic_readthrough(self, delay_mock):
"""A basic readthrough doesn't create a progress update"""
self.assertEqual(self.edition.readthrough_set.count(), 0)
self.client.post('/start-reading/{}'.format(self.edition.id), {
'start_date': '2020-11-27',
})
self.client.post(
"/start-reading/{}".format(self.edition.id),
{
"start_date": "2020-11-27",
},
)
readthroughs = self.edition.readthrough_set.all()
self.assertEqual(len(readthroughs), 1)
self.assertEqual(readthroughs[0].progressupdate_set.count(), 0)
self.assertEqual(
readthroughs[0].start_date,
datetime(2020, 11, 27, tzinfo=timezone.utc))
readthroughs[0].start_date, datetime(2020, 11, 27, tzinfo=timezone.utc)
)
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):
''' a readthrough with progress '''
""" a readthrough with progress """
self.assertEqual(self.edition.readthrough_set.count(), 0)
self.client.post('/start-reading/{}'.format(self.edition.id), {
'start_date': '2020-11-27',
'progress': 50,
})
self.client.post(
"/start-reading/{}".format(self.edition.id),
{
"start_date": "2020-11-27",
"progress": 50,
},
)
readthroughs = self.edition.readthrough_set.all()
self.assertEqual(len(readthroughs), 1)
self.assertEqual(
readthroughs[0].start_date,
datetime(2020, 11, 27, tzinfo=timezone.utc))
readthroughs[0].start_date, datetime(2020, 11, 27, tzinfo=timezone.utc)
)
self.assertEqual(readthroughs[0].progress, 50)
self.assertEqual(readthroughs[0].finish_date, None)
@@ -73,13 +78,17 @@ class ReadThrough(TestCase):
self.assertEqual(delay_mock.call_count, 1)
# Update progress
self.client.post('/edit-readthrough', {
'id': readthroughs[0].id,
'progress': 100,
})
self.client.post(
"/edit-readthrough",
{
"id": readthroughs[0].id,
"progress": 100,
},
)
progress_updates = readthroughs[0].progressupdate_set\
.order_by('updated_date').all()
progress_updates = (
readthroughs[0].progressupdate_set.order_by("updated_date").all()
)
self.assertEqual(len(progress_updates), 2)
self.assertEqual(progress_updates[1].mode, models.ProgressMode.PAGE)
self.assertEqual(progress_updates[1].progress, 100)
@@ -87,9 +96,12 @@ class ReadThrough(TestCase):
# Edit doesn't publish anything
self.assertEqual(delay_mock.call_count, 1)
self.client.post('/delete-readthrough', {
'id': readthroughs[0].id,
})
self.client.post(
"/delete-readthrough",
{
"id": readthroughs[0].id,
},
)
readthroughs = self.edition.readthrough_set.all()
updates = self.user.progressupdate_set.all()

View File

@@ -1,4 +1,4 @@
''' testing import '''
""" testing import """
from unittest.mock import patch
from django.test import RequestFactory, TestCase
@@ -6,41 +6,51 @@ from django.test import RequestFactory, TestCase
from bookwyrm import models
from bookwyrm.views import rss_feed
class RssFeedView(TestCase):
''' rss feed behaves as expected '''
""" rss feed behaves as expected """
def setUp(self):
''' test data '''
""" test data """
self.site = models.SiteSettings.objects.create()
self.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
"rss_user", "rss@test.rss", "password", local=True
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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"):
self.review = models.Review.objects.create(
name='Review name', content='test content', rating=3,
user=self.user, book=self.book)
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)
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)
content="test content", user=self.user
)
self.factory = RequestFactory()
def test_rss_feed(self):
''' load an rss feed '''
""" load an rss feed """
view = rss_feed.RssFeed()
request = self.factory.get('/user/rss_user/rss')
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

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
import json
from unittest.mock import patch
@@ -13,103 +13,107 @@ from bookwyrm.settings import DOMAIN
class ShelfViews(TestCase):
''' tag views'''
""" tag views"""
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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.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
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
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 '''
""" 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:
request = self.factory.get("", {"q": "Test Book"})
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = True
response = view(request)
self.assertIsInstance(response, JsonResponse)
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]["title"], "Test Book")
self.assertEqual(data[0]["key"], "https://%s/book/%d" % (DOMAIN, self.book.id))
def test_search_html_response(self):
''' searches remote connectors '''
""" searches remote connectors """
view = views.Search.as_view()
class TestConnector(abstract_connector.AbstractMinimalConnector):
''' nothing added here '''
""" 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',
base_url='https://example.com',
books_url='https://example.com/books',
covers_url='https://example.com/covers',
search_url='https://example.com/search?q=',
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=",
)
connector = TestConnector('example.com')
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
key="http://www.example.com/book/1",
title="Gideon the Ninth",
author="Tamsyn Muir",
year="2019",
connector=connector,
)
request = self.factory.get('', {'q': 'Test Book'})
request = self.factory.get("", {"q": "Test Book"})
request.user = self.local_user
with patch('bookwyrm.views.search.is_api_request') as is_api:
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:
with patch("bookwyrm.connectors.connector_manager.search") as manager:
manager.return_value = [search_result]
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
self.assertEqual(
response.context_data['book_results'][0].title, 'Gideon the Ninth')
response.context_data["book_results"][0].title, "Gideon the Ninth"
)
def test_search_html_response_users(self):
''' searches remote connectors '''
""" searches remote connectors """
view = views.Search.as_view()
request = self.factory.get('', {'q': 'mouse'})
request = self.factory.get("", {"q": "mouse"})
request.user = self.local_user
with patch('bookwyrm.views.search.is_api_request') as is_api:
with patch("bookwyrm.views.search.is_api_request") as is_api:
is_api.return_value = False
with patch('bookwyrm.connectors.connector_manager.search'):
with patch("bookwyrm.connectors.connector_manager.search"):
response = view(request)
self.assertIsInstance(response, TemplateResponse)
response.render()
self.assertEqual(
response.context_data['user_results'][0], self.local_user)
self.assertEqual(response.context_data["user_results"][0], self.local_user)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.template.response import TemplateResponse
from django.test import TestCase
@@ -8,195 +8,172 @@ from bookwyrm import models, views
from bookwyrm.activitypub import ActivitypubResponse
@patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay')
@patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay")
class ShelfViews(TestCase):
''' tag views'''
""" tag views"""
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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.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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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
name="Test Shelf", identifier="test-shelf", user=self.local_user
)
models.SiteSettings.objects.create()
def test_shelf_page(self, _):
''' there are so many views, this just makes sure it LOADS '''
""" 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 = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
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:
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)
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 = self.factory.get("/?page=1")
request.user = self.local_user
with patch('bookwyrm.views.shelf.is_api_request') as is_api:
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)
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 '''
""" 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')
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',
})
"",
{
"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')
self.assertEqual(shelf.privacy, "unlisted")
def test_edit_shelf_name(self, _):
''' change the name of an editable shelf '''
""" 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')
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'
})
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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)
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 '''
""" 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')
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'
})
"", {"privacy": "public", "user": self.local_user.id, "name": "cool name"}
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, request.user.username, shelf.identifier)
self.assertEqual(shelf.name, 'To Read')
self.assertEqual(shelf.name, "To Read")
def test_handle_shelve(self, _):
''' shelve a book '''
request = self.factory.post('', {
'book': self.book.id,
'shelf': self.shelf.identifier
})
""" shelve a book """
request = self.factory.post(
"", {"book": self.book.id, "shelf": self.shelf.identifier}
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.shelve(request)
# make sure the book is on the shelf
self.assertEqual(self.shelf.books.get(), self.book)
def test_handle_shelve_to_read(self, _):
''' special behavior for the to-read shelf '''
shelf = models.Shelf.objects.get(identifier='to-read')
request = self.factory.post('', {
'book': self.book.id,
'shelf': shelf.identifier
})
""" special behavior for the to-read shelf """
shelf = models.Shelf.objects.get(identifier="to-read")
request = self.factory.post(
"", {"book": self.book.id, "shelf": shelf.identifier}
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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)
def test_handle_shelve_reading(self, _):
''' special behavior for the reading shelf '''
shelf = models.Shelf.objects.get(identifier='reading')
request = self.factory.post('', {
'book': self.book.id,
'shelf': shelf.identifier
})
""" special behavior for the reading shelf """
shelf = models.Shelf.objects.get(identifier="reading")
request = self.factory.post(
"", {"book": self.book.id, "shelf": shelf.identifier}
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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)
def test_handle_shelve_read(self, _):
''' special behavior for the read shelf '''
shelf = models.Shelf.objects.get(identifier='read')
request = self.factory.post('', {
'book': self.book.id,
'shelf': shelf.identifier
})
""" special behavior for the read shelf """
shelf = models.Shelf.objects.get(identifier="read")
request = self.factory.post(
"", {"book": self.book.id, "shelf": shelf.identifier}
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
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)
def test_handle_unshelve(self, _):
''' remove a book from a shelf '''
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
""" remove a book from a shelf """
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.shelf
book=self.book, user=self.local_user, shelf=self.shelf
)
self.shelf.save()
self.assertEqual(self.shelf.books.count(), 1)
request = self.factory.post('', {
'book': self.book.id,
'shelf': self.shelf.id
})
request = self.factory.post("", {"book": self.book.id, "shelf": self.shelf.id})
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
views.unshelve(request)
self.assertEqual(self.shelf.books.count(), 0)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
import json
from unittest.mock import patch
from django.test import TestCase
@@ -9,239 +9,247 @@ from bookwyrm.settings import DOMAIN
class StatusViews(TestCase):
''' viewing and creating statuses '''
""" viewing and creating statuses """
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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'):
with patch("bookwyrm.models.user.set_remote_server"):
self.remote_user = models.User.objects.create_user(
'rat', 'rat@email.com', 'ratword',
"rat",
"rat@email.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',
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')
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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=work,
)
def test_handle_status(self):
''' create a status '''
""" create a status """
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)
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
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
view(request, 'comment')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, "comment")
status = models.Comment.objects.get()
self.assertEqual(status.content, '<p>hi</p>')
self.assertEqual(status.content, "<p>hi</p>")
self.assertEqual(status.user, self.local_user)
self.assertEqual(status.book, self.book)
def test_handle_status_reply(self):
''' create a status in reply to an existing status '''
""" 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.models.activitypub_mixin.broadcast_task.delay'):
"rat", "rat@rat.com", "password", local=True
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
parent = models.Status.objects.create(
content='parent status', user=self.local_user)
form = forms.ReplyForm({
'content': 'hi',
'user': user.id,
'reply_parent': parent.id,
'privacy': 'public',
})
request = self.factory.post('', form.data)
content="parent status", user=self.local_user
)
form = forms.ReplyForm(
{
"content": "hi",
"user": user.id,
"reply_parent": parent.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
request.user = user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
view(request, 'reply')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, "reply")
status = models.Status.objects.get(user=user)
self.assertEqual(status.content, '<p>hi</p>')
self.assertEqual(status.content, "<p>hi</p>")
self.assertEqual(status.user, user)
self.assertEqual(
models.Notification.objects.get().user, self.local_user)
self.assertEqual(models.Notification.objects.get().user, self.local_user)
def test_handle_status_mentions(self):
''' @mention a user in a post '''
""" @mention a user in a post """
view = views.CreateStatus.as_view()
user = models.User.objects.create_user(
'rat@%s' % DOMAIN, 'rat@rat.com', 'password',
local=True, localname='rat')
form = forms.CommentForm({
'content': 'hi @rat',
'user': self.local_user.id,
'book': self.book.id,
'privacy': 'public',
})
request = self.factory.post('', form.data)
"rat@%s" % DOMAIN, "rat@rat.com", "password", local=True, localname="rat"
)
form = forms.CommentForm(
{
"content": "hi @rat",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
view(request, 'comment')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
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, '<p>hi <a href="%s">@rat</a></p>' % user.remote_id
)
def test_handle_status_reply_with_mentions(self):
''' reply to a post with an @mention'ed user '''
""" reply to a post with an @mention'ed user """
view = views.CreateStatus.as_view()
user = models.User.objects.create_user(
'rat', 'rat@rat.com', 'password',
local=True, localname='rat')
form = forms.CommentForm({
'content': 'hi @rat@example.com',
'user': self.local_user.id,
'book': self.book.id,
'privacy': 'public',
})
request = self.factory.post('', form.data)
"rat", "rat@rat.com", "password", local=True, localname="rat"
)
form = forms.CommentForm(
{
"content": "hi @rat@example.com",
"user": self.local_user.id,
"book": self.book.id,
"privacy": "public",
}
)
request = self.factory.post("", form.data)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
view(request, 'comment')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, "comment")
status = models.Status.objects.get()
form = forms.ReplyForm({
'content': 'right',
'user': user.id,
'privacy': 'public',
'reply_parent': status.id
})
request = self.factory.post('', form.data)
form = forms.ReplyForm(
{
"content": "right",
"user": user.id,
"privacy": "public",
"reply_parent": status.id,
}
)
request = self.factory.post("", form.data)
request.user = user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
view(request, 'reply')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request, "reply")
reply = models.Status.replies(status).first()
self.assertEqual(reply.content, '<p>right</p>')
self.assertEqual(reply.content, "<p>right</p>")
self.assertEqual(reply.user, user)
# the mentioned user in the parent post is only included if @'ed
self.assertFalse(self.remote_user in reply.mention_users.all())
self.assertTrue(self.local_user in reply.mention_users.all())
def test_find_mentions(self):
''' detect and look up @ mentions of users '''
""" detect and look up @ mentions of users """
user = models.User.objects.create_user(
'nutria@%s' % DOMAIN, 'nutria@nutria.com', 'password',
local=True, localname='nutria')
self.assertEqual(user.username, 'nutria@%s' % DOMAIN)
"nutria@%s" % DOMAIN,
"nutria@nutria.com",
"password",
local=True,
localname="nutria",
)
self.assertEqual(user.username, "nutria@%s" % DOMAIN)
self.assertEqual(
list(views.status.find_mentions('@nutria'))[0],
('@nutria', user)
list(views.status.find_mentions("@nutria"))[0], ("@nutria", user)
)
self.assertEqual(
list(views.status.find_mentions('leading text @nutria'))[0],
('@nutria', user)
list(views.status.find_mentions("leading text @nutria"))[0],
("@nutria", user),
)
self.assertEqual(
list(views.status.find_mentions(
'leading @nutria trailing text'))[0],
('@nutria', user)
list(views.status.find_mentions("leading @nutria trailing text"))[0],
("@nutria", user),
)
self.assertEqual(
list(views.status.find_mentions(
'@rat@example.com'))[0],
('@rat@example.com', self.remote_user)
list(views.status.find_mentions("@rat@example.com"))[0],
("@rat@example.com", self.remote_user),
)
multiple = list(views.status.find_mentions(
'@nutria and @rat@example.com'))
self.assertEqual(multiple[0], ('@nutria', user))
self.assertEqual(multiple[1], ('@rat@example.com', self.remote_user))
multiple = list(views.status.find_mentions("@nutria and @rat@example.com"))
self.assertEqual(multiple[0], ("@nutria", user))
self.assertEqual(multiple[1], ("@rat@example.com", self.remote_user))
with patch('bookwyrm.views.status.handle_remote_webfinger') as rw:
with patch("bookwyrm.views.status.handle_remote_webfinger") as rw:
rw.return_value = self.local_user
self.assertEqual(
list(views.status.find_mentions('@beep@beep.com'))[0],
('@beep@beep.com', self.local_user)
list(views.status.find_mentions("@beep@beep.com"))[0],
("@beep@beep.com", self.local_user),
)
with patch('bookwyrm.views.status.handle_remote_webfinger') as rw:
with patch("bookwyrm.views.status.handle_remote_webfinger") as rw:
rw.return_value = None
self.assertEqual(list(views.status.find_mentions(
'@beep@beep.com')), [])
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("@nutria@%s" % DOMAIN))[0],
("@nutria@%s" % DOMAIN, user),
)
def test_format_links(self):
''' find and format urls into a tags '''
url = 'http://www.fish.com/'
""" 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
)
self.assertEqual(
views.status.format_links("(%s)" % url),
'(<a href="%s">www.fish.com/</a>)' % url,
)
url = "https://archive.org/details/dli.granth.72113/page/n25/mode/2up"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">www.fish.com/</a>' % url)
self.assertEqual(
views.status.format_links('(%s)' % url),
'(<a href="%s">www.fish.com/</a>)' % url)
url = 'https://archive.org/details/dli.granth.72113/page/n25/mode/2up'
'<a href="%s">'
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>" % url,
)
url = "https://openlibrary.org/search" "?q=arkady+strugatsky&mode=everything"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">' \
'archive.org/details/dli.granth.72113/page/n25/mode/2up</a>' \
% url)
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)
'<a href="%s">openlibrary.org/search'
"?q=arkady+strugatsky&mode=everything</a>" % url,
)
def test_to_markdown(self):
''' this is mostly handled in other places, but nonetheless '''
text = '_hi_ and http://fish.com is <marquee>rad</marquee>'
""" 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)
self.assertEqual(
result,
'<p><em>hi</em> and <a href="http://fish.com">fish.com</a> ' \
'is rad</p>')
'<p><em>hi</em> and <a href="http://fish.com">fish.com</a> ' "is rad</p>",
)
def test_to_markdown_link(self):
''' this is mostly handled in other places, but nonetheless '''
text = '[hi](http://fish.com) is <marquee>rad</marquee>'
""" 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>')
self.assertEqual(result, '<p><a href="http://fish.com">hi</a> ' "is rad</p>")
def test_handle_delete_status(self):
''' marks a status as deleted '''
""" marks a status as deleted """
view = views.DeleteStatus.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
status = models.Status.objects.create(
user=self.local_user, content='hi')
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
status = models.Status.objects.create(user=self.local_user, content="hi")
self.assertFalse(status.deleted)
request = self.factory.post('')
request = self.factory.post("")
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
as mock:
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay") as mock:
view(request, status.id)
activity = json.loads(mock.call_args_list[0][0][1])
self.assertEqual(activity['type'], 'Delete')
self.assertEqual(activity['object']['type'], 'Tombstone')
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["object"]["type"], "Tombstone")
status.refresh_from_db()
self.assertTrue(status.deleted)

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
from unittest.mock import patch
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
@@ -11,107 +11,109 @@ from bookwyrm.activitypub import ActivitypubResponse
class TagViews(TestCase):
''' tag views'''
""" tag views"""
def setUp(self):
''' we need basic test data and mocks '''
""" 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',
"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 = 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
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.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
title="Example Edition",
remote_id="https://example.com/book/1",
parent_work=self.work,
)
models.SiteSettings.objects.create()
def test_tag_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Tag.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
tag = models.Tag.objects.create(name='hi there')
models.UserTag.objects.create(
tag=tag, user=self.local_user, book=self.book)
request = self.factory.get('')
with patch('bookwyrm.views.tag.is_api_request') as is_api:
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
tag = models.Tag.objects.create(name="hi there")
models.UserTag.objects.create(tag=tag, user=self.local_user, book=self.book)
request = self.factory.get("")
with patch("bookwyrm.views.tag.is_api_request") as is_api:
is_api.return_value = False
result = view(request, tag.identifier)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
request = self.factory.get('')
with patch('bookwyrm.views.tag.is_api_request') as is_api:
request = self.factory.get("")
with patch("bookwyrm.views.tag.is_api_request") as is_api:
is_api.return_value = True
result = view(request, tag.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_tag_page_activitypub_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Tag.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
tag = models.Tag.objects.create(name='hi there')
models.UserTag.objects.create(
tag=tag, user=self.local_user, book=self.book)
request = self.factory.get('', {'page': 1})
with patch('bookwyrm.views.tag.is_api_request') as is_api:
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
tag = models.Tag.objects.create(name="hi there")
models.UserTag.objects.create(tag=tag, user=self.local_user, book=self.book)
request = self.factory.get("", {"page": 1})
with patch("bookwyrm.views.tag.is_api_request") as is_api:
is_api.return_value = True
result = view(request, tag.identifier)
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_tag(self):
''' add a tag to a book '''
""" add a tag to a book """
view = views.AddTag.as_view()
request = self.factory.post(
'', {
'name': 'A Tag!?',
'book': self.book.id,
})
"",
{
"name": "A Tag!?",
"book": self.book.id,
},
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request)
tag = models.Tag.objects.get()
user_tag = models.UserTag.objects.get()
self.assertEqual(tag.name, 'A Tag!?')
self.assertEqual(tag.identifier, 'A+Tag%21%3F')
self.assertEqual(tag.name, "A Tag!?")
self.assertEqual(tag.identifier, "A+Tag%21%3F")
self.assertEqual(user_tag.user, self.local_user)
self.assertEqual(user_tag.book, self.book)
def test_untag(self):
''' remove a tag from a book '''
""" remove a tag from a book """
view = views.RemoveTag.as_view()
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
tag = models.Tag.objects.create(name='A Tag!?')
models.UserTag.objects.create(
user=self.local_user, book=self.book, tag=tag)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
tag = models.Tag.objects.create(name="A Tag!?")
models.UserTag.objects.create(user=self.local_user, book=self.book, tag=tag)
request = self.factory.post(
'', {
'user': self.local_user.id,
'book': self.book.id,
'name': tag.name,
})
"",
{
"user": self.local_user.id,
"book": self.book.id,
"name": tag.name,
},
)
request.user = self.local_user
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay'):
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
view(request)
self.assertTrue(models.Tag.objects.filter(name='A Tag!?').exists())
self.assertTrue(models.Tag.objects.filter(name="A Tag!?").exists())
self.assertFalse(models.UserTag.objects.exists())

View File

@@ -1,4 +1,4 @@
''' test for app action functionality '''
""" test for app action functionality """
import pathlib
from unittest.mock import patch
from PIL import Image
@@ -15,180 +15,177 @@ from bookwyrm.activitypub import ActivitypubResponse
class UserViews(TestCase):
''' view user and edit profile '''
""" view user and edit profile """
def setUp(self):
''' we need basic test data and mocks '''
""" 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')
"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')
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
models.SiteSettings.objects.create()
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
def test_user_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.User.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
request.user = self.anonymous_user
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = True
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_user_page_blocked(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.User.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
self.rat.blocks.add(self.local_user)
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'rat')
result = view(request, "rat")
self.assertEqual(result.status_code, 404)
def test_followers_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Followers.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = True
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_followers_page_blocked(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Followers.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
self.rat.blocks.add(self.local_user)
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'rat')
result = view(request, "rat")
self.assertEqual(result.status_code, 404)
def test_following_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Following.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = True
result = view(request, 'mouse')
result = view(request, "mouse")
self.assertIsInstance(result, ActivitypubResponse)
self.assertEqual(result.status_code, 200)
def test_following_page_blocked(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.Following.as_view()
request = self.factory.get('')
request = self.factory.get("")
request.user = self.local_user
self.rat.blocks.add(self.local_user)
with patch('bookwyrm.views.user.is_api_request') as is_api:
with patch("bookwyrm.views.user.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 'rat')
result = view(request, "rat")
self.assertEqual(result.status_code, 404)
def test_edit_user_page(self):
''' there are so many views, this just makes sure it LOADS '''
""" there are so many views, this just makes sure it LOADS """
view = views.EditUser.as_view()
request = self.factory.get('')
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_edit_user(self):
''' use a form to update a user '''
""" 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'
request = self.factory.post('', form.data)
form.data["name"] = "New Name"
form.data["email"] = "wow@email.com"
request = self.factory.post("", form.data)
request.user = self.local_user
self.assertIsNone(self.local_user.name)
with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
as delay_mock:
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
view(request)
self.assertEqual(delay_mock.call_count, 1)
self.assertEqual(self.local_user.name, 'New Name')
self.assertEqual(self.local_user.email, 'wow@email.com')
self.assertEqual(self.local_user.name, "New Name")
self.assertEqual(self.local_user.email, "wow@email.com")
# idk how to mock the upload form, got tired of triyng to make it work
# 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'
# image_file = pathlib.Path(__file__).parent.joinpath(
# '../../static/images/no_cover.jpg')
# image = Image.open(image_file)
# form.files['avatar'] = SimpleUploadedFile(
# image_file, open(image_file), content_type='image/jpeg')
# request = self.factory.post('', form.data, form.files)
# request.user = self.local_user
# idk how to mock the upload form, got tired of triyng to make it work
# 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'
# image_file = pathlib.Path(__file__).parent.joinpath(
# '../../static/images/no_cover.jpg')
# image = Image.open(image_file)
# form.files['avatar'] = SimpleUploadedFile(
# image_file, open(image_file), content_type='image/jpeg')
# request = self.factory.post('', form.data, form.files)
# request.user = self.local_user
# with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
# as delay_mock:
# view(request)
# self.assertEqual(delay_mock.call_count, 1)
# self.assertEqual(self.local_user.name, 'New Name')
# self.assertEqual(self.local_user.email, 'wow@email.com')
# self.assertIsNotNone(self.local_user.avatar)
# self.assertEqual(self.local_user.avatar.size, (120, 120))
# with patch('bookwyrm.models.activitypub_mixin.broadcast_task.delay') \
# as delay_mock:
# view(request)
# self.assertEqual(delay_mock.call_count, 1)
# self.assertEqual(self.local_user.name, 'New Name')
# self.assertEqual(self.local_user.email, 'wow@email.com')
# self.assertIsNotNone(self.local_user.avatar)
# self.assertEqual(self.local_user.avatar.size, (120, 120))
def test_crop_avatar(self):
''' reduce that image size '''
""" 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.user.crop_avatar(image)