def setUp(self):  # pylint: disable=invalid-name
     self.client = Client()
     self.factory = CollectionFactory()
     self.collection_1 = self.factory.create_sample(
         sample='collection-1', name='collection-1', db_create=True
     )
     self.collection_2 = self.factory.create_sample(
         sample='collection-2', name='collection-2', db_create=True
     )
     self.maxDiff = None  # pylint: disable=invalid-name
Пример #2
0
class CollectionsUnauthorizeEndpointTestCase(StacBaseTestCase):

    def setUp(self):  # pylint: disable=invalid-name
        self.client = Client()
        self.collection_factory = CollectionFactory()
        self.collection = self.collection_factory.create_sample().model
        self.maxDiff = None  # pylint: disable=invalid-name

    def test_unauthorized_collection_post_put_patch(self):
        # make sure POST fails for anonymous user:
        # a post with the absolute valid minimum
        sample = self.collection_factory.create_sample(sample='collection-2')

        response = self.client.post(
            f"/{STAC_BASE_V}/collections",
            data=sample.get_json('post'),
            content_type='application/json'
        )
        self.assertStatusCode(401, response, msg="Unauthorized post was permitted.")

        # make sure PUT fails for anonymous user:
        sample = self.collection_factory.create_sample(
            name=self.collection.name, sample='collection-2'
        )
        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{self.collection.name}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(401, response, msg="Unauthorized put was permitted.")

        # make sure PATCH fails for anonymous user:
        response = self.client.patch(
            f"/{STAC_BASE_V}/collections/{self.collection.name}",
            data=sample.get_json('patch'),
            content_type='application/json'
        )
        self.assertStatusCode(401, response, msg="Unauthorized patch was permitted.")

    def test_unauthorized_collection_delete(self):
        path = f'/{STAC_BASE_V}/collections/{self.collection.name}'
        response = self.client.delete(path)
        # Collection delete is not implemented (and currently not foreseen).
        # Status code here is 401, as user is unauthorized for write requests.
        # If logged-in, it should be 405, as DELETE for collections is not
        # implemented.
        self.assertStatusCode(
            401, response, msg="unauthorized and unimplemented collection delete was permitted."
        )
Пример #3
0
    def test_item_upsert_race_condition(self):
        workers = 5
        status_201 = 0
        collection_sample = CollectionFactory().create_sample(sample='collection-2')
        item_sample = ItemFactory().create_sample(collection_sample.model, sample='item-1')

        def item_atomic_upsert_test(worker):
            # This method run on separate thread therefore it requires to create a new client and
            # to login it for each call.
            client = Client()
            client.login(username=self.username, password=self.password)
            return client.put(
                reverse('item-detail', args=[collection_sample['name'], item_sample['name']]),
                data=item_sample.get_json('put'),
                content_type='application/json'
            )

        # We call the PUT item several times in parallel with the same data to make sure
        # that we don't have any race condition.
        responses, errors = self.run_parallel(workers, item_atomic_upsert_test)

        for worker, response in responses:
            if response.status_code == 201:
                status_201 += 1
            self.assertIn(
                response.status_code, [200, 201],
                msg=f'Unexpected response status code {response.status_code} for worker {worker}'
            )
            self.check_stac_item(item_sample.json, response.json(), collection_sample['name'])
        self.assertEqual(status_201, 1, msg="Not only one upsert did a create !")
Пример #4
0
 def test_create_collection_only_required_attributes(self):
     # try to create a valid collection with only the required attributes.
     # Should not raise any errors.
     CollectionFactory().create_sample(name="collection-required-only",
                                       sample="collection-1",
                                       db_create=True,
                                       required_only=True)
Пример #5
0
 def test_create_collection_invalid_providers(self):
     # try to create a collection with invalid collection name
     with self.assertRaises(
             ValidationError,
             msg="Collection with invalid providers was accepted."):
         CollectionFactory().create_sample(
             sample="collection-invalid-providers", db_create=True)
