def test_view(self, mockpaginator, mockrepo, mocksolr_interface, mocksolr_iface): mocksolr = mocksolr_interface.return_value mocksolr_iface.return_value = mocksolr view_url = reverse('collection:view', kwargs={'pid': 'coll'}) mocksolr.query.return_value = mocksolr.query for method in ['query', 'sort_by', 'results_as', 'field_limit', 'facet_query']: getattr(mocksolr.query, method).return_value = mocksolr.query # set no solr results for last-modified query mocksolr.query.count.return_value = 0 # simulate 404 mockcoll = NonCallableMock() mockrepo.return_value.get_object.return_value = mockcoll # - doesn't exist mockcoll.exists = False response = self.client.get(view_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected status code %s but got %s for view collection when object doesn\'t exist' % \ (expected, got)) # - exists but is the wrong type mockcoll.exists = True mockcoll.has_requisite_content_models = False response = self.client.get(view_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected status code %s but got %s for view collection when object has wrong cmodels' % \ (expected, got)) # simulate valid fedora object mockcoll.has_requisite_content_models = True mockcoll.short_label = 'Yellowbacks' mockcoll.pid = 'coll:1' mockcoll.dc.content.description = 'Cheap 19thc paperbacks, often bound in yellow.' # simulate sunburnt's fluid interface # set up mock results for display on template solr_result = [ SolrVolume(**{'pid': 'vol:1', 'title': 'Asodecoan', 'creator': ['Atlanta-Southern Dental College.; Emory University Archives.']}), SolrVolume(**{'pid': 'vol:2', 'title': 'Sugar Crop of Lousiana', 'label': 'ocm123_V.2', 'date': ['1831']}), ] results = NonCallableMagicMock(spec=['__iter__', 'facet_counts']) results.__iter__.return_value = iter(solr_result) results.facet_counts.facet_queries = [] # - using a noncallable for the pagination result that is used in the template # because passing callables into django templates does weird things mockpage = NonCallableMock() mockpaginator.return_value.page.return_value = mockpage mockpage.object_list = results mockpage.has_other_pages = False mockpage.paginator.count = 2 mockpage.paginator.page_range = [1] mockpaginator.return_value.count = 2 mockpaginator.return_value.page_range = [1] response = self.client.get(view_url) # inspect solr query mocksolr.query.assert_called_with(content_model=Volume.VOLUME_CMODEL_PATTERN, collection_id=mockcoll.pid) mocksolr.query.sort_by.assert_any_call('title_exact') mocksolr.query.sort_by.assert_any_call('label') mocksolr.query.results_as.assert_called_with(SolrVolume) # inspect html result self.assertContains(response, mockcoll.short_label, msg_prefix='collection short label should be displayed') self.assertContains(response, '<title>%s Collection | Readux</title>' % mockcoll.short_label, html=True, msg_prefix='collection label should be included in html title') self.assertContains(response, mockcoll.dc.content.description, msg_prefix='collection dc:description should be displayed') self.assertContains(response, '2 volumes in this collection', msg_prefix='total count of volumes in the collection should be displayed') self.assertContains(response, solr_result[0]['title'], msg_prefix='volume title %(title)s should be displayed' % solr_result[0]) self.assertContains(response, solr_result[1]['title'], msg_prefix='volume title %(title)s should be displayed' % solr_result[1]) self.assertContains(response, '[V.2]', msg_prefix='volume number should be displayed when present') # date/creator self.assertContains(response, '(%s)' % solr_result[1]['date'][0], msg_prefix='volume date should be displayed when present') self.assertContains(response, '%s' % solr_result[0]['creator'][0], msg_prefix='volume author/creator should be displayed when present') # check that unapi / zotero harvest is enabled self.assertContains(response, '<link rel="unapi-server" type="application/xml" title="unAPI" href="%s" />' % \ reverse('books:unapi'), html=True, msg_prefix='link to unAPI server URL should be specified in header') self.assertContains(response, '<abbr class="unapi-id" title="%s"></abbr>' % solr_result[0]['pid'], msg_prefix='unapi item id for %s should be included to allow zotero harvest' % \ solr_result[0]['pid']) self.assertContains(response, '<abbr class="unapi-id" title="%s"></abbr>' % solr_result[1]['pid'], msg_prefix='unapi item id for %s should be included to allow zotero harvest' % \ solr_result[1]['pid']) self.assertFalse(response.has_header('last-modified'), 'last modified header should not be set when no results were found in solr') # last-modified mocksolr.query.count.return_value = 1 # set a timestamp to be returned for last-modified conditional processing mocksolr.query.return_value.__getitem__.return_value = {'timestamp': datetime.now()} response = self.client.get(view_url) self.assertTrue(response.has_header('last-modified'), 'last modified header should be set') ## annotation totals # empty annotation total in context for anonymous user self.assertEqual({}, response.context['annotated_volumes']) # check that annotation total is retrieved for ONLY logged in users with patch('readux.collection.views.Volume') as mockvolclass: self.client.get(view_url) mockvolclass.volume_annotation_count.assert_not_called() User = get_user_model() credentials = {'username': '******', 'password': '******'} testuser = User.objects.create_user(**credentials) self.client.login(**credentials) self.client.get(view_url) mockvolclass.volume_annotation_count.assert_called_with(testuser)
def test_volume(self, mockrepo): mockobj = NonCallableMock() mockobj.pid = 'vol:1' mockobj.title = 'Lecoq, the detective' mockobj.volume = 'V.1' mockobj.date = ['1801'] mockobj.creator = ['Gaboriau, Emile'] mockobj.book.dc.content.description_list = [ 'Translation of: Monsieur Lecoq.', 'Victorian yellowbacks + paperbacks, 1849-1905' ] mockobj.book.dc.content.publisher = 'London : Vizetelly' mockobj.book.volume_set = [mockobj, NonCallableMock(pid='vol:2')] mockobj.pdf_size = 1024 mockobj.has_pages = False mockobj.is_a_volume = True mockrepo.return_value.get_object.return_value = mockobj # to support for last modified conditional mockobj.ocr.created = datetime.now() vol_url = reverse('books:volume', kwargs={'pid': mockobj.pid}) response = self.client.get(vol_url) self.assertContains(response, mockobj.title, msg_prefix='response should include title') self.assertContains(response, mockobj.volume, msg_prefix='response should include volume label') self.assertContains(response, mockobj.date[0], msg_prefix='response should include date') self.assertContains(response, mockobj.creator[0], msg_prefix='response should include creator') for desc in mockobj.book.dc.content.description_list: self.assertContains(response, desc, msg_prefix='response should include dc:description') self.assertContains(response, mockobj.book.dc.content.publisher, msg_prefix='response should include publisher') self.assertContains(response, reverse('books:pdf', kwargs={'pid': mockobj.pid}), msg_prefix='response should include link to pdf') # related volumes self.assertContains(response, 'Related volumes', msg_prefix='response should include related volumes when present') self.assertContains(response, reverse('books:volume', kwargs={'pid': mockobj.book.volume_set[0].pid}), msg_prefix='response should link to related volumes') # pdf size self.assertContains(response, filesizeformat(mockobj.pdf_size), msg_prefix='PDF size should be displayed in human-readable format') # no pages loaded, should not include volume search or read online self.assertNotContains(response, 'Read online', msg_prefix='volume without pages loaded should not display read online option') # NOTE: href needed to differentiate from cover url, which starts the same self.assertNotContains(response, 'href="%s"' % reverse('books:pages', kwargs={'pid': mockobj.pid}), msg_prefix='volume without pages loaded should not have link to read online') self.assertNotContains(response, '<form id="volume-search" ', msg_prefix='volume without pages loaded should not have volume search') # annotation total passed to context self.assert_('annotated_volumes' not in response.context, 'annotation count should not be set for volumes without pages') # simulate volume with pages loaded mockobj.has_pages = True # to test annotation count mockobj.get_absolute_url.return_value = '/books/vol:1/' mockobj.annotation_count.return_value = 5 response = self.client.get(vol_url) # *should* include volume search and read online self.assertContains(response, 'Read online', msg_prefix='volume with pages loaded should display read online option') self.assertContains(response, reverse('books:pages', kwargs={'pid': mockobj.pid}), msg_prefix='volume with pages loaded should have link to read online') self.assertContains(response, '<form id="volume-search" ', msg_prefix='volume without pages loaded should have volume search') # annotation total passed to context self.assertEqual({mockobj.get_absolute_url(): 5}, response.context['annotated_volumes'], 'annotation count should be set for volumes with pages') mockobj.annotation_count.return_value = 0 response = self.client.get(vol_url) self.assert_('annotated_volumes' not in response.context, 'annotation count should not be set in context when it is zero') # non-existent should 404 mockobj.exists = False response = self.client.get(vol_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected %s for %s when object does not exist, got %s' % \ (expected, vol_url, got)) # exists but isn't a volume - should also 404 mockobj.exists = True mockobj.is_a_volume = False response = self.client.get(vol_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected %s for %s when object is not a volume, got %s' % \ (expected, vol_url, got))
def test_volume(self, mockrepo): mockobj = NonCallableMock() mockobj.pid = 'vol:1' mockobj.title = 'Lecoq, the detective' mockobj.volume = 'V.1' mockobj.date = ['1801'] mockobj.creator = ['Gaboriau, Emile'] mockobj.book.dc.content.description_list = [ 'Translation of: Monsieur Lecoq.', 'Victorian yellowbacks + paperbacks, 1849-1905' ] mockobj.book.dc.content.publisher = 'London : Vizetelly' mockobj.book.volume_set = [mockobj, NonCallableMock(pid='vol:2')] mockobj.pdf_size = 1024 mockobj.has_pages = False mockobj.is_a_volume = True mockrepo.return_value.get_object.return_value = mockobj # to support for last modified conditional mockobj.ocr.created = datetime.now() vol_url = reverse('books:volume', kwargs={'pid': mockobj.pid}) response = self.client.get(vol_url) self.assertContains(response, mockobj.title, msg_prefix='response should include title') self.assertContains(response, mockobj.volume, msg_prefix='response should include volume label') self.assertContains(response, mockobj.date[0], msg_prefix='response should include date') self.assertContains(response, mockobj.creator[0], msg_prefix='response should include creator') for desc in mockobj.book.dc.content.description_list: self.assertContains( response, desc, msg_prefix='response should include dc:description') self.assertContains(response, mockobj.book.dc.content.publisher, msg_prefix='response should include publisher') self.assertContains(response, reverse('books:pdf', kwargs={'pid': mockobj.pid}), msg_prefix='response should include link to pdf') # related volumes self.assertContains( response, 'Related volumes', msg_prefix='response should include related volumes when present') self.assertContains( response, reverse('books:volume', kwargs={'pid': mockobj.book.volume_set[0].pid}), msg_prefix='response should link to related volumes') # pdf size self.assertContains( response, filesizeformat(mockobj.pdf_size), msg_prefix='PDF size should be displayed in human-readable format') # no pages loaded, should not include volume search or read online self.assertNotContains( response, 'Read online', msg_prefix= 'volume without pages loaded should not display read online option' ) # NOTE: href needed to differentiate from cover url, which starts the same self.assertNotContains( response, 'href="%s"' % reverse('books:pages', kwargs={'pid': mockobj.pid}), msg_prefix= 'volume without pages loaded should not have link to read online') self.assertNotContains( response, '<form id="volume-search" ', msg_prefix= 'volume without pages loaded should not have volume search') # annotation total passed to context self.assert_( 'annotated_volumes' not in response.context, 'annotation count should not be set for volumes without pages') # simulate volume with pages loaded mockobj.has_pages = True # to test annotation count mockobj.get_absolute_url.return_value = '/books/vol:1/' mockobj.annotation_count.return_value = 5 response = self.client.get(vol_url) # *should* include volume search and read online self.assertContains( response, 'Read online', msg_prefix= 'volume with pages loaded should display read online option') self.assertContains( response, reverse('books:pages', kwargs={'pid': mockobj.pid}), msg_prefix= 'volume with pages loaded should have link to read online') self.assertContains( response, '<form id="volume-search" ', msg_prefix='volume without pages loaded should have volume search') # annotation total passed to context self.assertEqual( {mockobj.get_absolute_url(): 5}, response.context['annotated_volumes'], 'annotation count should be set for volumes with pages') mockobj.annotation_count.return_value = 0 response = self.client.get(vol_url) self.assert_( 'annotated_volumes' not in response.context, 'annotation count should not be set in context when it is zero') # non-existent should 404 mockobj.exists = False response = self.client.get(vol_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected %s for %s when object does not exist, got %s' % \ (expected, vol_url, got)) # exists but isn't a volume - should also 404 mockobj.exists = True mockobj.is_a_volume = False response = self.client.get(vol_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected %s for %s when object is not a volume, got %s' % \ (expected, vol_url, got))
def test_view(self, mockpaginator, mockrepo, mocksolr_interface, mocksolr_iface): mocksolr = mocksolr_interface.return_value mocksolr_iface.return_value = mocksolr view_url = reverse('collection:view', kwargs={'pid': 'coll'}) mocksolr.query.return_value = mocksolr.query for method in [ 'query', 'sort_by', 'results_as', 'field_limit', 'facet_query' ]: getattr(mocksolr.query, method).return_value = mocksolr.query # set no solr results for last-modified query mocksolr.query.count.return_value = 0 # simulate 404 mockcoll = NonCallableMock() mockrepo.return_value.get_object.return_value = mockcoll # - doesn't exist mockcoll.exists = False response = self.client.get(view_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected status code %s but got %s for view collection when object doesn\'t exist' % \ (expected, got)) # - exists but is the wrong type mockcoll.exists = True mockcoll.has_requisite_content_models = False response = self.client.get(view_url) expected, got = 404, response.status_code self.assertEqual(expected, got, 'expected status code %s but got %s for view collection when object has wrong cmodels' % \ (expected, got)) # simulate valid fedora object mockcoll.has_requisite_content_models = True mockcoll.short_label = 'Yellowbacks' mockcoll.pid = 'coll:1' mockcoll.dc.content.description = 'Cheap 19thc paperbacks, often bound in yellow.' # simulate sunburnt's fluid interface # set up mock results for display on template solr_result = [ SolrVolume( **{ 'pid': 'vol:1', 'title': 'Asodecoan', 'creator': [ 'Atlanta-Southern Dental College.; Emory University Archives.' ] }), SolrVolume( **{ 'pid': 'vol:2', 'title': 'Sugar Crop of Lousiana', 'label': 'ocm123_V.2', 'date': ['1831'] }), ] results = NonCallableMagicMock(spec=['__iter__', 'facet_counts']) results.__iter__.return_value = iter(solr_result) results.facet_counts.facet_queries = [] # - using a noncallable for the pagination result that is used in the template # because passing callables into django templates does weird things mockpage = NonCallableMock() mockpaginator.return_value.page.return_value = mockpage mockpage.object_list = results mockpage.has_other_pages = False mockpage.paginator.count = 2 mockpage.paginator.page_range = [1] mockpaginator.return_value.count = 2 mockpaginator.return_value.page_range = [1] response = self.client.get(view_url) # inspect solr query mocksolr.query.assert_called_with( content_model=Volume.VOLUME_CMODEL_PATTERN, collection_id=mockcoll.pid) mocksolr.query.sort_by.assert_any_call('title_exact') mocksolr.query.sort_by.assert_any_call('label') mocksolr.query.results_as.assert_called_with(SolrVolume) # inspect html result self.assertContains( response, mockcoll.short_label, msg_prefix='collection short label should be displayed') self.assertContains( response, '<title>%s Collection | Readux</title>' % mockcoll.short_label, html=True, msg_prefix='collection label should be included in html title') self.assertContains( response, mockcoll.dc.content.description, msg_prefix='collection dc:description should be displayed') self.assertContains( response, '2 volumes in this collection', msg_prefix= 'total count of volumes in the collection should be displayed') self.assertContains( response, solr_result[0]['title'], msg_prefix='volume title %(title)s should be displayed' % solr_result[0]) self.assertContains( response, solr_result[1]['title'], msg_prefix='volume title %(title)s should be displayed' % solr_result[1]) self.assertContains( response, '[V.2]', msg_prefix='volume number should be displayed when present') # date/creator self.assertContains( response, '(%s)' % solr_result[1]['date'][0], msg_prefix='volume date should be displayed when present') self.assertContains( response, '%s' % solr_result[0]['creator'][0], msg_prefix='volume author/creator should be displayed when present' ) # check that unapi / zotero harvest is enabled self.assertContains(response, '<link rel="unapi-server" type="application/xml" title="unAPI" href="%s" />' % \ reverse('books:unapi'), html=True, msg_prefix='link to unAPI server URL should be specified in header') self.assertContains(response, '<abbr class="unapi-id" title="%s"></abbr>' % solr_result[0]['pid'], msg_prefix='unapi item id for %s should be included to allow zotero harvest' % \ solr_result[0]['pid']) self.assertContains(response, '<abbr class="unapi-id" title="%s"></abbr>' % solr_result[1]['pid'], msg_prefix='unapi item id for %s should be included to allow zotero harvest' % \ solr_result[1]['pid']) self.assertFalse( response.has_header('last-modified'), 'last modified header should not be set when no results were found in solr' ) # last-modified mocksolr.query.count.return_value = 1 # set a timestamp to be returned for last-modified conditional processing mocksolr.query.return_value.__getitem__.return_value = { 'timestamp': datetime.now() } response = self.client.get(view_url) self.assertTrue(response.has_header('last-modified'), 'last modified header should be set') ## annotation totals # empty annotation total in context for anonymous user self.assertEqual({}, response.context['annotated_volumes']) # check that annotation total is retrieved for ONLY logged in users with patch('readux.collection.views.Volume') as mockvolclass: self.client.get(view_url) mockvolclass.volume_annotation_count.assert_not_called() User = get_user_model() credentials = {'username': '******', 'password': '******'} testuser = User.objects.create_user(**credentials) self.client.login(**credentials) self.client.get(view_url) mockvolclass.volume_annotation_count.assert_called_with(testuser)