def setUp(self): super().setUp() # Create some asset uploads for i in range(1, 4): AssetUpload.objects.create(asset=self.asset, upload_id=f'upload-{i}', status=AssetUpload.Status.ABORTED, checksum_multihash=get_sha256_multihash( b'upload-%d' % i), number_parts=2, ended=utc_aware(datetime.utcnow()), md5_parts=[]) for i in range(4, 8): AssetUpload.objects.create(asset=self.asset, upload_id=f'upload-{i}', status=AssetUpload.Status.COMPLETED, checksum_multihash=get_sha256_multihash( b'upload-%d' % i), number_parts=2, ended=utc_aware(datetime.utcnow()), md5_parts=[]) AssetUpload.objects.create( asset=self.asset, upload_id='upload-8', status=AssetUpload.Status.IN_PROGRESS, checksum_multihash=get_sha256_multihash(b'upload-8'), number_parts=2, md5_parts=[]) self.maxDiff = None # pylint: disable=invalid-name
def test_item_deserialization_end_date_before_start_date(self): today = datetime.utcnow() yesterday = today - timedelta(days=1) sample = self.data_factory.create_item_sample( collection=self.collection.model, sample='item-1', properties={ 'start_datetime': isoformat(utc_aware(today)), "end_datetime": isoformat(utc_aware(yesterday)) }) # translate to Python native: serializer = ItemSerializer(data=sample.get_json('deserialize')) with self.assertRaises(ValidationError): serializer.is_valid(raise_exception=True)
def abort_multipart_upload(self, executor, asset_upload, asset): key = get_asset_path(asset.item, asset.name) executor.abort_multipart_upload(key, asset, asset_upload.upload_id) asset_upload.status = AssetUpload.Status.ABORTED asset_upload.ended = utc_aware(datetime.utcnow()) asset_upload.urls = [] asset_upload.save()
def test_asset_endpoint_post_read_only_in_payload(self): collection_name = self.collection.name item_name = self.item.name asset = self.factory.create_asset_sample(item=self.item, created=utc_aware( datetime.utcnow()), create_asset_file=True) path = f'/{STAC_BASE_V}/collections/{collection_name}/items/{item_name}/assets' response = self.client.post(path, data=asset.get_json('post', keep_read_only=True), content_type="application/json") self.assertStatusCode(400, response) self.assertEqual( { 'created': ['Found read-only property in payload'], 'href': ['Found read-only property in payload'] }, response.json()['description'], msg='Unexpected error message', ) # Make sure that the asset is not found in DB self.assertFalse(Asset.objects.filter(name=asset.json['id']).exists(), msg="Invalid asset has been created in DB")
def check_urls_response(self, urls, number_parts): now = utc_aware(datetime.utcnow()) self.assertEqual(len(urls), number_parts) for i, url in enumerate(urls): self.assertListEqual(list(url.keys()), ['url', 'part', 'expires'], msg='Url dictionary keys missing') self.assertEqual( url['part'], i + 1, msg=f'Part {url["part"]} does not match the url index {i}') try: url_parsed = parse.urlparse(url["url"]) self.assertIn(url_parsed[0], ['http', 'https']) except ValueError as error: self.fail( msg= f"Invalid url {url['url']} for part {url['part']}: {error}" ) try: expires_dt = fromisoformat(url['expires']) self.assertGreater( expires_dt, now, msg= f"expires {url['expires']} for part {url['part']} is not in future" ) except ValueError as error: self.fail( msg= f"Invalid expires {url['expires']} for part {url['part']}: {error}" )
def test_item_endpoint_patch_read_only_in_payload(self): data = {"created": utc_aware(datetime.utcnow())} path = f'/{STAC_BASE_V}/collections/{self.collection.name}/items/{self.item.name}' response = self.client.patch(path, data=data, content_type="application/json") self.assertStatusCode(400, response)
def test_asset_endpoint_put_read_only_in_payload(self): collection_name = self.collection['name'] item_name = self.item['name'] asset_name = self.asset['name'] changed_asset = self.factory.create_asset_sample( item=self.item.model, name=asset_name, sample='asset-1-updated', media_type=self.asset['media_type'], created=utc_aware(datetime.utcnow()), create_asset_file=False, checksum_multihash=self.asset['checksum_multihash'], ) path = f'/{STAC_BASE_V}/collections/{collection_name}/items/{item_name}/assets/{asset_name}' response = self.client.put(path, data=changed_asset.get_json( 'put', keep_read_only=True), content_type="application/json") self.assertStatusCode(400, response) self.assertEqual( { 'created': ['Found read-only property in payload'], 'checksum:multihash': ['Found read-only property in payload'] }, response.json()['description'], msg='Unexpected error message')
def setUpTestData(cls): cls.factory = Factory() cls.collection = cls.factory.create_collection_sample().model cls.item_1 = cls.factory.create_item_sample( cls.collection, name='item-1', properties_datetime=fromisoformat('2019-01-01T00:00:00Z'), db_create=True, ) cls.now = utc_aware(datetime.utcnow()) cls.yesterday = cls.now - timedelta(days=1) cls.item_now = cls.factory.create_item_sample( cls.collection, name='item-now', properties_datetime=cls.now, db_create=True, ) cls.item_yesterday = cls.factory.create_item_sample( cls.collection, name='item-yesterday', properties_datetime=cls.yesterday, db_create=True)
def test_item_create_model(self): item = Item(collection=self.collection, name='item-1', properties_datetime=utc_aware(datetime.utcnow())) item.full_clean() item.save() self.assertEqual('item-1', item.name)
def test_item_deserialization_update_remove_title(self): original_sample = self.data_factory.create_item_sample( collection=self.collection.model, sample='item-1', ) sample = self.data_factory.create_item_sample( collection=self.collection.model, sample='item-2', name=original_sample["name"], properties={"datetime": isoformat(utc_aware(datetime.utcnow()))}) serializer = ItemSerializer(original_sample.model, data=sample.get_json('deserialize')) serializer.is_valid(raise_exception=True) item = serializer.save() # mock a request needed for the serialization of links context = { 'request': api_request_mocker.get( f'{STAC_BASE_V}/collections/{self.collection["name"]}/items/{sample["name"]}' ) } serializer = ItemSerializer(item, context=context) python_native = serializer.data self.check_stac_item(sample.json, python_native, self.collection["name"]) self.assertNotIn('title', python_native['properties'].keys(), msg="Title was not removed")
def test_create_asset_upload_default(self): asset_upload = self.create_asset_upload(self.asset_1, 'default-upload') self.assertEqual(asset_upload.urls, [], msg="Wrong default value") self.assertEqual(asset_upload.ended, None, msg="Wrong default value") self.assertAlmostEqual(utc_aware(datetime.utcnow()).timestamp(), asset_upload.created.timestamp(), delta=1, msg="Wrong default value")
def test_item_create_model_none_geometry(self): # None geometry should not be allowed with self.assertRaises(ValidationError): item = Item(collection=self.collection, properties_datetime=utc_aware(datetime.utcnow()), name='item-empty', geometry=None) item.full_clean() item.save()
def setUpTestData(cls): cls.data_factory = Factory() cls.collection_created = utc_aware(datetime.now()) cls.collection = cls.data_factory.create_collection_sample( db_create=True) cls.item = cls.data_factory.create_item_sample( collection=cls.collection.model, db_create=True) cls.asset = cls.data_factory.create_asset_sample(item=cls.item.model, db_create=True)
def setUp(self): self.data_factory = Factory() self.collection_created = utc_aware(datetime.now()) self.collection = self.data_factory.create_collection_sample( db_create=True) self.item = self.data_factory.create_item_sample( collection=self.collection.model, db_create=True) self.asset = self.data_factory.create_asset_sample( item=self.item.model, db_create=True) self.collection.model.refresh_from_db() self.maxDiff = None # pylint: disable=invalid-name
def test_collections_post_read_only_in_payload(self): collection = self.collection_factory.create_sample(created=utc_aware(datetime.utcnow())) response = self.client.post( f"/{STAC_BASE_V}/collections", data=collection.get_json('post', keep_read_only=True), content_type='application/json' ) self.assertStatusCode(400, response) self.assertEqual({'created': ['Found read-only property in payload']}, response.json()['description'], msg='Unexpected error message')
def test_item_create_model_valid_geometry(self): # a correct geometry should not pose any problems item = Item( collection=self.collection, properties_datetime=utc_aware(datetime.utcnow()), name='item-1', geometry=GEOSGeometry( 'SRID=4326;POLYGON ' '((5.96 45.82, 5.96 47.81, 10.49 47.81, 10.49 45.82, 5.96 45.82))' )) item.full_clean() item.save()
def test_item_create_model_invalid_geometry(self): # a geometry with self-intersection should not be allowed with self.assertRaises(ValidationError): item = Item( collection=self.collection, properties_datetime=utc_aware(datetime.utcnow()), name='item-1', geometry=GEOSGeometry( 'SRID=4326;POLYGON ' '((5.96 45.82, 5.96 47.81, 10.49 45.82, 10.49 47.81, 5.96 45.82))' )) item.full_clean() item.save()
def test_delete_asset_with_upload_in_progress(self): asset_upload_1 = self.create_asset_upload(self.asset, 'upload-in-progress') asset_upload_2 = self.create_asset_upload( self.asset, 'upload-completed', status=AssetUpload.Status.COMPLETED, ended=utc_aware(datetime.utcnow())) asset_upload_3 = self.create_asset_upload( self.asset, 'upload-aborted', status=AssetUpload.Status.ABORTED, ended=utc_aware(datetime.utcnow())) asset_upload_4 = self.create_asset_upload( self.asset, 'upload-aborted-2', status=AssetUpload.Status.ABORTED, ended=utc_aware(datetime.utcnow())) # Try to delete parent asset with self.assertRaises(ValidationError): self.asset.delete() self.assertEqual(4, len(list(AssetUpload.objects.all()))) self.assertTrue(Asset.objects.all().filter( name=self.asset.name, item__name=self.item.name, item__collection__name=self.collection.name).exists()) self.update_asset_upload(asset_upload_1, status=AssetUpload.Status.ABORTED, ended=utc_aware(datetime.utcnow())) self.asset.delete() self.assertEqual(0, len(list(AssetUpload.objects.all()))) self.assertFalse(Asset.objects.all().filter( name=self.asset.name, item__name=self.item.name, item__collection__name=self.collection.name).exists())
def test_collection_patch_read_only_in_payload(self): collection_name = self.collection.name # get a name that is registered in the service payload_json = {'license': 'open-source', 'created': utc_aware(datetime.utcnow())} # for the start, the collection[1] has to have a different licence than the payload self.assertNotEqual(self.collection.license, payload_json['license']) response = self.client.patch( f"/{STAC_BASE_V}/collections/{collection_name}", data=payload_json, content_type='application/json' ) self.assertStatusCode(400, response) self.assertEqual({'created': ['Found read-only property in payload']}, response.json()['description'], msg='Unexpected error message')
def create_presigned_url(self, key, asset, part, upload_id, part_md5): '''Create a presigned url for an upload part on the backend Args: key: string key on the S3 backend for which we want to create a presigned url upload part asset: Asset Asset metadata model associated with the S3 backend key part: int Part number for which to create a presigned url for upload part upload_id: string Upload ID for which to create a presigned url part_md5: string base64 MD5 digest of the part Returns: dict(string, int, datetime) Dict {'url': string, 'part': int, 'expires': datetime} ''' expires = utc_aware(datetime.utcnow() + timedelta( seconds=settings.AWS_PRESIGNED_URL_EXPIRES)) params = { 'Bucket': settings.AWS_STORAGE_BUCKET_NAME, 'Key': key, 'UploadId': upload_id, 'PartNumber': part, 'ContentMD5': part_md5, } url = self.call_s3_api(self.s3.generate_presigned_url, 'upload_part', Params=params, ExpiresIn=settings.AWS_PRESIGNED_URL_EXPIRES, HttpMethod='PUT', log_extra={ 'collection': asset.item.collection.name, 'item': asset.item.name, 'asset': asset.name, 'upload_id': upload_id }) logger.info('Presigned url %s for %s part %s with expires %s created', url, key, part, isoformat(expires), extra={ 'upload_id': upload_id, 'asset': asset.name }) return {'url': url, 'part': part, 'expires': expires}
def setUpTestData(cls): cls.factory = Factory() cls.collection = cls.factory.create_collection_sample().model cls.items = cls.factory.create_item_samples( [ 'item-1', 'item-2', 'item-switzerland', 'item-switzerland-west', 'item-switzerland-east', 'item-switzerland-north', 'item-switzerland-south', 'item-paris' ], cls.collection, db_create=True, ) cls.now = utc_aware(datetime.utcnow()) cls.yesterday = cls.now - timedelta(days=1)
def test_delete_asset_upload(self): upload_id = 'upload-in-progress' asset_upload = self.create_asset_upload(self.asset, upload_id) with self.assertRaises( ProtectedError, msg="Deleting an upload in progress not allowed"): asset_upload.delete() asset_upload = self.update_asset_upload( asset_upload, status=AssetUpload.Status.COMPLETED, ended=utc_aware(datetime.utcnow())) asset_upload.delete() self.assertFalse(AssetUpload.objects.all().filter( upload_id=upload_id, asset__name=self.asset.name).exists())
def list(self, request, *args, **kwargs): if not Collection.objects.filter( name=self.kwargs['collection_name']).exists(): logger.error("The collection %s does not exist", self.kwargs['collection_name']) raise Http404( f"The collection {self.kwargs['collection_name']} does not exists." ) queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) else: serializer = self.get_serializer(queryset, many=True) data = { 'type': 'FeatureCollection', 'timeStamp': utc_aware(datetime.utcnow()), 'features': serializer.data, 'links': [ OrderedDict([ ('rel', 'self'), ('href', request.build_absolute_uri()), ]), OrderedDict([ ('rel', 'root'), ('href', request.build_absolute_uri(f'/{settings.STAC_BASE_V}/')), ]), OrderedDict([ ('rel', 'parent'), ('href', request.build_absolute_uri('.').rstrip('/')), ]) ] } if page is not None: return self.get_paginated_response(data) return Response(data)
def complete_multipart_upload(self, executor, validated_data, asset_upload, asset): key = get_asset_path(asset.item, asset.name) parts = validated_data.get('parts', None) if parts is None: raise serializers.ValidationError( {'parts': _("Missing required field")}, code='missing') if len(parts) > asset_upload.number_parts: raise serializers.ValidationError({'parts': [_("Too many parts")]}, code='invalid') if len(parts) < asset_upload.number_parts: raise serializers.ValidationError({'parts': [_("Too few parts")]}, code='invalid') executor.complete_multipart_upload(key, asset, parts, asset_upload.upload_id) asset_upload.update_asset_checksum_multihash() asset_upload.status = AssetUpload.Status.COMPLETED asset_upload.ended = utc_aware(datetime.utcnow()) asset_upload.urls = [] asset_upload.save()
def list(self, request, *args, **kwargs): validate_search_request = ValidateSearchRequest() validate_search_request.validate( request) # validate the search request queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) else: serializer = self.get_serializer(queryset, many=True) data = { 'type': 'FeatureCollection', 'timeStamp': utc_aware(datetime.utcnow()), 'features': serializer.data, 'links': [ OrderedDict([ ('rel', 'self'), ('href', request.build_absolute_uri()), ]), OrderedDict([ ('rel', 'root'), ('href', request.build_absolute_uri(f'/{settings.STAC_BASE_V}/')), ]), OrderedDict([ ('rel', 'parent'), ('href', request.build_absolute_uri('.').rstrip('/')), ]) ] } if page is not None: return self.paginator.get_paginated_response(data, request) return Response(data)
def list(self, request, *args, **kwargs): validate_search_request = ValidateSearchRequest() validate_search_request.validate( request) # validate the search request queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) else: serializer = self.get_serializer(queryset, many=True) data = { 'type': 'FeatureCollection', 'timeStamp': utc_aware(datetime.utcnow()), 'features': serializer.data, 'links': get_relation_links(request, self.name) } if page is not None: return self.paginator.get_paginated_response(data, request) return Response(data)
def list(self, request, *args, **kwargs): validate_collection(self.kwargs) queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) else: serializer = self.get_serializer(queryset, many=True) data = { 'type': 'FeatureCollection', 'timeStamp': utc_aware(datetime.utcnow()), 'features': serializer.data, 'links': get_relation_links(request, self.name, [self.kwargs['collection_name']]) } if page is not None: return self.get_paginated_response(data) return Response(data)
class CollectionsSummariesTestCase(TestCase): y200 = utc_aware( datetime.strptime('0200-01-01T00:00:00Z', '%Y-%m-%dT%H:%M:%SZ')) y8000 = utc_aware( datetime.strptime('8000-01-01T00:00:00Z', '%Y-%m-%dT%H:%M:%SZ')) @classmethod @mock_s3_asset_file def setUpTestData(cls): cls.data_factory = Factory() @mock_s3_asset_file def setUp(self): self.collection = self.data_factory.create_collection_sample( name='collection-test-summaries-auto-update', db_create=True).model # def tearDown(self): # self.collection.delete() def add_range_item(self, start, end, name): item = self.data_factory.create_item_sample( collection=self.collection, name=name, sample='item-2', properties_start_datetime=start, properties_end_datetime=end, ).model return item def add_single_datetime_item(self, datetime_val, name): item = self.data_factory.create_item_sample( collection=self.collection, name=name, properties_datetime=datetime_val, ).model return item def add_asset(self, item, name, eo_gsd, geoadmin_variant, proj_epsg): asset = self.data_factory.create_asset_sample( item=item, name=name, eo_gsd=eo_gsd, geoadmin_variant=geoadmin_variant, proj_epsg=proj_epsg).model return asset def test_update_collection_summaries_asset_insertion(self): # Tests if the collection's summaries are updated when an asset is # added to the collection's two items item1 = self.add_range_item(self.y200, self.y8000, "item1") item2 = self.add_range_item(self.y200, self.y8000, "item2") self.add_asset(item1, "asset1", 1.2, "kgrs", 1234) self.assertEqual( self.collection.summaries["eo:gsd"], [1.2], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been inserted.") self.assertEqual( self.collection.summaries["geoadmin:variant"], ["kgrs"], "Collection's summaries[geoadmin:variant] has not been correctly " " updated after asset has been inserted.") self.assertEqual( self.collection.summaries["proj:epsg"], [1234], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been inserted.") self.add_asset(item2, "asset2", 2.1, "komb", 4321) self.assertEqual( self.collection.summaries["eo:gsd"], [1.2, 2.1], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been inserted.") self.assertEqual( self.collection.summaries["geoadmin:variant"], ["kgrs", "komb"], "Collection's summaries[geoadmin:variant] has not been correctly " "updated after asset has been inserted.") self.assertEqual( self.collection.summaries["proj:epsg"], [1234, 4321], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been inserted.") def test_update_collection_summaries_asset_deletion(self): # Tests if the collection's summaries are updated when assets are # deleted from the collection item1 = self.add_range_item(self.y200, self.y8000, "item1") asset1 = self.add_asset(item1, "asset1", 1.2, "kgrs", 1234) asset2 = self.add_asset(item1, "asset2", 2.1, "komb", 4321) asset2.delete() self.assertEqual( self.collection.summaries["eo:gsd"], [asset1.eo_gsd], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been deleted.") self.assertEqual( self.collection.summaries["geoadmin:variant"], [asset1.geoadmin_variant], "Collection's summaries[geoadmin:variant] has not been correctly " "updated after asset has been deleted.") self.assertEqual( self.collection.summaries["proj:epsg"], [asset1.proj_epsg], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been deleted.") asset1.delete() self.assertEqual( self.collection.summaries["eo:gsd"], [], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been deleted.") self.assertEqual( self.collection.summaries["geoadmin:variant"], [], "Collection's summaries[geoadmin:variant] has not been correctly " "updated after asset has been deleted.") self.assertEqual( self.collection.summaries["proj:epsg"], [], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been deleted.") def test_update_collection_summaries_empty_asset_delete(self): # This test has been introduced due to a bug when removing an asset without eo:gsd, # proj:espg and geoadmin:variant from a collections with summaries self.assertEqual(self.collection.summaries, { 'eo:gsd': [], 'proj:epsg': [], 'geoadmin:variant': [] }) item = self.data_factory.create_item_sample( collection=self.collection).model asset = self.data_factory.create_asset_sample(item=item, required_only=True, geoadmin_variant=None, eo_gsd=None, proj_epsg=None).model self.assertEqual(self.collection.summaries, { 'eo:gsd': [], 'proj:epsg': [], 'geoadmin:variant': [] }) asset2 = self.data_factory.create_asset_sample(item=item, required_only=True, geoadmin_variant='krel', eo_gsd=2, proj_epsg=2056).model self.assertIsNone(asset.geoadmin_variant) self.assertEqual(self.collection.summaries, { 'eo:gsd': [2], 'proj:epsg': [2056], 'geoadmin:variant': ['krel'] }) asset.delete() self.assertEqual(self.collection.summaries, { 'eo:gsd': [2], 'proj:epsg': [2056], 'geoadmin:variant': ['krel'] }) asset2.delete() self.assertEqual(self.collection.summaries, { 'eo:gsd': [], 'proj:epsg': [], 'geoadmin:variant': [] }) def test_update_collection_summaries_asset_update(self): # Tests if collection's summaries are updated correctly after an # asset was updated item1 = self.add_range_item(self.y200, self.y8000, "item1") asset1 = self.add_asset(item1, "asset1", 1.2, "kgrs", 1234) asset2 = self.add_asset(item1, "asset2", 2.1, "komb", 4321) asset1.eo_gsd = 12.34 asset1.geoadmin_variant = "krel" asset1.proj_epsg = 9999 asset1.full_clean() asset1.save() self.assertEqual( self.collection.summaries["eo:gsd"], [2.1, 12.34], "Collection's summaries[eo:gsd] has not been correctly " "updated after asset has been inserted.") self.assertEqual( self.collection.summaries["geoadmin:variant"], ["komb", "krel"], "Collection's summaries[geoadmin:variant] has not been " "correctly updated after asset has been inserted.") self.assertEqual( self.collection.summaries["proj:epsg"], [4321, 9999], "Collection's summaries[proj:epsg] has not been correctly " "updated after asset has been inserted.") def test_update_collection_summaries_none_values(self): # update a variant, that as been None as a start value item = self.data_factory.create_item_sample( collection=self.collection).model asset = self.add_asset(item, 'asset-1', None, None, None) self.assertEqual(self.collection.summaries, { 'eo:gsd': [], 'proj:epsg': [], 'geoadmin:variant': [] }) asset.geoadmin_variant = "krel" asset.eo_gsd = 2 asset.proj_epsg = 2056 asset.full_clean() asset.save() self.assertEqual(self.collection.summaries, { 'eo:gsd': [2.0], 'proj:epsg': [2056], 'geoadmin:variant': ['krel'] })
def test_pagination(self): # pylint: disable=too-many-locals items = self.factory.create_item_samples(3, self.collections[0].model, db_create=True) asset = self.factory.create_asset_sample(items[0].model, db_create=True) for i in range(1, 4): AssetUpload.objects.create( asset=asset.model, upload_id=f'upload-{i}', status=AssetUpload.Status.ABORTED, checksum_multihash=get_sha256_multihash(b'upload-%d' % i), number_parts=2, ended=utc_aware(datetime.utcnow()), md5_parts=['md5-%d-1' % i, 'md5-%d-2' % i]) for endpoint, result_attribute in [ ('collections', 'collections'), (f'collections/{self.collections[0]["name"]}/items', 'features'), (f'collections/{self.collections[0]["name"]}/items/{items[0]["name"]}/' f'assets/{asset["name"]}/uploads', 'uploads') ]: with self.subTest(endpoint=endpoint): # Page 1: response = self.client.get( f"/{STAC_BASE_V}/{endpoint}?limit=1") self.assertStatusCode(200, response) page_1 = response.json() # Make sure previous link is not present self.assertIsNone( get_link(page_1['links'], 'previous'), msg='Pagination previous link present for initial query') # Get and check next link next_link_2 = self._get_check_link(page_1['links'], 'next', endpoint) # PAGE 2: # Read the next page page_2 = self._read_link(next_link_2, 'next', [page_1], result_attribute) # get and check next link next_link_3 = self._get_check_link(page_2['links'], 'next', endpoint) # Get and check previous link previous_link_1 = self._get_check_link(page_2['links'], 'previous', endpoint) # PAGE 3: # Read the next page page_3 = self._read_link(next_link_3, 'next', [page_1, page_2], result_attribute) # Make sure next link is not present self.assertIsNone( get_link(page_3['links'], 'next'), msg='Pagination next link present for last page') # Get and check previous link previous_link_2 = self._get_check_link(page_3['links'], 'previous', endpoint) # Navigate back with previous links # PAGE: 2 _page_2 = self._read_link(previous_link_2, 'previous', [page_1, page_3], result_attribute) self.assertEqual( page_2[result_attribute], _page_2[result_attribute], msg= "Previous link for page 2 is not equal to next link to page 2" ) # get and check next link _next_link_3 = self._get_check_link(_page_2['links'], 'next', endpoint) # Get and check previous link _previous_link_1 = self._get_check_link( _page_2['links'], 'previous', endpoint) # PAGE 1: _page_1 = self._read_link(_previous_link_1, 'previous', [_page_2, page_2, page_3], result_attribute) self.assertEqual( page_1[result_attribute], _page_1[result_attribute], msg= "Previous link for page 1 is not equal to initial page 1")
class CollectionsSummariesTestCase(StacBaseTransactionTestCase): y200 = utc_aware(datetime.strptime('0200-01-01T00:00:00Z', '%Y-%m-%dT%H:%M:%SZ')) y8000 = utc_aware(datetime.strptime('8000-01-01T00:00:00Z', '%Y-%m-%dT%H:%M:%SZ')) @mock_s3_asset_file def setUp(self): self.data_factory = Factory() self.collection = self.data_factory.create_collection_sample( name='collection-test-summaries-auto-update', db_create=True ).model def add_range_item(self, start, end, name): item = self.data_factory.create_item_sample( collection=self.collection, name=name, sample='item-2', properties_start_datetime=start, properties_end_datetime=end, db_create=True ).model return item def add_single_datetime_item(self, datetime_val, name): item = self.data_factory.create_item_sample( collection=self.collection, name=name, properties_datetime=datetime_val, db_create=True, ).model return item def add_asset(self, item, eo_gsd, geoadmin_variant, proj_epsg, geoadmin_lang=None): asset = self.data_factory.create_asset_sample( item=item, eo_gsd=eo_gsd, geoadmin_variant=geoadmin_variant, geoadmin_lang=geoadmin_lang, proj_epsg=proj_epsg, db_create=True ).model self.collection.refresh_from_db() return asset def test_update_collection_summaries_asset_insertion(self): # Tests if the collection's summaries are updated when an asset is # added to the collection's two items item1 = self.add_range_item(self.y200, self.y8000, "item1") item2 = self.add_range_item(self.y200, self.y8000, "item2") self.add_asset(item1, 1.2, "kgrs", 1234, 'de') self.assertListEqual( self.collection.summaries_eo_gsd, [1.2], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been inserted." ) self.assertListEqual( self.collection.summaries_geoadmin_variant, ["kgrs"], "Collection's summaries[geoadmin:variant] has not been correctly " " updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_geoadmin_lang, ["de"], "Collection's summaries[geoadmin:lang] has not been correctly " " updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_proj_epsg, [1234], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been inserted." ) self.add_asset(item2, 2.1, "komb", 4321, 'fr') self.assertListEqual( self.collection.summaries_eo_gsd, [1.2, 2.1], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been inserted." ) self.assertListEqual( self.collection.summaries_geoadmin_variant, ["kgrs", "komb"], "Collection's summaries[geoadmin:variant] has not been correctly " "updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_geoadmin_lang, ["de", "fr"], "Collection's summaries[geoadmin:lang] has not been correctly " "updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_proj_epsg, [1234, 4321], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been inserted." ) def test_update_collection_summaries_asset_deletion(self): # Tests if the collection's summaries are updated when assets are # deleted from the collection item1 = self.add_range_item(self.y200, self.y8000, "item1") asset1 = self.add_asset(item1, 1.2, "kgrs", 1234, 'de') asset2 = self.add_asset(item1, 2.1, "komb", 4321, 'fr') asset2.delete() self.collection.refresh_from_db() self.assertListEqual( self.collection.summaries_eo_gsd, [asset1.eo_gsd], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been deleted." ) self.assertListEqual( self.collection.summaries_geoadmin_variant, [asset1.geoadmin_variant], "Collection's summaries[geoadmin:variant] has not been correctly " "updated after asset has been deleted." ) self.assertListEqual( self.collection.summaries_geoadmin_lang, [asset1.geoadmin_lang], "Collection's summaries[geoadmin:lang] has not been correctly " "updated after asset has been deleted." ) self.assertListEqual( self.collection.summaries_proj_epsg, [asset1.proj_epsg], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been deleted." ) asset1.delete() self.collection.refresh_from_db() self.assertListEqual( self.collection.summaries_eo_gsd, [], "Collection's summaries[eo:gsd] has not been correctly updated " "after asset has been deleted." ) self.assertListEqual( self.collection.summaries_geoadmin_variant, [], "Collection's summaries[geoadmin:variant] has not been correctly " "updated after asset has been deleted." ) self.assertListEqual( self.collection.summaries_geoadmin_lang, [], "Collection's summaries[geoadmin:lang] has not been correctly " "updated after asset has been deleted." ) self.assertListEqual( self.collection.summaries_proj_epsg, [], "Collection's summaries[proj:epsg] has not been correctly updated " "after asset has been deleted." ) def test_update_collection_summaries_empty_asset_delete(self): # This test has been introduced due to a bug when removing an asset without eo:gsd, # proj:epsg and geoadmin:variant from a collections with summaries self.assertListEqual(self.collection.summaries_proj_epsg, []) self.assertListEqual(self.collection.summaries_geoadmin_variant, []) self.assertListEqual(self.collection.summaries_geoadmin_lang, []) self.assertListEqual(self.collection.summaries_eo_gsd, []) item = self.data_factory.create_item_sample( collection=self.collection, db_create=True ).model asset = self.data_factory.create_asset_sample( item=item, required_only=True, geoadmin_variant=None, geoadmin_lang=None, eo_gsd=None, proj_epsg=None, db_create=True ).model self.assertListEqual(self.collection.summaries_proj_epsg, []) self.assertListEqual(self.collection.summaries_geoadmin_variant, []) self.assertListEqual(self.collection.summaries_geoadmin_lang, []) self.assertListEqual(self.collection.summaries_eo_gsd, []) asset2 = self.data_factory.create_asset_sample( item=item, required_only=True, geoadmin_variant='krel', geoadmin_lang='en', eo_gsd=2, proj_epsg=2056, db_create=True ).model self.collection.refresh_from_db() self.assertIsNone(asset.geoadmin_variant) self.assertListEqual(self.collection.summaries_proj_epsg, [2056]) self.assertListEqual(self.collection.summaries_geoadmin_variant, ['krel']) self.assertListEqual(self.collection.summaries_geoadmin_lang, ['en']) self.assertListEqual(self.collection.summaries_eo_gsd, [2]) asset.delete() self.collection.refresh_from_db() self.assertListEqual(self.collection.summaries_proj_epsg, [2056]) self.assertListEqual(self.collection.summaries_geoadmin_variant, ['krel']) self.assertListEqual(self.collection.summaries_geoadmin_lang, ['en']) self.assertListEqual(self.collection.summaries_eo_gsd, [2]) asset2.delete() self.collection.refresh_from_db() self.assertListEqual(self.collection.summaries_proj_epsg, []) self.assertListEqual(self.collection.summaries_geoadmin_variant, []) self.assertListEqual(self.collection.summaries_geoadmin_lang, []) self.assertListEqual(self.collection.summaries_eo_gsd, []) def test_update_collection_summaries_asset_update(self): # Tests if collection's summaries are updated correctly after an # asset was updated item1 = self.add_range_item(self.y200, self.y8000, "item1") asset1 = self.add_asset(item1, 1.2, "kgrs", 1234, 'de') asset2 = self.add_asset(item1, 2.1, "komb", 4321, 'fr') asset1.eo_gsd = 12.34 asset1.geoadmin_variant = "krel" asset1.geoadmin_lang = "en" asset1.proj_epsg = 9999 asset1.full_clean() asset1.save() self.collection.refresh_from_db() self.assertListEqual( self.collection.summaries_eo_gsd, [2.1, 12.34], "Collection's summaries[eo:gsd] has not been correctly " "updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_geoadmin_variant, ["komb", "krel"], "Collection's summaries[geoadmin:variant] has not been " "correctly updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_geoadmin_lang, ["en", "fr"], "Collection's summaries[geoadmin:lang] has not been " "correctly updated after asset has been inserted." ) self.assertListEqual( self.collection.summaries_proj_epsg, [4321, 9999], "Collection's summaries[proj:epsg] has not been correctly " "updated after asset has been inserted." ) def test_update_collection_summaries_none_values(self): # update a variant, that as been None as a start value item = self.data_factory.create_item_sample(collection=self.collection).model asset = self.add_asset(item, None, None, None, None) self.assertListEqual(self.collection.summaries_proj_epsg, []) self.assertListEqual(self.collection.summaries_geoadmin_variant, []) self.assertListEqual(self.collection.summaries_geoadmin_lang, []) self.assertListEqual(self.collection.summaries_eo_gsd, []) asset.geoadmin_variant = "krel" asset.eo_gsd = 2 asset.proj_epsg = 2056 asset.geoadmin_lang = 'rm' asset.full_clean() asset.save() self.collection.refresh_from_db() self.assertListEqual(self.collection.summaries_proj_epsg, [2056]) self.assertListEqual(self.collection.summaries_eo_gsd, [2.0]) self.assertListEqual(self.collection.summaries_geoadmin_variant, ['krel']) self.assertListEqual(self.collection.summaries_geoadmin_lang, ['rm'])