Beispiel #1
0
    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)
Beispiel #2
0
    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))
Beispiel #3
0
    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))
Beispiel #4
0
    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)