regluit/core/tests.py

509 lines
20 KiB
Python
Executable File

from decimal import Decimal as D
from datetime import datetime, timedelta
from django.test import TestCase
from django.test.client import Client
from django.utils import unittest
from django.db import IntegrityError
from django.contrib.auth.models import User
from django.conf import settings
from django.contrib.comments.models import Comment
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from regluit.payment.models import Transaction
from regluit.core.models import Campaign, Work, UnglueitError, Edition
from regluit.core import bookloader, models, search, goodreads, librarything
from regluit.core import isbn
from regluit.payment.parameters import PAYMENT_TYPE_AUTHORIZATION
from regluit.core import tasks
from celery.task.sets import TaskSet
from celery.task import chord
from time import sleep
from math import factorial
from urlparse import parse_qs, urlparse
class BookLoaderTests(TestCase):
def test_add_by_isbn(self):
# edition
edition = bookloader.add_by_isbn('0441012035')
self.assertEqual(edition.title, 'Neuromancer')
self.assertEqual(edition.publication_date, '2004')
self.assertEqual(edition.publisher, u'Ace Hardcover')
self.assertEqual(edition.isbn_10, '0441012035')
self.assertEqual(edition.isbn_13, '9780441012039')
self.assertEqual(edition.googlebooks_id, "2NyiPwAACAAJ")
# authors
self.assertEqual(edition.authors.all().count(), 1)
self.assertEqual(edition.authors.all()[0].name, 'William Gibson')
# work
self.assertTrue(edition.work)
# locale in language
edition = bookloader.add_by_isbn('9787500676911')
self.assertEqual(edition.work.language, 'zh')
def test_update_edition(self):
w = models.Work(title='silly title', language='xx')
w.save()
e = models.Edition(title=w.title,work=w)
e.save()
models.Identifier(type='isbn', value='9780226032030', work=w, edition=e).save()
bookloader.update_edition(e)
self.assertEqual(e.work.language, 'en')
self.assertEqual(e.title, 'Forbidden journeys')
def test_double_add(self):
bookloader.add_by_isbn('0441012035')
bookloader.add_by_isbn('0441012035')
self.assertEqual(models.Edition.objects.all().count(), 1)
self.assertEqual(models.Author.objects.all().count(), 1)
self.assertEqual(models.Work.objects.all().count(), 1)
def test_missing_isbn(self):
e = bookloader.add_by_isbn_from_google('0139391401')
self.assertEqual(e, None)
def test_thingisbn(self):
isbns = bookloader.thingisbn('0441012035')
self.assertTrue(len(isbns) > 20)
self.assertTrue('0441012035' in isbns)
self.assertTrue('3453313895' in isbns)
def test_add_related(self):
# add one edition
edition = bookloader.add_by_isbn('0441012035')
self.assertEqual(models.Edition.objects.count(), 1)
self.assertEqual(models.Work.objects.count(), 1)
lang=edition.work.language
# ask for related editions to be added using the work we just created
bookloader.add_related('0441012035')
self.assertTrue(models.Edition.objects.count() > 15)
self.assertEqual(models.Work.objects.filter(language=lang).count(), 1)
self.assertTrue(edition.work.editions.count() > 9)
def test_populate_edition(self):
edition = bookloader.add_by_googlebooks_id('c_dBPgAACAAJ')
edition = tasks.populate_edition.run(edition.isbn_13)
self.assertTrue(edition.work.editions.all().count() > 20)
self.assertTrue(edition.work.subjects.all().count() > 10)
self.assertTrue(edition.work.publication_date)
edition.publication_date = None
self.assertTrue(edition.work.publication_date)
def test_merge_works_mechanics(self):
"""Make sure then merge_works is still okay when we try to merge works with themselves and with deleted works"""
w1 = Work(title="Work 1")
w1.save()
w2 = Work(title="Work 2")
w2.save()
e1 = Edition(work=w1)
e1.save()
e2 = Edition(work=w2)
e2.save()
e2a = Edition(work=w2)
e2a.save()
self.assertTrue(e1)
self.assertTrue(e2)
self.assertTrue(e2a)
self.assertTrue(e1.work)
self.assertTrue(e2.work)
self.assertEqual(models.Work.objects.count(), 2)
w1_id = w1.id
w2_id = w2.id
# first try to merge work 1 into itself -- should not do anything
bookloader.merge_works(w1,w1)
self.assertEqual(models.Work.objects.count(), 2)
# merge the second work into the first
bookloader.merge_works(e1.work, e2.work)
self.assertEqual(models.Work.objects.count(),1)
self.assertEqual(models.WasWork.objects.count(),1)
# getting proper view?
anon_client = Client()
r = anon_client.get("/work/%s/" % w1_id)
self.assertEqual(r.status_code, 200)
r = anon_client.get("/work/%s/" % w2_id)
self.assertEqual(r.status_code, 200)
# try to do it twice -- nothing should happen
bookloader.merge_works(e1.work, e2a.work)
r = anon_client.get("/work/%s/" % w1_id)
self.assertEqual(r.status_code, 200)
r = anon_client.get("/work/%s/" % w2_id)
self.assertEqual(r.status_code, 200)
def test_merge_works(self):
# add two editions and see that there are two stub works
e1 = bookloader.add_by_isbn('0385722133')
e2 = bookloader.add_by_isbn('0385504187')
self.assertTrue(e1)
self.assertTrue(e2)
self.assertTrue(e1.work)
self.assertTrue(e2.work)
self.assertEqual(models.Work.objects.count(), 2)
# add the stub works to a wishlist
user = User.objects.create_user('test', 'test@example.com', 'testpass')
user.wishlist.add_work(e1.work, 'test')
user.wishlist.add_work(e2.work, 'test')
# create campaigns for the stub works
c1 = models.Campaign.objects.create(
name=e1.work.title,
work=e2.work,
description='Test Campaign 1',
deadline=datetime.now(),
target=D('1000.00'),
)
c2 = models.Campaign.objects.create(
name=e2.work.title,
work=e2.work,
description='Test Campaign 2',
deadline=datetime.now(),
target=D('1000.00'),
)
# comment on the works
site = Site.objects.all()[0]
wct = ContentType.objects.get_for_model(models.Work)
comment1 = Comment(
content_type=wct,
object_pk=e1.work.pk,
comment="test comment1",
user=user,
site=site
)
comment1.save()
comment2 = Comment(
content_type=wct,
object_pk=e2.work.pk,
comment="test comment2",
user=user,
site=site
)
comment2.save()
# now add related edition to make sure Works get merged
bookloader.add_related('0385722133')
self.assertEqual(models.Work.objects.count(), 1)
w3 = models.Edition.get_by_isbn('0385722133').work
# and that relevant Campaigns and Wishlists are updated
self.assertEqual(c1.work, c2.work)
self.assertEqual(user.wishlist.works.all().count(), 1)
self.assertEqual(Comment.objects.for_model(w3).count(), 2)
anon_client = Client()
r = anon_client.get("/work/%s/" % w3.pk)
self.assertEqual(r.status_code, 200)
r = anon_client.get("/work/%s/" % e2.work.pk)
self.assertEqual(r.status_code, 200)
def test_ebook(self):
edition = bookloader.add_by_oclc('1246014')
self.assertEqual(edition.ebooks.count(), 2)
#ebook_epub = edition.ebooks.all()[0]
ebook_epub = edition.ebooks.filter(format='epub')[0]
self.assertEqual(ebook_epub.format, 'epub')
#self.assertEqual(ebook_epub.url, 'http://books.google.com/books/download/The_Latin_language.epub?id=U3FXAAAAYAAJ&ie=ISO-8859-1&output=epub&source=gbs_api')
self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("id"), ['U3FXAAAAYAAJ'])
self.assertEqual(parse_qs(urlparse(ebook_epub.url).query).get("output"), ['epub'])
self.assertEqual(ebook_epub.provider, 'Google Books')
self.assertEqual(ebook_epub.set_provider(), 'Google Books')
ebook_pdf = edition.ebooks.filter(format='pdf')[0]
self.assertEqual(ebook_pdf.format, 'pdf')
#self.assertEqual(ebook_pdf.url, 'http://books.google.com/books/download/The_Latin_language.pdf?id=U3FXAAAAYAAJ&ie=ISO-8859-1&output=pdf&sig=ACfU3U2yLt3nmTncB8ozxOWUc4iHKUznCA&source=gbs_api')
self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("id"), ['U3FXAAAAYAAJ'])
self.assertEqual(parse_qs(urlparse(ebook_pdf.url).query).get("output"), ['pdf'])
self.assertEqual(ebook_pdf.provider, 'Google Books')
self.assertEqual(edition.public_domain, True)
w = edition.work
self.assertEqual(w.first_epub().url, ebook_epub.url)
self.assertEqual(w.first_pdf().url, ebook_pdf.url)
self.assertEqual(w.first_epub_url(), ebook_epub.url)
self.assertEqual(w.first_pdf_url(), ebook_pdf.url)
ebook_pdf.url='http://en.wikisource.org/wiki/Frankenstein'
self.assertEqual(ebook_pdf.set_provider(), 'Wikisource')
def test_add_no_ebook(self):
# this edition lacks an ebook, but we should still be able to load it
e = bookloader.add_by_isbn('0465019358')
self.assertTrue(e)
def test_one_language(self):
# english edition for cat's cradle should only pull in other
# english editions
work = bookloader.add_by_isbn('079530272X').work
self.assertEqual(work.language, 'en')
bookloader.add_related('079530272X')
for edition in work.editions.all():
self.assertEqual(edition.title.lower(), "cat's cradle")
def test_add_openlibrary(self):
work = bookloader.add_by_isbn('0441012035').work
bookloader.add_related('0441012035')
bookloader.add_openlibrary(work)
subjects = [s.name for s in work.subjects.all()]
self.assertTrue(len(subjects) > 10)
self.assertTrue('Science fiction' in subjects)
self.assertEqual(work.openlibrary_id, '/works/OL27258W')
self.assertEqual(work.goodreads_id, '14770')
self.assertEqual(work.librarything_id, '609')
def test_load_gutenberg_edition(self):
"""Let's try this out for Moby Dick"""
title = "Moby Dick"
ol_work_id = "/works/OL102749W"
gutenberg_etext_id = 2701
epub_url = "http://www.gutenberg.org/cache/epub/2701/pg2701.epub"
license = 'http://www.gutenberg.org/license'
lang = 'en'
format = 'epub'
publication_date = datetime(2001,7,1)
seed_isbn = '9780142000083' # http://www.amazon.com/Moby-Dick-Whale-Penguin-Classics-Deluxe/dp/0142000086
ebook = bookloader.load_gutenberg_edition(title, gutenberg_etext_id, ol_work_id, seed_isbn, epub_url, format, license, lang, publication_date)
self.assertEqual(ebook.url, epub_url)
class SearchTests(TestCase):
def test_basic_search(self):
results = search.gluejar_search('melville')
self.assertEqual(len(results), 10)
r = results[0]
self.assertTrue(r.has_key('title'))
self.assertTrue(r.has_key('author'))
self.assertTrue(r.has_key('description'))
self.assertTrue(r.has_key('cover_image_thumbnail'))
self.assertTrue(r.has_key('publisher'))
self.assertTrue(r.has_key('isbn_13'))
self.assertTrue(r.has_key('googlebooks_id'))
def test_pagination(self):
r1 = search.gluejar_search('melville', page=1)
r2 = search.gluejar_search('melville', page=2)
isbns1 = set([r['isbn_13'] for r in r1])
isbns2 = set([r['isbn_13'] for r in r2])
self.assertTrue(isbns1 != isbns2)
def test_googlebooks_search(self):
response = search.googlebooks_search('melville', '69.243.24.29', 1)
self.assertEqual(len(response['items']), 10)
class CampaignTests(TestCase):
def test_required_fields(self):
# a campaign must have a target, deadline and a work
c = Campaign()
self.assertRaises(IntegrityError, c.save)
c = Campaign(target=D('1000.00'))
self.assertRaises(IntegrityError, c.save)
c = Campaign(target=D('1000.00'), deadline=datetime(2012, 1, 1))
self.assertRaises(IntegrityError, c.save)
w = Work()
w.save()
c = Campaign(target=D('1000.00'), deadline=datetime(2012, 1, 1), work=w)
c.save()
def test_campaign_status(self):
w = Work()
w.save()
# INITIALIZED
c1 = Campaign(target=D('1000.00'),deadline=datetime(2012,1,1),work=w)
c1.save()
self.assertEqual(c1.status, 'INITIALIZED')
# ACTIVATED
c2 = Campaign(target=D('1000.00'),deadline=datetime(2012,1,1),work=w)
c2.save()
self.assertEqual(c2.status, 'INITIALIZED')
c2.activate()
self.assertEqual(c2.status, 'ACTIVE')
# SUSPENDED
c2.suspend(reason="for testing")
self.assertEqual(c2.status, 'SUSPENDED')
# RESUMING
c2.resume(reason="for testing")
#self.assertEqual(c2.suspended, None)
self.assertEqual(c2.status,'ACTIVE')
# should not let me suspend a campaign that hasn't been initialized
self.assertRaises(UnglueitError, c1.suspend, "for testing")
# UNSUCCESSFUL
c3 = Campaign(target=D('1000.00'),deadline=datetime.utcnow() - timedelta(days=1),work=w)
c3.save()
c3.activate()
self.assertTrue(c3.update_success())
self.assertEqual(c3.status, 'UNSUCCESSFUL')
# SUCCESSFUL
c4 = Campaign(target=D('1000.00'),deadline=datetime.utcnow() - timedelta(days=1),work=w)
c4.save()
c4.activate()
t = Transaction()
t.amount = D('1234.00')
t.type = PAYMENT_TYPE_AUTHORIZATION
t.status = 'ACTIVE'
t.approved = True
t.campaign = c4
t.save()
self.assertTrue(c4.update_success())
self.assertEqual(c4.status, 'SUCCESSFUL')
# WITHDRAWN
c5 = Campaign(target=D('1000.00'),deadline=datetime(2012,1,1),work=w)
c5.save()
c5.activate().withdraw('testing')
self.assertEqual(c5.status, 'WITHDRAWN')
class WishlistTest(TestCase):
def test_add_remove(self):
# add a work to a user's wishlist
user = User.objects.create_user('test', 'test@example.com', 'testpass')
edition = bookloader.add_by_isbn('0441012035')
work = edition.work
num_wishes=work.num_wishes
user.wishlist.add_work(work, 'test')
self.assertEqual(user.wishlist.works.count(), 1)
self.assertEqual(work.num_wishes, num_wishes+1)
user.wishlist.remove_work(work)
self.assertEqual(user.wishlist.works.count(), 0)
self.assertEqual(work.num_wishes, num_wishes)
class CeleryTaskTest(TestCase):
def test_single_fac(self):
n = 10
task = tasks.fac.delay(n)
result = task.get(timeout=10)
self.assertEqual(result,factorial(n))
def test_subtask(self):
n = 30
subtasks = [tasks.fac.subtask(args=(x,)) for x in range(n)]
job = TaskSet(tasks=subtasks)
result = job.apply_async()
while not result.ready():
sleep(0.2)
self.assertEqual(result.join(),[factorial(x) for x in range(n)])
class GoodreadsTest(TestCase):
def test_goodreads_shelves(self):
# test to see whether the core undeletable shelves are on the list
gr_uid = "767708" # for Raymond Yee
gc = goodreads.GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
shelves = gc.shelves_list(gr_uid)
shelf_names = [s['name'] for s in shelves['user_shelves']]
self.assertTrue('currently-reading' in shelf_names)
self.assertTrue('read' in shelf_names)
self.assertTrue('to-read' in shelf_names)
def test_review_list_unauth(self):
gr_uid = "767708" # for Raymond Yee
gc = goodreads.GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
reviews = gc.review_list_unauth(user_id=gr_uid, shelf='read')
# test to see whether there is a book field in each of the review
self.assertTrue(all([r.has_key("book") for r in reviews]))
class LibraryThingTest(TestCase):
def test_scrape_test_lib(self):
# account yujx : has one book: 0471925675
lt_username = 'yujx'
lt = librarything.LibraryThing(username=lt_username)
books = list(lt.parse_user_catalog(view_style=5))
self.assertEqual(len(books),1)
self.assertEqual(books[0]['isbn'], '0471925675')
self.assertEqual(books[0]['work_id'], '80826')
self.assertEqual(books[0]['book_id'], '79883733')
class ISBNTest(TestCase):
def test_ISBN(self):
milosz_10 = '006019667X'
milosz_13 = '9780060196677'
python_10 = '0-672-32978-6'
python_10_wrong = '0-672-32978-7'
python_13 = '978-0-672-32978-4'
isbn_python_10 = isbn.ISBN(python_10)
isbn_python_13 = isbn.ISBN(python_13)
# return None for invalid characters
self.assertEqual(None, isbn.ISBN("978-0-M72-32978-X").to_string('13'))
self.assertEqual(isbn.ISBN("978-0-M72-32978-X").valid, False)
# check that only ISBN 13 starting with 978 or 979 are accepted
self.assertEqual(None, isbn.ISBN("111-0-M72-32978-X").to_string())
# right type?
self.assertEqual(isbn_python_10.type, '10')
self.assertEqual(isbn_python_13.type, '13')
# valid?
self.assertEqual(isbn_python_10.valid, True)
self.assertEqual(isbn.ISBN(python_10_wrong).valid, False)
# do conversion -- first the outside methods
self.assertEqual(isbn.convert_10_to_13(isbn.strip(python_10)),isbn.strip(python_13))
self.assertEqual(isbn.convert_13_to_10(isbn.strip(python_13)),isbn.strip(python_10))
# check formatting
self.assertEqual(isbn.ISBN(python_13).to_string(type='13'), '9780672329784')
self.assertEqual(isbn.ISBN(python_13).to_string('13',True), '978-0-672-32978-4')
self.assertEqual(isbn.ISBN(python_13).to_string(type='10'), '0672329786')
self.assertEqual(isbn.ISBN(python_10).to_string(type='13'), '9780672329784')
self.assertEqual(isbn.ISBN(python_10).to_string(10,True), '0-672-32978-6')
# complain if one tries to get ISBN-10 for a 979 ISBN 13
# making up a 979 ISBN
isbn_979 = isbn.ISBN("979-1-234-56789-0").validate()
self.assertEqual(isbn_979.to_string('10'), None)
# check casting to string -- ISBN 13
self.assertEqual(str(isbn.ISBN(python_10)), '0672329786')
# test __eq__ and __ne__ and validate
self.assertTrue(isbn.ISBN(milosz_10) == isbn.ISBN(milosz_13))
self.assertTrue(isbn.ISBN(milosz_10) == milosz_13)
self.assertFalse(isbn.ISBN(milosz_10) == 'ddds')
self.assertFalse(isbn.ISBN(milosz_10) != milosz_10)
self.assertTrue(isbn.ISBN(python_10) != python_10_wrong)
self.assertEqual(isbn.ISBN(python_10_wrong).validate(), python_10)
self.assertEqual(isbn.ISBN(python_13).validate(), python_10)
# curious about set membership
self.assertEqual(len(set([isbn.ISBN(milosz_10), isbn.ISBN(milosz_13)])),2)
self.assertEqual(len(set([str(isbn.ISBN(milosz_10)), str(isbn.ISBN(milosz_13))])),2)
self.assertEqual(len(set([isbn.ISBN(milosz_10).to_string(), isbn.ISBN(milosz_13).to_string()])),1)