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
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
 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()
Ejemplo n.º 4
0
    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}"
             )
Ejemplo n.º 6
0
 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)
Ejemplo n.º 7
0
    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')
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
 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)
Ejemplo n.º 10
0
    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")
Ejemplo n.º 12
0
 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()
Ejemplo n.º 13
0
 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)
Ejemplo n.º 14
0
 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
Ejemplo n.º 15
0
    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')
Ejemplo n.º 16
0
 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()
Ejemplo n.º 17
0
 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())
Ejemplo n.º 19
0
 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')
Ejemplo n.º 20
0
    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}
Ejemplo n.º 21
0
 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())
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
 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()
Ejemplo n.º 25
0
    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)
Ejemplo n.º 26
0
    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)
Ejemplo n.º 27
0
    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)
Ejemplo n.º 28
0
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']
        })
Ejemplo n.º 29
0
    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")
Ejemplo n.º 30
0
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'])