Пример #6
0
 def test_create_collection_missing_mandatory_fields(self):
     # try to create a collection with invalid collection name
     with self.assertRaises(
             ValidationError,
             msg="Collection with missing mandatory fields was accepted."):
         CollectionFactory().create_sample(
             name="collection-missing-mandatory-fields",
             sample="collection-missing-mandatory-fields",
             db_create=True)
class CollectionsEndpointTestCase(StacBaseTestCase):

    def setUp(self):  # pylint: disable=invalid-name
        self.client = Client()
        self.factory = CollectionFactory()
        self.collection_1 = self.factory.create_sample(
            sample='collection-1', name='collection-1', db_create=True
        )
        self.collection_2 = self.factory.create_sample(
            sample='collection-2', name='collection-2', db_create=True
        )
        self.maxDiff = None  # pylint: disable=invalid-name

    def test_collections_endpoint(self):
        # create a third collection with an ascendent name to make sure that collections
        # ordering is working
        collection_3 = self.factory.create_sample(
            sample='collection-2', name='collection-0', db_create=True
        )
        response = self.client.get(f"/{STAC_BASE_V}/collections")
        response_json = response.json()
        self.assertStatusCode(200, response)

        # Check that the output is sorted by name
        collection_ids = [collection['title'] for collection in response_json['collections']]
        self.assertListEqual(
            collection_ids, sorted(collection_ids), msg="Collections are not sorted by ID"
        )

        collection_samples = sorted([self.collection_1, self.collection_2, collection_3],
                                    key=lambda collection: collection['title'])
        for i, collection in enumerate(collection_samples):
            self.check_stac_collection(collection.json, response_json['collections'][i])

    def test_single_collection_endpoint(self):
        collection_name = self.collection_1.attributes['name']
        response = self.client.get(f"/{STAC_BASE_V}/collections/{collection_name}")
        response_json = response.json()
        self.assertStatusCode(200, response)
        # The ETag change between each test call due to the created, updated time that are in the
        # hash computation of the ETag
        self.check_header_etag(None, response)

        self.check_stac_collection(self.collection_1.json, response_json)
Пример #8
0
 def setUp(self):  # pylint: disable=invalid-name
     self.client = Client()
     client_login(self.client)
     self.collection_factory = CollectionFactory()
     self.maxDiff = None  # pylint: disable=invalid-name
