Update Celery to 4.3
[wolnelektury.git] / src / catalogue / tests / test_book_import.py
1 # -*- coding: utf-8 -*-
2 # This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
3 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
4 #
5 from django.core.files.base import ContentFile
6 from catalogue.test_utils import *
7 from catalogue import models
8 from librarian import WLURI
9
10 from os import path, makedirs
11
12
13 class BookImportLogicTests(WLTestCase):
14
15     def setUp(self):
16         WLTestCase.setUp(self)
17         self.book_info = BookInfoStub(
18             url=WLURI.from_slug(u"default-book"),
19             about=u"http://wolnelektury.pl/example/URI/default_book",
20             title=u"Default Book",
21             author=PersonStub(("Jim",), "Lazy"),
22             kind="X-Kind",
23             genre="X-Genre",
24             epoch="X-Epoch",
25             language=u"pol",
26         )
27
28         self.expected_tags = [
29            ('author', 'jim-lazy'),
30            ('genre', 'x-genre'),
31            ('epoch', 'x-epoch'),
32            ('kind', 'x-kind'),
33         ]
34         self.expected_tags.sort()
35
36     def test_empty_book(self):
37         book_text = "<utwor />"
38         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
39         book.refresh_from_db()
40
41         self.assertEqual(book.title, "Default Book")
42         self.assertEqual(book.slug, "default-book")
43         self.assert_(book.parent is None)
44         self.assertFalse(book.has_html_file())
45
46         # no fragments generated
47         self.assertEqual(book.fragments.count(), 0)
48
49         # TODO: this should be filled out probably...
50         self.assertEqual(book.wiki_link, '')
51         self.assertEqual(book.gazeta_link, '')
52         self.assertEqual(book.description, '')
53
54         tags = [(tag.category, tag.slug) for tag in book.tags]
55         tags.sort()
56
57         self.assertEqual(tags, self.expected_tags)
58
59     def test_not_quite_empty_book(self):
60         """ Not empty, but without any real text.
61
62         Should work like any other non-empty book.
63         """
64
65         book_text = """<utwor>
66         <liryka_l>
67             <nazwa_utworu>Nic</nazwa_utworu>
68         </liryka_l></utwor>
69         """
70
71         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
72         book.refresh_from_db()
73         self.assertTrue(book.has_html_file())
74
75     def test_book_with_fragment(self):
76         book_text = """<utwor>
77         <opowiadanie>
78             <akap><begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" /></akap>
79         </opowiadanie></utwor>
80         """
81
82         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
83         book.refresh_from_db()
84         self.assertTrue(book.has_html_file())
85
86         self.assertEqual(book.fragments.count(), 1)
87         self.assertEqual(book.fragments.all()[0].text, u'<p class="paragraph">Ala ma kota</p>\n')
88
89         self.assert_(('theme', 'love') in [(tag.category, tag.slug) for tag in book.fragments.all()[0].tags])
90
91     def test_book_with_empty_theme(self):
92         """ empty themes should be ignored """
93
94         book_text = """<utwor>
95         <opowiadanie>
96             <akap><begin id="m01" /><motyw id="m01"> , Love , , </motyw>Ala ma kota<end id="m01" /></akap>
97         </opowiadanie></utwor>
98         """
99
100         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
101         self.assert_([('theme', 'love')],
102                      book.fragments.all()[0].tags.filter(category='theme').values_list('category', 'slug'))
103
104     def test_book_with_no_theme(self):
105         """ fragments with no themes shouldn't be created at all """
106
107         book_text = """<utwor>
108         <opowiadanie>
109             <akap><begin id="m01" /><motyw id="m01"></motyw>Ala ma kota<end id="m01" /></akap>
110         </opowiadanie></utwor>
111         """
112
113         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
114         self.assertEqual(book.fragments.count(), 0)
115         self.assertEqual(book.tags.filter(category='theme').count(), 0)
116
117     def test_book_with_invalid_slug(self):
118         """ Book with invalid characters in slug shouldn't be imported """
119         self.book_info.url = WLURI.from_slug(u"default_book")
120         book_text = "<utwor />"
121         with self.assertRaises(ValueError):
122             models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
123
124     def test_book_replace_title(self):
125         book_text = """<utwor />"""
126         models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
127         self.book_info.title = u"Extraordinary"
128         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info, overwrite=True)
129
130         tags = [(tag.category, tag.slug) for tag in book.tags]
131         tags.sort()
132
133         self.assertEqual(tags, self.expected_tags)
134
135     def test_book_replace_author(self):
136         book_text = """<utwor />"""
137         models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
138         self.book_info.author = PersonStub(("Hans", "Christian"), "Andersen")
139         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info, overwrite=True)
140
141         tags = [(tag.category, tag.slug) for tag in book.tags]
142         tags.sort()
143
144         self.expected_tags.remove(('author', 'jim-lazy'))
145         self.expected_tags.append(('author', 'hans-christian-andersen'))
146         self.expected_tags.sort()
147
148         self.assertEqual(tags, self.expected_tags)
149
150         # the old tag shouldn't disappear
151         models.Tag.objects.get(slug="jim-lazy", category="author")
152
153     def test_book_remove_fragment(self):
154         book_text = """<utwor>
155         <opowiadanie>
156             <akap>
157                 <begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" />
158                 <begin id="m02" /><motyw id="m02">Hatred</motyw>To kot Ali<end id="m02" />
159             </akap>
160         </opowiadanie></utwor>
161         """
162         book_text_after = """<utwor>
163         <opowiadanie>
164             <akap>
165                 <begin id="m01" /><motyw id="m01">Love</motyw>Ala ma kota<end id="m01" />
166                 To kot Ali
167             </akap>
168         </opowiadanie></utwor>
169         """
170
171         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
172         self.assertEqual(book.fragments.count(), 2)
173         book = models.Book.from_text_and_meta(ContentFile(book_text_after), self.book_info, overwrite=True)
174         self.assertEqual(book.fragments.count(), 1)
175
176     def test_multiple_tags(self):
177         book_text = """<utwor />"""
178         self.book_info.authors = self.book_info.author, PersonStub(("Joe",), "Dilligent"),
179         self.book_info.kinds = self.book_info.kind, 'Y-Kind',
180         self.book_info.genres = self.book_info.genre, 'Y-Genre',
181         self.book_info.epochs = self.book_info.epoch, 'Y-Epoch',
182
183         self.expected_tags.extend([
184            ('author', 'joe-dilligent'),
185            ('genre', 'y-genre'),
186            ('epoch', 'y-epoch'),
187            ('kind', 'y-kind'),
188         ])
189         self.expected_tags.sort()
190
191         book = models.Book.from_text_and_meta(ContentFile(book_text), self.book_info)
192         tags = [(tag.category, tag.slug) for tag in book.tags]
193         tags.sort()
194
195         self.assertEqual(tags, self.expected_tags)
196
197
198 class ChildImportTests(WLTestCase):
199
200     def setUp(self):
201         WLTestCase.setUp(self)
202         self.child_info = BookInfoStub(
203             genre='X-Genre',
204             epoch='X-Epoch',
205             kind='X-Kind',
206             author=PersonStub(("Joe",), "Doe"),
207             **info_args("Child")
208         )
209
210         self.parent_info = BookInfoStub(
211             genre='X-Genre',
212             epoch='X-Epoch',
213             kind='X-Kind',
214             author=PersonStub(("Jim",), "Lazy"),
215             parts=[self.child_info.url],
216             **info_args("Parent")
217         )
218
219     def test_child(self):
220         text = """<utwor />"""
221         child = models.Book.from_text_and_meta(ContentFile(text), self.child_info)
222         parent = models.Book.from_text_and_meta(ContentFile(text), self.parent_info)
223         author = parent.tags.get(category='author')
224         books = self.client.get(author.get_absolute_url()).context['object_list']
225         self.assertEqual(len(books), 1, "Only parent book should be visible on author's page")
226
227     def test_child_replace(self):
228         parent_text = """<utwor />"""
229         child_text = """<utwor>
230         <opowiadanie>
231             <akap><begin id="m01" /><motyw id="m01">Pies</motyw>Ala ma kota<end id="m01" /></akap>
232         </opowiadanie></utwor>
233         """
234         child = models.Book.from_text_and_meta(ContentFile(child_text), self.child_info)
235         parent = models.Book.from_text_and_meta(ContentFile(parent_text), self.parent_info)
236         child_text = """<utwor>
237         <opowiadanie>
238             <akap><begin id="m01" /><motyw id="m01">Kot</motyw>Ala ma kota<end id="m01" /></akap>
239         </opowiadanie></utwor>
240         """
241         child = models.Book.from_text_and_meta(ContentFile(child_text), self.child_info, overwrite=True)
242         themes = parent.related_themes()
243         self.assertEqual(['Kot'], [tag.name for tag in themes], 'wrong related theme list')
244
245
246 class TreeImportTest(WLTestCase):
247     def setUp(self):
248         WLTestCase.setUp(self)
249         self.child_info = BookInfoStub(
250             genre='X-Genre',
251             epoch='X-Epoch',
252             kind='X-Kind',
253             author=PersonStub(("Joe",), "Doe"),
254             **info_args("Child")
255         )
256         self.CHILD_TEXT = """<utwor>
257         <opowiadanie>
258             <akap><begin id="m01" /><motyw id="m01">Pies</motyw>
259                 Ala ma kota<end id="m01" /></akap>
260         </opowiadanie></utwor>
261         """
262         self.child = models.Book.from_text_and_meta(
263             ContentFile(self.CHILD_TEXT), self.child_info)
264
265         self.book_info = BookInfoStub(
266             genre='X-Genre',
267             epoch='X-Epoch',
268             kind='X-Kind',
269             author=PersonStub(("Joe",), "Doe"),
270             parts=[self.child_info.url],
271             **info_args("Book")
272         )
273         self.BOOK_TEXT = """<utwor />"""
274         self.book = models.Book.from_text_and_meta(
275             ContentFile(self.BOOK_TEXT), self.book_info)
276
277         self.parent_info = BookInfoStub(
278             genre='X-Genre',
279             epoch='X-Epoch',
280             kind='X-Kind',
281             author=PersonStub(("Jim",), "Lazy"),
282             parts=[self.book_info.url],
283             **info_args("Parent")
284         )
285         self.PARENT_TEXT = """<utwor />"""
286         self.parent = models.Book.from_text_and_meta(
287             ContentFile(self.PARENT_TEXT), self.parent_info)
288
289     def test_ok(self):
290         self.assertEqual(
291                 list(self.client.get('/katalog/gatunek/x-genre/').context['object_list']),
292                 [self.parent],
293                 u"There should be only parent on common tag page."
294             )
295         # pies = models.Tag.objects.get(slug='pies')
296         themes = self.parent.related_themes()
297         self.assertEqual(len(themes), 1, u"There should be child theme in parent theme counter.")
298         # TODO: book_count is deprecated, update here.
299         # epoch = models.Tag.objects.get(slug='x-epoch')
300         # self.assertEqual(epoch.book_count, 1, u"There should be only parent in common tag's counter.")
301
302     def test_child_republish(self):
303         child_text = """<utwor>
304         <opowiadanie>
305             <akap><begin id="m01" /><motyw id="m01">Pies, Kot</motyw>
306                 Ala ma kota<end id="m01" /></akap>
307         </opowiadanie></utwor>
308         """
309         models.Book.from_text_and_meta(
310             ContentFile(child_text), self.child_info, overwrite=True)
311         self.assertEqual(
312                 list(self.client.get('/katalog/gatunek/x-genre/').context['object_list']),
313                 [self.parent],
314                 u"There should only be parent on common tag page."
315             )
316         # pies = models.Tag.objects.get(slug='pies')
317         # kot = models.Tag.objects.get(slug='kot')
318         self.assertEqual(len(self.parent.related_themes()), 2,
319                          u"There should be child themes in parent theme counter.")
320         # TODO: book_count is deprecated, update here.
321         # epoch = models.Tag.objects.get(slug='x-epoch')
322         # self.assertEqual(epoch.book_count, 1, u"There should only be parent in common tag's counter.")
323
324     def test_book_change_child(self):
325         second_child_info = BookInfoStub(
326             genre='X-Genre',
327             epoch='X-Epoch',
328             kind='Other-Kind',
329             author=PersonStub(("Joe",), "Doe"),
330             **info_args("Second Child")
331         )
332         second_child_text = """<utwor>
333         <opowiadanie>
334             <akap><begin id="m01" /><motyw id="m01">Kot</motyw>
335                 Ala ma kota<end id="m01" /></akap>
336         </opowiadanie></utwor>
337         """
338         # Import a second child.
339         second_child = models.Book.from_text_and_meta(
340             ContentFile(second_child_text), second_child_info)
341         # The book has only this new child now.
342         self.book_info.parts = [second_child_info.url]
343         self.book = models.Book.from_text_and_meta(
344             ContentFile(self.BOOK_TEXT), self.book_info, overwrite=True)
345
346         self.assertEqual(
347             set(self.client.get('/katalog/gatunek/x-genre/').context['object_list']),
348             {self.parent, self.child},
349             u"There should be parent and old child on common tag page."
350         )
351         # kot = models.Tag.objects.get(slug='kot')
352         self.assertEqual(len(self.parent.related_themes()), 1,
353                          u"There should only be new child themes in parent theme counter.")
354         # # book_count deprecated, update test.
355         # epoch = models.Tag.objects.get(slug='x-epoch')
356         # self.assertEqual(epoch.book_count, 2,
357         #                  u"There should be parent and old child in common tag's counter.")
358         self.assertEqual(
359             list(self.client.get('/katalog/lektura/parent/motyw/kot/').context['fragments']),
360             [second_child.fragments.all()[0]],
361             u"There should be new child's fragments on parent's theme page."
362         )
363         self.assertEqual(
364             list(self.client.get('/katalog/lektura/parent/motyw/pies/').context['fragments']),
365             [],
366             u"There should be no old child's fragments on parent's theme page."
367         )
368
369
370 class MultilingualBookImportTest(WLTestCase):
371     def setUp(self):
372         WLTestCase.setUp(self)
373         common_uri = WLURI.from_slug('common-slug')
374
375         self.pol_info = BookInfoStub(
376             genre='X-Genre',
377             epoch='X-Epoch',
378             kind='X-Kind',
379             author=PersonStub(("Joe",), "Doe"),
380             variant_of=common_uri,
381             **info_args(u"Książka")
382         )
383
384         self.eng_info = BookInfoStub(
385             genre='X-Genre',
386             epoch='X-Epoch',
387             kind='X-Kind',
388             author=PersonStub(("Joe",), "Doe"),
389             variant_of=common_uri,
390             **info_args("A book", "eng")
391         )
392
393     def test_multilingual_import(self):
394         book_text = """<utwor><opowiadanie><akap>A</akap></opowiadanie></utwor>"""
395
396         models.Book.from_text_and_meta(ContentFile(book_text), self.pol_info)
397         models.Book.from_text_and_meta(ContentFile(book_text), self.eng_info)
398
399         self.assertEqual(
400             set([b.language for b in models.Book.objects.all()]),
401             {'pol', 'eng'},
402             'Books imported in wrong languages.'
403         )
404
405
406 class BookImportGenerateTest(WLTestCase):
407     def setUp(self):
408         WLTestCase.setUp(self)
409         xml = path.join(path.dirname(__file__), 'files/fraszka-do-anusie.xml')
410         self.book = models.Book.from_xml_file(xml)
411
412     def test_gen_pdf(self):
413         self.book.pdf_file.build()
414         book = models.Book.objects.get(pk=self.book.pk)
415         self.assertTrue(path.exists(book.pdf_file.path))
416
417     def test_gen_pdf_parent(self):
418         """This book contains a child."""
419         xml = path.join(path.dirname(__file__), "files/fraszki.xml")
420         parent = models.Book.from_xml_file(xml)
421         parent.pdf_file.build()
422         parent = models.Book.objects.get(pk=parent.pk)
423         self.assertTrue(path.exists(parent.pdf_file.path))
424
425     def test_custom_pdf(self):
426         from catalogue.tasks import build_custom_pdf
427         out = 'test-custom.pdf'
428         absoulute_path = path.join(settings.MEDIA_ROOT, out)
429
430         if not path.exists(path.dirname(absoulute_path)):
431             makedirs(path.dirname(absoulute_path))
432
433         build_custom_pdf(self.book.id, customizations=['nofootnotes', '13pt', 'a4paper'], file_name=out)
434         self.assertTrue(path.exists(absoulute_path))