def test_performance(self): """Count the number of queries required to fetch the centroids.""" # Make a GeometryStore object without points/lines/polygons/centroid # This should not appear in list unlocated = GeometryStore() unlocated.save() # Single point store which doesn't have an associcated project # This should not appear in list random_point = GeometryStore() random_point.save() point = PointGeometry(geom=Point(20, 30)) point.save() random_point.points.add(point) # Create 9 more (for a total of 10) random point projects for the map for i in range(9): geo = GeometryStore() geo.save() point = PointGeometry(geom=Point(20, 30)) point.save() geo.points.add(point) project = ProjectFactory(published=True) project.geo = geo project.save() with self.settings(PUBLISH_FILTER_ENABLED=True): self.client.logout() with self.assertNumQueries(3): # All response data should be fetched in a single query response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 10)
def test_project_totals(self): """Project totals should be in the homepage context.""" road = InfrastructureTypeFactory(name='Road', slug='road') rail = InfrastructureTypeFactory(name='Railroad', slug='rail') # Create 3 road projects, 2 of which are published ProjectFactory(infrastructure_type=road, published=True) ProjectFactory(infrastructure_type=road, published=True) ProjectFactory(infrastructure_type=road, published=False) # Create 2 rail projects, 1 of which is published ProjectFactory(infrastructure_type=rail, published=True) ProjectFactory(infrastructure_type=rail, published=False) # Totals should be in the response response = self.client.get(self.url) self.assertEqual(response.status_code, 200) expected = { 'road': { 'id': road.pk, 'count': 2, 'label': 'Road', }, 'rail': { 'id': rail.pk, 'count': 1, 'label': 'Railroad', } } self.assertEqual(response.context['db_totals'], expected)
def setUp(self): self.geom_with_published_project = GeometryStore() self.geom_with_published_project.save() point = PointGeometry(geom=Point(20, 30)) point.save() self.geom_with_published_project.points.add(point) self.published_project = ProjectFactory( published=True, countries=[CountryFactory(), CountryFactory()], total_cost=1200000) self.published_project.geo = self.geom_with_published_project self.published_project.save() self.geom_with_unpublished_project = GeometryStore() self.geom_with_unpublished_project.save() point = PointGeometry(geom=Point(40, 50)) point.save() self.geom_with_unpublished_project.points.add(point) self.unpublished_project = ProjectFactory(published=False) self.unpublished_project.geo = self.geom_with_unpublished_project self.unpublished_project.save() self.list_url = reverse('api:geostore-centroids-list') self.user = User(username='******', password='******') self.user.save()
def setUp(self): super().setUp() self.project = ProjectFactory(published=True) self.other_project = ProjectFactory(published=True) self.curated_project_collection = CuratedProjectCollectionFactory( published=True, ) self.curated_project_collection.projects.add(self.project, self.other_project) self.url = reverse('api:curated-projects-list')
def setUp(self): self.geometry_store = GeometryStore() self.geometry_store.save() point = PointGeometryFactory() self.geometry_store.points.add(point) self.url = reverse('api:geometrystore-detail', args=[self.geometry_store.identifier]) # View ignores GeometryStores without projects, so add one self.project = ProjectFactory( countries=[CountryFactory(), CountryFactory()]) self.project.geo = self.geometry_store self.project.save() self.user = User(username='******', password='******') self.user.save()
def setUp(self): super().setUp() self.published_entry_count = 102 self.published_project_count = 101 EntryFactory.create_batch(self.published_entry_count, published=True) ProjectFactory.create_batch(self.published_project_count, published=True) self.unpublished_entry_count = 14 self.unpublished_project_count = 6 EntryFactory.create_batch(self.unpublished_entry_count, published=False) ProjectFactory.create_batch(self.unpublished_project_count, published=False) from django.conf import settings self.SEARCH = getattr(settings, 'SEARCH') self.PUBLISH_FILTER_ENABLED = getattr(settings, 'PUBLISH_FILTER_ENABLED', True)
def test_project_serializer(self): obj = ProjectFactory.create(name='Test title', countries=CountryFactory.create_batch(4), status=5) serializer = ProjectSerializer() doc = serializer.create_document(obj) self.assertIsInstance(doc, ProjectDoc) self.assertEqual(doc.name, 'Test title') self.assertEqual(len(doc.countries), 4) self.assertEqual(obj.status, 5) # doc should have string representation of choice self.assertEqual(obj.get_status_display(), doc.status)
def test_rebuild_index_no_args(self): EntryFactory.create_batch(100, published=True) ProjectFactory.create_batch(100, published=True) num_base_people = 100 num_employed_people = 120 total_num_people = num_base_people + num_employed_people PersonFactory.create_batch(num_base_people, published=True) PositionFactory.create_batch(num_employed_people) out = io.StringIO() call_command('rebuild_index', stdout=out) self.assertIn( "Reindexed {} '{}' documents".format( 100, EntryFactory._meta.model._meta.label), out.getvalue()) self.assertIn( "Reindexed {} '{}' documents".format( 100, ProjectFactory._meta.model._meta.label), out.getvalue()) self.assertIn( "Reindexed {} '{}' documents".format( total_num_people, PersonFactory._meta.model._meta.label), out.getvalue())
def test_index_model_multiple_models(self): entry_objects = EntryFactory.create_batch(30, published=True) project_objects = ProjectFactory.create_batch(20, published=True) job = self.queue.enqueue(index_model, EntryFactory._meta.model._meta.label) self.assertEqual(job.result, (30, [])) self.assertEqual(job.get_status(), 'finished') job = self.queue.enqueue(index_model, ProjectFactory._meta.model._meta.label) self.assertEqual(job.result, (20, [])) self.assertEqual(job.get_status(), 'finished') self.index.refresh() self.assertEqual( len(entry_objects) + len(project_objects), self.search.count())
def test_filters(self): included_project = ProjectFactory(published=True) included_project.save() excluded_project = ProjectFactory(published=True) excluded_project.save() with self.subTest('no filters'): response = self.client.get(self.url) returned_projects = [ result['name'] for result in json.loads(response.content.decode())['results'] ] self.assertIn(included_project.name, returned_projects) self.assertIn(excluded_project.name, returned_projects) with self.subTest('filter by funding'): funding = ProjectFunding(project=included_project, amount=5) funding.save() params = {'funding__amount__gte': '4'} response = self.client.get(self.url, params) returned_projects = [ result['name'] for result in json.loads(response.content.decode())['results'] ] self.assertIn(included_project.name, returned_projects) self.assertNotIn(excluded_project.name, returned_projects) with self.subTest('filter by funding - currency amount'): funding = ProjectFunding(project=included_project, amount=5) funding.save() params = {'funding__currency_amount__gte': '4 USD'} response = self.client.get(self.url, params) returned_projects = [ result['name'] for result in json.loads(response.content.decode())['results'] ] self.assertIn(included_project.name, returned_projects) self.assertNotIn(excluded_project.name, returned_projects)
def setUp(self): super().setUp() self.url = reverse('search:search') self.index_patch = patch.object(SiteSearch, 'index', TEST_SEARCH['default']['index']) self.index_patch.start() india = CountryFactory(name='India') china = CountryFactory(name='China') rail_type = InfrastructureTypeFactory(name='Railroad') road_type = InfrastructureTypeFactory(name='Road') self.china_rail = ProjectFactory(name='China Rail Project', infrastructure_type=rail_type, countries=[ china, ]) self.china_road = ProjectFactory(name='China Road Project', infrastructure_type=road_type, countries=[ china, ]) self.india_rail = ProjectFactory(name='India Rail Project', infrastructure_type=rail_type, countries=[ india, ]) self.india_road = ProjectFactory(name='India Road Project', infrastructure_type=road_type, countries=[ india, ]) serializer = ProjectSerializer() serializer.create_document(self.china_rail).save() serializer.create_document(self.china_road).save() serializer.create_document(self.india_rail).save() serializer.create_document(self.india_road).save() self.index.refresh()
class TestGeometryStoreDetailView(TestCase): def setUp(self): self.geometry_store = GeometryStore() self.geometry_store.save() point = PointGeometryFactory() self.geometry_store.points.add(point) self.url = reverse('api:geometrystore-detail', args=[self.geometry_store.identifier]) # View ignores GeometryStores without projects, so add one self.project = ProjectFactory( countries=[CountryFactory(), CountryFactory()]) self.project.geo = self.geometry_store self.project.save() self.user = User(username='******', password='******') self.user.save() def test_geometrystore_with_no_project(self): """ Without a project, the GeometryStoreDetailView should return a 404 """ geometry_store = GeometryStore() geometry_store.save() point = PointGeometryFactory() geometry_store.points.add(point) url = reverse('api:geometrystore-detail', args=[geometry_store.identifier]) with self.subTest('Authenticated'): self.client.force_login(self.user) response = self.client.get(url) self.assertEqual(response.status_code, 404) with self.subTest('Anonymous'): self.client.logout() response = self.client.get(url) self.assertEqual(response.status_code, 404) def test_published_project(self): self.project.published = True self.project.save() with self.settings(PUBLISH_FILTER_ENABLED=True): with self.subTest('Authenticated and PUBLISH_FILTER_ENABLED'): self.client.force_login(self.user) response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True))) with self.subTest('Not authenticated, PUBLISH_FILTER_ENABLED'): self.client.logout() response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True))) with self.settings(PUBLISH_FILTER_ENABLED=False): with self.subTest( 'Authenticated and PUBLISH_FILTER_ENABLED == False'): self.client.force_login(self.user) response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True))) with self.subTest( 'Not authenticated, PUBLISH_FILTER_ENABLED == False'): self.client.logout() response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True))) def test_unpublished_project(self): self.project.published = False self.project.save() with self.settings(PUBLISH_FILTER_ENABLED=True): with self.subTest('Authenticated and PUBLISH_FILTER_ENABLED'): self.client.force_login(self.user) response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True))) with self.subTest('Not authenticated, PUBLISH_FILTER_ENABLED'): self.client.logout() response = self.client.get(self.url) self.assertEqual(response.status_code, 404) with self.settings(PUBLISH_FILTER_ENABLED=False): with self.subTest( 'Authenticated and PUBLISH_FILTER_ENABLED == False'): self.client.force_login(self.user) response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True))) with self.subTest( 'Not authenticated, PUBLISH_FILTER_ENABLED == False'): self.client.logout() response = self.client.get(self.url) self.assertEqual(response.status_code, 200) response_locations = [ proj['locations'] for proj in response.data['projects'] ][0] self.assertEqual( set(response_locations), set(self.project.countries.values_list('name', flat=True)))
class TestGeometryStoreCentroidViewSet(TestCase): def setUp(self): self.geom_with_published_project = GeometryStore() self.geom_with_published_project.save() point = PointGeometry(geom=Point(20, 30)) point.save() self.geom_with_published_project.points.add(point) self.published_project = ProjectFactory( published=True, countries=[CountryFactory(), CountryFactory()], total_cost=1200000) self.published_project.geo = self.geom_with_published_project self.published_project.save() self.geom_with_unpublished_project = GeometryStore() self.geom_with_unpublished_project.save() point = PointGeometry(geom=Point(40, 50)) point.save() self.geom_with_unpublished_project.points.add(point) self.unpublished_project = ProjectFactory(published=False) self.unpublished_project.geo = self.geom_with_unpublished_project self.unpublished_project.save() self.list_url = reverse('api:geostore-centroids-list') self.user = User(username='******', password='******') self.user.save() def test_centroid_list(self): # Make a GeometryStore object without points/lines/polygons/centroid # This should not appear in list unlocated = GeometryStore() unlocated.save() # Single point store which doesn't have an associcated project # This should not appear in list random_point = GeometryStore() random_point.save() point = PointGeometry(geom=Point(20, 30)) point.save() random_point.points.add(point) with self.settings(PUBLISH_FILTER_ENABLED=True): with self.subTest('Authenticated and PUBLISH_FILTER_ENABLED'): self.client.force_login(self.user) response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) # Both geometries from setUp should be in the list, but not the one without a centroid. data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 2) with self.subTest('Not authenticated, PUBLISH_FILTER_ENABLED'): self.client.logout() response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) # Only the geometry with a published project should be included. data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 1) with self.settings(PUBLISH_FILTER_ENABLED=False): with self.subTest( 'Authenticated and PUBLISH_FILTER_ENABLED == False'): self.client.force_login(self.user) response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) # Both geometries from setUp should be in the list, but not the one without a centroid. data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 2) with self.subTest( 'Not authenticated, PUBLISH_FILTER_ENABLED == False'): self.client.logout() response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) # Both geometries from setUp should be in the list, but not the one without a centroid. data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 2) def test_response_format(self): """Centroids should include related project information in their properties.""" with self.settings(PUBLISH_FILTER_ENABLED=True): self.client.logout() response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) # Only the geometry with a published project should be included. data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 1) feature = data['features'][0] self.assertEqual( feature, { 'id': str(self.geom_with_published_project.identifier), 'type': 'Feature', 'geometry': { 'type': 'Point', 'coordinates': [ self.geom_with_published_project.centroid.x, self.geom_with_published_project.centroid.y, ], }, 'properties': { 'label': self.published_project.name, 'geostore': str(self.geom_with_published_project.identifier), 'icon-image': 'dot', 'infrastructureType': self.published_project.infrastructure_type.name, "locations": ','.join( self.geom_with_published_project.projects.values_list( 'countries__name', flat=True)), "total_cost": self.geom_with_published_project.projects.all() [0].total_cost, "currency": self.geom_with_published_project.projects.all() [0].total_cost_currency, } }) def test_performance(self): """Count the number of queries required to fetch the centroids.""" # Make a GeometryStore object without points/lines/polygons/centroid # This should not appear in list unlocated = GeometryStore() unlocated.save() # Single point store which doesn't have an associcated project # This should not appear in list random_point = GeometryStore() random_point.save() point = PointGeometry(geom=Point(20, 30)) point.save() random_point.points.add(point) # Create 9 more (for a total of 10) random point projects for the map for i in range(9): geo = GeometryStore() geo.save() point = PointGeometry(geom=Point(20, 30)) point.save() geo.points.add(point) project = ProjectFactory(published=True) project.geo = geo project.save() with self.settings(PUBLISH_FILTER_ENABLED=True): self.client.logout() with self.assertNumQueries(3): # All response data should be fetched in a single query response = self.client.get(self.list_url) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 10) def test_centroid_list_filters(self): """ Test that one can filter by the related project's infrastructure type name, which is set as an annoation """ project_type = self.geom_with_published_project.projects.first( ).infrastructure_type.name with self.subTest('project type match'): response = self.client.get(self.list_url, {'project_type': project_type}) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 1) with self.subTest('project type not match'): response = self.client.get(self.list_url, {'project_type': "FOO"}) self.assertEqual(response.status_code, 200) data = json.loads(response.content.decode()) self.assertEqual(len(data['features']), 0)
class TestSearchViewSet(BaseSearchTestCase): def setUp(self): super().setUp() self.url = reverse('search:search') self.index_patch = patch.object(SiteSearch, 'index', TEST_SEARCH['default']['index']) self.index_patch.start() india = CountryFactory(name='India') china = CountryFactory(name='China') rail_type = InfrastructureTypeFactory(name='Railroad') road_type = InfrastructureTypeFactory(name='Road') self.china_rail = ProjectFactory(name='China Rail Project', infrastructure_type=rail_type, countries=[ china, ]) self.china_road = ProjectFactory(name='China Road Project', infrastructure_type=road_type, countries=[ china, ]) self.india_rail = ProjectFactory(name='India Rail Project', infrastructure_type=rail_type, countries=[ india, ]) self.india_road = ProjectFactory(name='India Road Project', infrastructure_type=road_type, countries=[ india, ]) serializer = ProjectSerializer() serializer.create_document(self.china_rail).save() serializer.create_document(self.china_road).save() serializer.create_document(self.india_rail).save() serializer.create_document(self.india_road).save() self.index.refresh() def tearDown(self): super().tearDown() self.index_patch.stop() def test_that_view_loads(self): """Load search page with no query string.""" response = self.client.get(self.url) self.assertEqual(response.status_code, 200) def test_with_search_param(self): """Search for objects in the index.""" with self.subTest('No results'): params = {'q': '123'} response = self.client.get(self.url, params) self.assertContains(response, 'No results found') with self.subTest('Find project'): self.index.refresh() params = {'q': 'China Rail'} response = self.client.get(self.url, params) self.assertContains(response, self.china_rail.get_absolute_url()) def test_with_search_facets(self): """Narrow results by using facets.""" with self.subTest('Find all projects'): params = { 'q': 'project', 'facet': [ '_category:Project', ], } response = self.client.get(self.url, params) self.assertContains(response, self.china_rail.get_absolute_url()) self.assertContains(response, self.china_road.get_absolute_url()) self.assertContains(response, self.india_rail.get_absolute_url()) self.assertContains(response, self.india_road.get_absolute_url()) with self.subTest('Find road projects'): params = { 'q': 'project', 'facet': [ '_category:Project', 'infrastructure_type:Road', ], } response = self.client.get(self.url, params) self.assertNotContains(response, self.china_rail.get_absolute_url()) self.assertContains(response, self.china_road.get_absolute_url()) self.assertNotContains(response, self.india_rail.get_absolute_url()) self.assertContains(response, self.india_road.get_absolute_url()) with self.subTest('Find road projects in China'): params = { 'q': 'project', 'facet': [ '_category:Project', 'infrastructure_type:Road', 'project_location:China', ], } response = self.client.get(self.url, params) self.assertNotContains(response, self.china_rail.get_absolute_url()) self.assertContains(response, self.china_road.get_absolute_url()) self.assertNotContains(response, self.india_rail.get_absolute_url()) self.assertNotContains(response, self.india_road.get_absolute_url()) def test_search_pagination(self): """User can select page size and the page they want to view.""" with self.subTest('Change page size'): params = {'q': 'project', 'size': '2'} response = self.client.get(self.url, params) self.assertEqual(response.context['search']['offset'], 0) self.assertEqual(response.context['search']['size'], 2) self.assertEqual(len(response.context['search']['results']), 2) self.assertEqual(response.context['search']['total'], 4) with self.subTest('Get next page'): params = { 'q': 'project', 'size': '2', 'offset': '2', } response = self.client.get(self.url, params) self.assertEqual(response.context['search']['offset'], 2) self.assertEqual(response.context['search']['size'], 2) self.assertEqual(len(response.context['search']['results']), 2) self.assertEqual(response.context['search']['total'], 4) with self.subTest('Invalid page'): params = { 'q': 'project', 'size': 'foo', 'offset': 'bar', } response = self.client.get(self.url, params) self.assertEqual(response.context['search']['offset'], 0) self.assertEqual(response.context['search']['size'], 20) self.assertEqual(len(response.context['search']['results']), 4) self.assertEqual(response.context['search']['total'], 4)