Пример #9
0
class CollectionsWriteEndpointTestCase(StacBaseTestCase):

    def setUp(self):  # pylint: disable=invalid-name
        self.client = Client()
        client_login(self.client)
        self.collection_factory = CollectionFactory()
        self.maxDiff = None  # pylint: disable=invalid-name

    def test_valid_collections_post(self):
        collection = self.collection_factory.create_sample()

        path = f"/{STAC_BASE_V}/collections"
        response = self.client.post(
            path, data=collection.get_json('post'), content_type='application/json'
        )
        self.assertStatusCode(201, response)
        self.check_header_location(f'{path}/{collection.json["id"]}', response)

        response = self.client.get(f"/{STAC_BASE_V}/collections/{collection.json['id']}")
        response_json = response.json()
        self.assertEqual(response_json['id'], collection.json['id'])
        self.check_stac_collection(collection.json, response.json())

        # the dataset already exists in the database
        response = self.client.post(
            f"/{STAC_BASE_V}/collections",
            data=collection.get_json('post'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'id': ['This field must be unique.']},
                         response.json()['description'],
                         msg='Unexpected error message')

    def test_collections_post_extra_payload(self):
        collection = self.collection_factory.create_sample(extra_payload='not allowed')

        response = self.client.post(
            f"/{STAC_BASE_V}/collections",
            data=collection.get_json('post'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'extra_payload': ['Unexpected property in payload']},
                         response.json()['description'],
                         msg='Unexpected error message')

    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_invalid_collections_post(self):
        # the dataset already exists in the database
        collection = self.collection_factory.create_sample(sample='collection-invalid')

        response = self.client.post(
            f"/{STAC_BASE_V}/collections",
            data=collection.get_json('post'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'license': ['Not a valid string.']},
                         response.json()['description'],
                         msg='Unexpected error message')

    def test_collections_min_mandatory_post(self):
        # a post with the absolute valid minimum
        collection = self.collection_factory.create_sample(required_only=True)

        path = f"/{STAC_BASE_V}/collections"
        response = self.client.post(
            path, data=collection.get_json('post'), content_type='application/json'
        )
        response_json = response.json()
        logger.debug(response_json)
        self.assertStatusCode(201, response)
        self.check_header_location(f'{path}/{collection.json["id"]}', response)
        self.assertNotIn('title', response_json.keys())  # key does not exist
        self.assertNotIn('providers', response_json.keys())  # key does not exist
        self.check_stac_collection(collection.json, response_json)

    def test_collections_less_than_mandatory_post(self):
        # a post with the absolute valid minimum
        collection = self.collection_factory.create_sample(
            sample='collection-missing-mandatory-fields'
        )

        response = self.client.post(
            f"/{STAC_BASE_V}/collections",
            data=collection.get_json('post'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual(
            {
                'description': ['This field is required.'],
                'license': ['This field is required.'],
            },
            response.json()['description'],
            msg='Unexpected error message',
        )
Пример #10
0
 def setUp(self):  # pylint: disable=invalid-name
     self.client = Client()
     self.collection_factory = CollectionFactory()
     self.collection = self.collection_factory.create_sample().model
     self.maxDiff = None  # pylint: disable=invalid-name
Пример #11
0
class CollectionsUpdateEndpointTestCase(StacBaseTestCase):

    def setUp(self):  # pylint: disable=invalid-name
        self.client = Client()
        client_login(self.client)
        self.collection_factory = CollectionFactory()
        self.collection = self.collection_factory.create_sample().model
        self.maxDiff = None  # pylint: disable=invalid-name

    def test_collection_put_dont_exists(self):
        sample = self.collection_factory.create_sample(sample='collection-2')

        # the dataset to update does not exist yet
        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(404, response)

    def test_collections_put(self):
        sample = self.collection_factory.create_sample(
            name=self.collection.name, sample='collection-2'
        )

        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )

        self.assertStatusCode(200, response)

        # is it persistent?
        response = self.client.get(f"/{STAC_BASE_V}/collections/{sample['name']}")

        self.assertStatusCode(200, response)
        self.check_stac_collection(sample.json, response.json())

    def test_collections_put_extra_payload(self):
        sample = self.collection_factory.create_sample(
            name=self.collection.name, sample='collection-2', extra_payload='not valid'
        )

        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'extra_payload': ['Unexpected property in payload']},
                         response.json()['description'],
                         msg='Unexpected error message')

    def test_collections_put_read_only_in_payload(self):
        sample = self.collection_factory.create_sample(
            name=self.collection.name, sample='collection-2', created=utc_aware(datetime.utcnow())
        )

        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put', 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_collection_put_change_id(self):
        sample = self.collection_factory.create_sample(
            name='new-collection-name', sample='collection-2'
        )

        # for the start, the id have to be different
        self.assertNotEqual(self.collection.name, sample['name'])
        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{self.collection.name}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(200, response)

        # check if id changed
        response = self.client.get(f"/{STAC_BASE_V}/collections/{sample['name']}")
        self.assertStatusCode(200, response)
        self.check_stac_collection(sample.json, response.json())

        # the old collection shouldn't exist any more
        response = self.client.get(f"/{STAC_BASE_V}/collections/{self.collection.name}")
        self.assertStatusCode(404, response)

    def test_collection_put_remove_optional_fields(self):
        collection_name = self.collection.name  # get a name that is registered in the service
        sample = self.collection_factory.create_sample(
            name=collection_name, sample='collection-1', required_only=True
        )

        # for the start, the collection[1] has to have a title
        self.assertNotEqual('', f'{self.collection.title}')
        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(200, response)
        response_json = response.json()
        self.assertNotIn('title', response_json.keys())  # key does not exist
        self.assertNotIn('providers', response_json.keys())  # key does not exist

    def test_collection_patch(self):
        collection_name = self.collection.name  # get a name that is registered in the service
        payload_json = {'license': 'open-source'}
        # for the start, the collection[1] has to have a different licence than the payload
        self.assertNotEqual(self.collection.license, payload_json['license'])
        # for start the payload has no description
        self.assertNotIn('title', payload_json.keys())

        response = self.client.patch(
            f"/{STAC_BASE_V}/collections/{collection_name}",
            data=payload_json,
            content_type='application/json'
        )
        self.assertStatusCode(200, response)
        response_json = response.json()
        # licence affected by patch
        self.assertEqual(payload_json['license'], response_json['license'])

        # description not affected by patch
        self.assertEqual(self.collection.description, response_json['description'])

    def test_collection_patch_extra_payload(self):
        collection_name = self.collection.name  # get a name that is registered in the service
        payload_json = {'license': 'open-source', 'extra_payload': True}
        # for the start, the collection[1] has to have a different licence than the payload
        self.assertNotEqual(self.collection.license, payload_json['license'])
        # for start the payload has no description
        response = self.client.patch(
            f"/{STAC_BASE_V}/collections/{collection_name}",
            data=payload_json,
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'extra_payload': ['Unexpected property in payload']},
                         response.json()['description'],
                         msg='Unexpected error message')

    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 test_authorized_collection_delete(self):
        path = f'/{STAC_BASE_V}/collections/{self.collection.name}'
        response = self.client.delete(path)
        # Collection delete is not implemented (and currently not foreseen), hence
        # the status code should be 405. If it should get implemented in future
        # an unauthorized delete should get a status code of 401 (see test above).
        self.assertStatusCode(405, response, msg="unimplemented collection delete was permitted.")
 def setUp(self):  # pylint: disable=invalid-name
     self.client = Client()
     client_login(self.client)
     self.collection_factory = CollectionFactory()
     self.collection = self.collection_factory.create_sample(db_create=True)
     self.maxDiff = None  # pylint: disable=invalid-name
class CollectionsUpdateEndpointTestCase(StacBaseTestCase):

    def setUp(self):  # pylint: disable=invalid-name
        self.client = Client()
        client_login(self.client)
        self.collection_factory = CollectionFactory()
        self.collection = self.collection_factory.create_sample(db_create=True)
        self.maxDiff = None  # pylint: disable=invalid-name

    def test_collections_put(self):
        sample = self.collection_factory.create_sample(
            name=self.collection['name'], sample='collection-2'
        )

        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )

        self.assertStatusCode(200, response)

        # is it persistent?
        response = self.client.get(f"/{STAC_BASE_V}/collections/{sample['name']}")

        self.assertStatusCode(200, response)
        self.check_stac_collection(sample.json, response.json())

    def test_collections_put_extra_payload(self):
        sample = self.collection_factory.create_sample(
            name=self.collection['name'], sample='collection-2', extra_payload='not valid'
        )

        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'extra_payload': ['Unexpected property in payload']},
                         response.json()['description'],
                         msg='Unexpected error message')

    def test_collections_put_read_only_in_payload(self):
        sample = self.collection_factory.create_sample(
            name=self.collection['name'],
            sample='collection-2',
            created=utc_aware(datetime.utcnow())
        )

        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put', 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_collection_put_change_id(self):
        # Renaming is no longer allowed, due to this the test has been adapted
        sample = self.collection_factory.create_sample(
            name='new-collection-name', sample='collection-2'
        )

        # test if renaming does not work
        self.assertNotEqual(self.collection['name'], sample['name'])
        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{self.collection['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'id': 'Renaming is not allowed'},
                         response.json()['description'],
                         msg='Unexpected error message')

        # check if id has not changed
        response = self.client.get(f"/{STAC_BASE_V}/collections/{sample['name']}")
        self.assertStatusCode(404, response)

        # the old collection should still exist
        response = self.client.get(f"/{STAC_BASE_V}/collections/{self.collection['name']}")
        self.assertStatusCode(200, response)

    def test_collection_put_remove_optional_fields(self):
        collection_name = self.collection['name']  # get a name that is registered in the service
        sample = self.collection_factory.create_sample(
            name=collection_name, sample='collection-1', required_only=True
        )

        # for the start, the collection[1] has to have a title
        self.assertNotEqual('', f'{self.collection["title"]}')
        response = self.client.put(
            f"/{STAC_BASE_V}/collections/{sample['name']}",
            data=sample.get_json('put'),
            content_type='application/json'
        )
        self.assertStatusCode(200, response)
        response_json = response.json()
        self.assertNotIn('title', response_json.keys())  # key does not exist
        self.assertNotIn('providers', response_json.keys())  # key does not exist

    def test_collection_patch(self):
        collection_name = self.collection['name']  # get a name that is registered in the service
        payload_json = {'license': 'open-source'}
        # for the start, the collection[1] has to have a different licence than the payload
        self.assertNotEqual(self.collection["license"], payload_json['license'])
        # for start the payload has no description
        self.assertNotIn('title', payload_json.keys())

        response = self.client.patch(
            f"/{STAC_BASE_V}/collections/{collection_name}",
            data=payload_json,
            content_type='application/json'
        )
        self.assertStatusCode(200, response)
        response_json = response.json()
        # licence affected by patch
        self.assertEqual(payload_json['license'], response_json['license'])

        # description not affected by patch
        self.assertEqual(self.collection["description"], response_json['description'])

    def test_collection_patch_extra_payload(self):
        collection_name = self.collection['name']  # get a name that is registered in the service
        payload_json = {'license': 'open-source', 'extra_payload': True}
        # for the start, the collection[1] has to have a different licence than the payload
        self.assertNotEqual(self.collection['license'], payload_json['license'])
        # for start the payload has no description
        response = self.client.patch(
            f"/{STAC_BASE_V}/collections/{collection_name}",
            data=payload_json,
            content_type='application/json'
        )
        self.assertStatusCode(400, response)
        self.assertEqual({'extra_payload': ['Unexpected property in payload']},
                         response.json()['description'],
                         msg='Unexpected error message')

    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 test_collection_atomic_upsert_update_500(self):
        sample = self.collection_factory.create_sample(
            sample='collection-2', name=self.collection['name']
        )

        # Make sure samples is different from actual data
        self.assertNotEqual(sample.attributes, self.collection.attributes)

        # the dataset to update does not exist yet
        with self.settings(DEBUG_PROPAGATE_API_EXCEPTIONS=True), disableLogger('stac_api.apps'):
            # because we explicitely test a crash here we don't want to print a CRITICAL log on the
            # console therefore disable it.
            response = self.client.put(
                reverse('test-collection-detail-http-500', args=[sample['name']]),
                data=sample.get_json('put'),
                content_type='application/json'
            )
        self.assertStatusCode(500, response)
        self.assertEqual(response.json()['description'], "AttributeError('test exception')")

        # Make sure that the ressource has not been created
        response = self.client.get(reverse('collection-detail', args=[sample['name']]))
        self.assertStatusCode(200, response)
        self.check_stac_collection(self.collection.json, response.json())
Пример #14
0
 def test_create_collection_with_providers_and_links(self):
     # try to create a valid collection with providers and links. Should not raise any errors.
     CollectionFactory().create_sample(name="collection-links-providers",
                                       sample="collection-1",
                                       db_create=True)
Пример #15
0
 def setUpTestData(cls):
     cls.collection = CollectionFactory().create_sample(db_create=True)
Пример #16
0
 def setUpTestData(cls):
     CollectionFactory().create_sample().create()