From 5d428ec438c831ef8071bef1c4e2977c57f145c0 Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Tue, 12 Sep 2023 12:10:24 +0200 Subject: [PATCH 1/6] Add second map to map_layer_relation.py --- sample/layman.map/internal_url_thumbnail.json | 57 ------------------ ...sld_style_applied_in_map_thumbnail_map.png | Bin 45592 -> 0 bytes .../map_layer_relation/internal_hranice.json | 34 +++++++++++ .../map_layer_relation/map_layer_relation.py | 52 ++++++++++------ tests/static_data/__init__.py | 11 ---- 5 files changed, 67 insertions(+), 87 deletions(-) delete mode 100644 sample/layman.map/internal_url_thumbnail.json delete mode 100644 sample/style/test_sld_style_applied_in_map_thumbnail_map.png create mode 100644 tests/dynamic_data/publications/map_layer_relation/internal_hranice.json diff --git a/sample/layman.map/internal_url_thumbnail.json b/sample/layman.map/internal_url_thumbnail.json deleted file mode 100644 index 9a24b2c55..000000000 --- a/sample/layman.map/internal_url_thumbnail.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "describedBy": "https://raw.githubusercontent.com/hslayers/map-compositions/2.0.0/schema.json", - "schema_version": "2.0.0", - "abstract": "World places and boundaries abstract", - "title": "World places and boundaries", - "extent": [ - -35.0, - -48.5, - 179, - 81.5 - ], - "nativeExtent": [ - -35.0, - -48.5, - 179, - 81.5 - ], - "projection": "EPSG:4326", - "layers": [ - { - "metadata": {}, - "visibility": true, - "opacity": 1, - "title": "Staty", - "className": "HSLayers.Layer.WMS", - "singleTile": true, - "url": "http://localhost:8000/geoserver/test_workspace_wms/ows", - "params": { - "LAYERS": "post_blue_style", - "FORMAT": "image\/png" - } - }, - { - "metadata": {}, - "visibility": true, - "opacity": 1, - "title": "Defini\u010dn\u00ed body administrativn\u00edch celk\u016f", - "className": "HSLayers.Layer.WMS", - "singleTile": true, - "wmsMaxScale": 0, - "legends": [ - "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26version%3D1.3.0%26service%3DWMS%26request%3DGetLegendGraphic%26sld_version%3D1.1.0%26layer%3Ddefinicni_body_administrativnich_celku%26format%3Dimage%2Fpng%26STYLE%3Ddefault" - ], - "maxResolution": null, - "minResolution": 0, - "url": "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26", - "params": { - "LAYERS": "definicni_body_administrativnich_celku", - "INFO_FORMAT": "application\/vnd.ogc.gml", - "FORMAT": "image\/png", - "FROMCRS": "EPSG:3857", - "VERSION": "1.3.0" - }, - "dimensions": {} - } - ] -} diff --git a/sample/style/test_sld_style_applied_in_map_thumbnail_map.png b/sample/style/test_sld_style_applied_in_map_thumbnail_map.png deleted file mode 100644 index e95e8be10114e5011f5a40d83dc44c15089436fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45592 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 IM6N<$f-`<7F8}}l diff --git a/tests/dynamic_data/publications/map_layer_relation/internal_hranice.json b/tests/dynamic_data/publications/map_layer_relation/internal_hranice.json new file mode 100644 index 000000000..b455fa3db --- /dev/null +++ b/tests/dynamic_data/publications/map_layer_relation/internal_hranice.json @@ -0,0 +1,34 @@ +{ + "describedBy": "https://raw.githubusercontent.com/hslayers/map-compositions/2.0.0/schema.json", + "schema_version": "2.0.0", + "abstract": "World places and boundaries abstract", + "title": "World places and boundaries", + "extent": [ + -35.0, + -48.5, + 179, + 81.5 + ], + "nativeExtent": [ + -3896182.18, + -6190443.81, + 19926188.85, + 16579785.82 + ], + "projection": "epsg:3857", + "layers": [ + { + "metadata": {}, + "visibility": true, + "opacity": 1, + "title": "Hranice", + "className": "HSLayers.Layer.WMS", + "singleTile": true, + "url": "http://localhost:8000/geoserver/layer_map_relation_workspace_wms/ows", + "params": { + "LAYERS": "hranice", + "FORMAT": "image\/png" + } + } + ] +} diff --git a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py index 31b54e257..2c72f3908 100644 --- a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py +++ b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py @@ -16,6 +16,9 @@ WORKSPACE = 'layer_map_relation_workspace' LAYER_HRANICE = Publication(WORKSPACE, process_client.LAYER_TYPE, 'hranice') +LAYER_MISTA_NON_EXISTENT = Publication(WORKSPACE, process_client.LAYER_TYPE, 'mista') +MAP_HRANICE = Publication(WORKSPACE, process_client.MAP_TYPE, 'map_hranice') +MAP_HRANICE_OPERATES_ON = [LAYER_HRANICE] TEST_CASES = { 'post': { @@ -30,12 +33,12 @@ }, 'exp_after_rest_method': { 'map_layers': { - # workspace, layer name, layer index, exists? - (WORKSPACE, 'hranice', 1, True), - (WORKSPACE, 'mista', 2, False), - (WORKSPACE, 'hranice', 3, True), + # layer, layer index, exists? + (LAYER_HRANICE, 1, True), + (LAYER_MISTA_NON_EXISTENT, 2, False), + (LAYER_HRANICE, 3, True), }, - 'operates_on': ['hranice'], + 'operates_on': [LAYER_HRANICE], }, }, 'delete': { @@ -46,11 +49,11 @@ }, 'exp_before_rest_method': { 'map_layers': { - (WORKSPACE, 'hranice', 1, True), - (WORKSPACE, 'mista', 2, False), - (WORKSPACE, 'hranice', 3, True), + (LAYER_HRANICE, 1, True), + (LAYER_MISTA_NON_EXISTENT, 2, False), + (LAYER_HRANICE, 3, True), }, - 'operates_on': ['hranice'], + 'operates_on': [LAYER_HRANICE], }, 'exp_after_rest_method': { 'map_layers': None, @@ -74,7 +77,7 @@ class TestPublication(base_test.TestSingleRestPublication): type=EnumTestTypes.MANDATORY, ) for key, params in TEST_CASES.items()] - layer_uuids = {} + publ_uuids = {} def before_class(self): resp = self.post_publication(LAYER_HRANICE, args={ @@ -86,7 +89,12 @@ def before_class(self): 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.shx', ], }, scope='class') - self.layer_uuids[LAYER_HRANICE.name] = resp['uuid'] + self.publ_uuids[LAYER_HRANICE] = resp['uuid'] + + resp = self.post_publication(MAP_HRANICE, args={ + 'file_paths': [os.path.join(DIRECTORY, 'internal_hranice.json')], + }, scope='class') + self.publ_uuids[MAP_HRANICE] = resp['uuid'] def assert_exp_map_layers(self, map, exp_map_layers, exp_operates_on): with app.app_context(): @@ -101,17 +109,17 @@ def assert_exp_map_layers(self, map, exp_map_layers, exp_operates_on): for ml in publ_info['_map_layers'] } exp_map_layers = { - layer[:3] + ((self.layer_uuids[layer[1]] if layer[3] else None),) - for layer in exp_map_layers + (layer.workspace, layer.name, layer_index, self.publ_uuids[layer] if exists else None) + for layer, layer_index, exists in exp_map_layers } assert found_map_layers == exp_map_layers exp_operates_on = [ { - "xlink:href": f"http://localhost:3080/csw?SERVICE=CSW&VERSION=2.0.2&REQUEST=GetRecordById&OUTPUTSCHEMA=http://www.isotc211.org/2005/gmd&ID=m-{self.layer_uuids[layer_name]}#_m-{self.layer_uuids[layer_name]}", - "xlink:title": layer_name, + "xlink:href": f"http://localhost:3080/csw?SERVICE=CSW&VERSION=2.0.2&REQUEST=GetRecordById&OUTPUTSCHEMA=http://www.isotc211.org/2005/gmd&ID=m-{self.publ_uuids[layer]}#_m-{self.publ_uuids[layer]}", + "xlink:title": layer.name, } - for layer_name in exp_operates_on + for layer in exp_operates_on ] asserts_publ.metadata.correct_values_in_metadata( map.workspace, map.type, map.name, http_method=REQUEST_METHOD_POST, exp_values={ @@ -123,7 +131,7 @@ def assert_exp_layer_maps(layer, map_operates_on_tuples): exp_layer_maps = sorted([ (map.workspace, map.name) for map, operates_on in map_operates_on_tuples - if layer.name in operates_on + if layer in operates_on ]) with app.app_context(): found_layer_maps = [ @@ -135,7 +143,10 @@ def assert_exp_layer_maps(layer, map_operates_on_tuples): def test_publication(self, map, rest_method, rest_args, params): exp = params['exp_before_rest_method'] self.assert_exp_map_layers(map, exp['map_layers'], exp['operates_on']) - self.assert_exp_layer_maps(LAYER_HRANICE, [(map, exp['operates_on'] or [])]) + self.assert_exp_layer_maps(LAYER_HRANICE, [ + (MAP_HRANICE, MAP_HRANICE_OPERATES_ON), + (map, exp['operates_on'] or []), + ]) rest_method(map, args=rest_args) if rest_method == self.post_publication: # pylint: disable=W0143 @@ -143,4 +154,7 @@ def test_publication(self, map, rest_method, rest_args, params): exp = params['exp_after_rest_method'] self.assert_exp_map_layers(map, exp['map_layers'], exp['operates_on']) - self.assert_exp_layer_maps(LAYER_HRANICE, [(map, exp['operates_on'] or [])]) + self.assert_exp_layer_maps(LAYER_HRANICE, [ + (MAP_HRANICE, MAP_HRANICE_OPERATES_ON), + (map, exp['operates_on'] or []), + ]) diff --git a/tests/static_data/__init__.py b/tests/static_data/__init__.py index a25e33fda..128aaa1c4 100644 --- a/tests/static_data/__init__.py +++ b/tests/static_data/__init__.py @@ -765,16 +765,6 @@ 'bbox': (1627490.9553976597, 6547334.172794042, 1716546.5480322787, 6589515.35758913), }, }, - (COMMON_WORKSPACE, MAP_TYPE, 'post_internal_layer'): { - DEFINITION: [ - {'file_paths': ['sample/layman.map/internal_url_thumbnail.json', ]}, - ], - TEST_DATA: { - 'layers': [(COMMON_WORKSPACE, LAYER_TYPE, 'post_blue_style'), ], - 'operates_on': {(COMMON_WORKSPACE, LAYER_TYPE, 'post_blue_style'), }, - 'thumbnail': 'sample/style/test_sld_style_applied_in_map_thumbnail_map.png', - }, - }, (OWNER, MAP_TYPE, 'post_private'): { DEFINITION: [ {'headers': HEADERS[OWNER]}, @@ -848,7 +838,6 @@ # if (ws, pt, pn) in {(COMMON_WORKSPACE, LAYER_TYPE, 'post_common_sld'), # (COMMON_WORKSPACE, LAYER_TYPE, 'post_common_qml'), # (COMMON_WORKSPACE, LAYER_TYPE, 'post_jp2'), -# (COMMON_WORKSPACE, MAP_TYPE, 'post_internal_layer'), # (COMMON_WORKSPACE, LAYER_TYPE, 'post_blue_style'), # (COMMON_WORKSPACE, LAYER_TYPE, 'post_10countries_sld'), # }} From e7284c0ca837f8baeeacea77a3940ea3172970aa Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Tue, 12 Sep 2023 12:26:23 +0200 Subject: [PATCH 2/6] Move publ_uuids to base test class --- tests/dynamic_data/base_test.py | 9 ++++++++- .../publications/crs/maps/maps_test.py | 20 ++++++++----------- .../map_layer_relation/map_layer_relation.py | 8 ++------ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/tests/dynamic_data/base_test.py b/tests/dynamic_data/base_test.py index d5397cd8c..c8cdba7d7 100644 --- a/tests/dynamic_data/base_test.py +++ b/tests/dynamic_data/base_test.py @@ -81,6 +81,8 @@ class TestSingleRestPublication: post_before_test_scope = 'function' + publ_uuids = {} + @classmethod @final def parametrize_test_cases(cls) -> [TestCaseType]: @@ -185,8 +187,13 @@ def post_publication(cls, publication, args=None, scope='function'): else: cls.publications_to_cleanup_on_function_end.add(publication) - return process_client.publish_workspace_publication(publication.type, publication.workspace, publication.name, + resp = process_client.publish_workspace_publication(publication.type, publication.workspace, publication.name, **args) + if isinstance(resp, dict): + maybe_uuid = resp.get('uuid', None) + if maybe_uuid: + cls.publ_uuids[publication] = maybe_uuid + return resp @classmethod def ensure_publication(cls, publication, args=None, scope='function'): diff --git a/tests/dynamic_data/publications/crs/maps/maps_test.py b/tests/dynamic_data/publications/crs/maps/maps_test.py index 67f5f6e19..1a16f15ca 100644 --- a/tests/dynamic_data/publications/crs/maps/maps_test.py +++ b/tests/dynamic_data/publications/crs/maps/maps_test.py @@ -7,8 +7,8 @@ from ..... import Publication DIRECTORY = os.path.dirname(os.path.abspath(__file__)) - -LAYER_FOR_MAPS = "layer_for_map_crs" +WORKSPACE = 'dynamic_test_workspace_crs_maps' +LAYER_FOR_MAPS = Publication(WORKSPACE, process_client.LAYER_TYPE, "layer_for_map_crs") KEY_INFO_VALUES = 'info_values' KEY_THUMBNAIL_TOLERANCE = 'thumbnail_tolerance' @@ -48,7 +48,7 @@ class TestMap(base_test.TestSingleRestPublication): - workspace = 'dynamic_test_workspace_crs_maps' + workspace = WORKSPACE publication_type = process_client.MAP_TYPE @@ -61,18 +61,14 @@ class TestMap(base_test.TestSingleRestPublication): type=tests.EnumTestTypes.MANDATORY, ) for key, params in TEST_CASES.items()] - layer_uuids = {} - def before_class(self): - resp = self.post_publication(Publication(self.workspace, process_client.LAYER_TYPE, LAYER_FOR_MAPS), scope='class') - self.layer_uuids[LAYER_FOR_MAPS] = resp['uuid'] + self.post_publication(LAYER_FOR_MAPS, scope='class') def test_input_crs(self, map, key, params, rest_method): """Parametrized using pytest_generate_tests""" map_crs = key - layer_name = LAYER_FOR_MAPS map_args = { - 'map_layers': [(self.workspace, layer_name)], + 'map_layers': [(LAYER_FOR_MAPS.workspace, LAYER_FOR_MAPS.name)], 'native_extent': params[KEY_INFO_VALUES]['exp_publication_detail']['native_bounding_box'], 'crs': map_crs, 'title': map.name, @@ -84,10 +80,10 @@ def test_input_crs(self, map, key, params, rest_method): 'native_crs': map_crs, 'title': map.name, '_map_layers': [{ - 'name': LAYER_FOR_MAPS, - 'workspace': self.workspace, + 'name': LAYER_FOR_MAPS.name, + 'workspace': LAYER_FOR_MAPS.workspace, 'index': 1, - 'uuid': self.layer_uuids[LAYER_FOR_MAPS], + 'uuid': self.publ_uuids[LAYER_FOR_MAPS], }], **params.get(KEY_INFO_VALUES, {}).get('exp_publication_detail', {}) } diff --git a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py index 2c72f3908..cbafbd200 100644 --- a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py +++ b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py @@ -77,10 +77,8 @@ class TestPublication(base_test.TestSingleRestPublication): type=EnumTestTypes.MANDATORY, ) for key, params in TEST_CASES.items()] - publ_uuids = {} - def before_class(self): - resp = self.post_publication(LAYER_HRANICE, args={ + self.post_publication(LAYER_HRANICE, args={ 'file_paths': [ 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.cpg', 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.dbf', @@ -89,12 +87,10 @@ def before_class(self): 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.shx', ], }, scope='class') - self.publ_uuids[LAYER_HRANICE] = resp['uuid'] - resp = self.post_publication(MAP_HRANICE, args={ + self.post_publication(MAP_HRANICE, args={ 'file_paths': [os.path.join(DIRECTORY, 'internal_hranice.json')], }, scope='class') - self.publ_uuids[MAP_HRANICE] = resp['uuid'] def assert_exp_map_layers(self, map, exp_map_layers, exp_operates_on): with app.app_context(): From 7a952411c79d1ad96438e928a6b9c10003382e98 Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Tue, 12 Sep 2023 13:14:50 +0200 Subject: [PATCH 3/6] Change key order in map_layer_relation.py --- .../map_layer_relation/map_layer_relation.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py index cbafbd200..f7735264f 100644 --- a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py +++ b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py @@ -22,15 +22,15 @@ TEST_CASES = { 'post': { - 'rest_method': base_test_classes.RestMethodAll.POST, - 'rest_args': { - 'file_paths': [os.path.join(DIRECTORY, 'internal_wms_and_wfs.json')], - }, 'post_before_test_args': {}, 'exp_before_rest_method': { 'map_layers': None, 'operates_on': None, }, + 'rest_method': base_test_classes.RestMethodAll.POST, + 'rest_args': { + 'file_paths': [os.path.join(DIRECTORY, 'internal_wms_and_wfs.json')], + }, 'exp_after_rest_method': { 'map_layers': { # layer, layer index, exists? @@ -42,8 +42,6 @@ }, }, 'delete': { - 'rest_method': base_test_classes.RestMethodAll.DELETE, - 'rest_args': {}, 'post_before_test_args': { 'file_paths': [os.path.join(DIRECTORY, 'internal_wms_and_wfs.json')], }, @@ -55,6 +53,8 @@ }, 'operates_on': [LAYER_HRANICE], }, + 'rest_method': base_test_classes.RestMethodAll.DELETE, + 'rest_args': {}, 'exp_after_rest_method': { 'map_layers': None, 'operates_on': None, From 97e40999bb419d7619200c996eff7253a209d766 Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Tue, 12 Sep 2023 20:02:54 +0200 Subject: [PATCH 4/6] Enable to use actor_name in process_client.py --- test_tools/process_client.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/test_tools/process_client.py b/test_tools/process_client.py index b38bc3ea1..d03b887d4 100644 --- a/test_tools/process_client.py +++ b/test_tools/process_client.py @@ -172,6 +172,7 @@ def patch_workspace_publication(publication_type, file_paths=None, external_table_uri=None, headers=None, + actor_name=None, access_rights=None, title=None, style_file=None, @@ -189,6 +190,8 @@ def patch_workspace_publication(publication_type, skip_asserts=False, ): headers = headers or {} + if actor_name: + assert TOKEN_HEADER not in headers publication_type_def = PUBLICATION_TYPES_DEF[publication_type] if not skip_asserts: @@ -210,6 +213,9 @@ def patch_workspace_publication(publication_type, # Compress settings can be used only with compress option assert not compress_settings or compress + if actor_name and actor_name != settings.ANONYM_USER: + headers.update(get_authz_headers(actor_name)) + file_paths = [] if file_paths is None and not map_layers else file_paths with app.app_context(): @@ -325,6 +331,7 @@ def publish_workspace_publication(publication_type, file_paths=None, external_table_uri=None, headers=None, + actor_name=None, access_rights=None, title=None, style_file=None, @@ -344,6 +351,8 @@ def publish_workspace_publication(publication_type, ): title = title or name headers = headers or {} + if actor_name: + assert TOKEN_HEADER not in headers publication_type_def = PUBLICATION_TYPES_DEF[publication_type] assert not map_layers or not file_paths @@ -364,6 +373,9 @@ def publish_workspace_publication(publication_type, assert not (time_regex and publication_type == MAP_TYPE) + if actor_name and actor_name != settings.ANONYM_USER: + headers.update(get_authz_headers(actor_name)) + with app.app_context(): r_url = url_for(publication_type_def.post_workspace_publication_url, workspace=workspace) @@ -557,7 +569,14 @@ def assert_workspace_publications(publication_type, workspace, expected_publicat assert_workspace_maps = partial(assert_workspace_publications, MAP_TYPE) -def get_workspace_publication_metadata_comparison(publication_type, workspace, name, headers=None): +def get_workspace_publication_metadata_comparison(publication_type, workspace, name, headers=None, actor_name=None): + headers = headers or {} + if actor_name: + assert TOKEN_HEADER not in headers + + if actor_name and actor_name != settings.ANONYM_USER: + headers.update(get_authz_headers(actor_name)) + publication_type_def = PUBLICATION_TYPES_DEF[publication_type] with app.app_context(): r_url = url_for(publication_type_def.get_workspace_metadata_comparison_url, **{publication_type_def.url_param_name: name}, workspace=workspace) From 5c1e296ca4bf5394af18678cb9e2c9b79432e8a1 Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Tue, 12 Sep 2023 20:26:09 +0200 Subject: [PATCH 5/6] Test map with private layer in map_layer_relation.py --- test_tools/process.py | 1 + tests/asserts/final/publication/metadata.py | 8 ++- .../internal_hranice_private.json | 57 +++++++++++++++++++ .../map_layer_relation/map_layer_relation.py | 51 +++++++++++++++-- tests/static_data/__init__.py | 35 ------------ .../multi_publications/__init__.py | 0 .../multi_publications/publications_test.py | 23 -------- .../single_publication/layers_test.py | 1 + .../single_publication/maps_test.py | 41 ------------- 9 files changed, 109 insertions(+), 108 deletions(-) create mode 100644 tests/dynamic_data/publications/map_layer_relation/internal_hranice_private.json delete mode 100644 tests/static_data/multi_publications/__init__.py delete mode 100644 tests/static_data/multi_publications/publications_test.py delete mode 100644 tests/static_data/single_publication/maps_test.py diff --git a/test_tools/process.py b/test_tools/process.py index 60981ba12..ea87c0e91 100644 --- a/test_tools/process.py +++ b/test_tools/process.py @@ -69,6 +69,7 @@ def oauth2_provider_mock(): 'dynamic_test_workspace_geoserver_proxy_user_2': None, 'dynamic_test_layer_patch_without_data_user': None, 'test_fix_issuer_id_user': None, + 'layer_map_relation_user': None, }, }, 'host': '0.0.0.0', diff --git a/tests/asserts/final/publication/metadata.py b/tests/asserts/final/publication/metadata.py index d8f9219d7..622b1f0b1 100644 --- a/tests/asserts/final/publication/metadata.py +++ b/tests/asserts/final/publication/metadata.py @@ -53,14 +53,16 @@ def expected_values_in_micka_metadata(workspace, publ_type, name, expected_value ) -def correct_values_in_metadata(workspace, publ_type, name, http_method, *, exp_values=None): +def correct_values_in_metadata(workspace, publ_type, name, http_method, *, exp_values=None, actor_name=None): exp_values = exp_values or {} + actor_name = actor_name or settings.ANONYM_USER md_props = { process_client.LAYER_TYPE: LAYER_METADATA_PROPERTIES, process_client.MAP_TYPE: MAP_METADATA_PROPERTIES, }[publ_type] with app.app_context(): - resp_json = process_client.get_workspace_publication_metadata_comparison(publ_type, workspace, name,) + resp_json = process_client.get_workspace_publication_metadata_comparison(publ_type, workspace, name, + actor_name=actor_name) assert md_props.issubset(set(resp_json['metadata_properties'].keys())) for key, value in resp_json['metadata_properties'].items(): assert value['equal_or_null'] is True, f'key={key}, value={value}' @@ -68,7 +70,7 @@ def correct_values_in_metadata(workspace, publ_type, name, http_method, *, exp_v get_template_path_and_values_method, args = { process_client.LAYER_TYPE: (layer_csw_util.get_template_path_and_values, {}), - process_client.MAP_TYPE: (map_csw_util.get_template_path_and_values, {'actor_name': settings.ANONYM_USER}), + process_client.MAP_TYPE: (map_csw_util.get_template_path_and_values, {'actor_name': actor_name}), }[publ_type] with app.app_context(): _, md_values = get_template_path_and_values_method(workspace, name, http_method=http_method, **args) diff --git a/tests/dynamic_data/publications/map_layer_relation/internal_hranice_private.json b/tests/dynamic_data/publications/map_layer_relation/internal_hranice_private.json new file mode 100644 index 000000000..40ccf41c4 --- /dev/null +++ b/tests/dynamic_data/publications/map_layer_relation/internal_hranice_private.json @@ -0,0 +1,57 @@ +{ + "describedBy": "https://raw.githubusercontent.com/hslayers/map-compositions/2.0.0/schema.json", + "schema_version": "2.0.0", + "abstract": "World places and boundaries abstract", + "title": "World places and boundaries", + "extent": [ + -35.0, + -48.5, + 179, + 81.5 + ], + "nativeExtent": [ + -3896182.18, + -6190443.81, + 19926188.85, + 16579785.82 + ], + "projection": "epsg:3857", + "layers": [ + { + "metadata": {}, + "visibility": true, + "opacity": 1, + "title": "Defini\u010dn\u00ed body administrativn\u00edch celk\u016f", + "className": "HSLayers.Layer.WMS", + "singleTile": true, + "wmsMaxScale": 0, + "legends": [ + "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26version%3D1.3.0%26service%3DWMS%26request%3DGetLegendGraphic%26sld_version%3D1.1.0%26layer%3Ddefinicni_body_administrativnich_celku%26format%3Dimage%2Fpng%26STYLE%3Ddefault" + ], + "maxResolution": null, + "minResolution": 0, + "url": "https%3A%2F%2Fgeoportal.kraj-lbc.cz%2Fcgi-bin%2Fmapserv%3Fmap%3D%2Fdata%2Fgis%2FMapServer%2Fprojects%2Fwms%2Fatlas%2Fadministrativni_cleneni.map%26", + "params": { + "LAYERS": "definicni_body_administrativnich_celku", + "INFO_FORMAT": "application\/vnd.ogc.gml", + "FORMAT": "image\/png", + "FROMCRS": "EPSG:3857", + "VERSION": "1.3.0" + }, + "dimensions": {} + }, + { + "metadata": {}, + "visibility": true, + "opacity": 1, + "title": "Hranice", + "className": "HSLayers.Layer.WMS", + "singleTile": true, + "url": "http://localhost:8000/geoserver/layer_map_relation_user_wms/ows", + "params": { + "LAYERS": "hranice_private", + "FORMAT": "image\/png" + } + } + ] +} diff --git a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py index f7735264f..59964b39b 100644 --- a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py +++ b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py @@ -1,6 +1,8 @@ import os +import pytest + from layman import app -from layman.common import REQUEST_METHOD_POST +from layman.common import REQUEST_METHOD_POST, REQUEST_METHOD_PATCH from layman.util import get_publication_info from test_tools import process_client from tests import EnumTestTypes, Publication @@ -14,8 +16,10 @@ DIRECTORY = os.path.dirname(os.path.abspath(__file__)) WORKSPACE = 'layer_map_relation_workspace' +PRIVATE_WORKSPACE = 'layer_map_relation_user' LAYER_HRANICE = Publication(WORKSPACE, process_client.LAYER_TYPE, 'hranice') +LAYER_HRANICE_PRIVATE = Publication(PRIVATE_WORKSPACE, process_client.LAYER_TYPE, 'hranice_private') LAYER_MISTA_NON_EXISTENT = Publication(WORKSPACE, process_client.LAYER_TYPE, 'mista') MAP_HRANICE = Publication(WORKSPACE, process_client.MAP_TYPE, 'map_hranice') MAP_HRANICE_OPERATES_ON = [LAYER_HRANICE] @@ -60,15 +64,35 @@ 'operates_on': None, }, }, + 'patch_map_with_unauthorized_layer': { + 'post_before_test_args': { + 'file_paths': [os.path.join(DIRECTORY, 'internal_hranice_private.json')], + }, + 'exp_before_rest_method': { + 'map_layers': [(LAYER_HRANICE_PRIVATE, 1, True)], + 'operates_on': [], + }, + 'rest_method': base_test_classes.RestMethodAll.PATCH, + 'rest_args': { + 'actor_name': PRIVATE_WORKSPACE, + }, + 'exp_after_rest_method': { + 'map_layers': [(LAYER_HRANICE_PRIVATE, 1, True)], + 'operates_on': [LAYER_HRANICE_PRIVATE], + }, + }, } +@pytest.mark.usefixtures('oauth2_provider_mock') class TestPublication(base_test.TestSingleRestPublication): workspace = WORKSPACE publication_type = process_client.MAP_TYPE rest_parametrization = [] + usernames_to_reserve = [PRIVATE_WORKSPACE] + test_cases = [base_test.TestCaseType(key=key, params=params, rest_args=params['rest_args'], @@ -88,11 +112,23 @@ def before_class(self): ], }, scope='class') + self.post_publication(LAYER_HRANICE_PRIVATE, args={ + 'file_paths': [ + 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.cpg', + 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.dbf', + 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.prj', + 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.shp', + 'tmp/naturalearth/110m/cultural/ne_110m_admin_0_boundary_lines_land.shx', + ], + 'access_rights': {'read': PRIVATE_WORKSPACE, 'write': PRIVATE_WORKSPACE}, + 'actor_name': PRIVATE_WORKSPACE, + }, scope='class') + self.post_publication(MAP_HRANICE, args={ 'file_paths': [os.path.join(DIRECTORY, 'internal_hranice.json')], }, scope='class') - def assert_exp_map_layers(self, map, exp_map_layers, exp_operates_on): + def assert_exp_map_layers(self, map, exp_map_layers, exp_operates_on, http_method, actor_name): with app.app_context(): publ_info = get_publication_info(map.workspace, map.type, map.name, context={'keys': ['map_layers']}) @@ -118,7 +154,7 @@ def assert_exp_map_layers(self, map, exp_map_layers, exp_operates_on): for layer in exp_operates_on ] asserts_publ.metadata.correct_values_in_metadata( - map.workspace, map.type, map.name, http_method=REQUEST_METHOD_POST, exp_values={ + map.workspace, map.type, map.name, http_method=http_method, actor_name=actor_name, exp_values={ 'operates_on': exp_operates_on, }) @@ -138,18 +174,21 @@ def assert_exp_layer_maps(layer, map_operates_on_tuples): def test_publication(self, map, rest_method, rest_args, params): exp = params['exp_before_rest_method'] - self.assert_exp_map_layers(map, exp['map_layers'], exp['operates_on']) + self.assert_exp_map_layers(map, exp['map_layers'], exp['operates_on'], http_method=REQUEST_METHOD_POST, + actor_name=params['post_before_test_args'].get('actor_name')) self.assert_exp_layer_maps(LAYER_HRANICE, [ (MAP_HRANICE, MAP_HRANICE_OPERATES_ON), (map, exp['operates_on'] or []), ]) rest_method(map, args=rest_args) - if rest_method == self.post_publication: # pylint: disable=W0143 + if rest_method in [self.post_publication, self.patch_publication]: assert_util.is_publication_valid_and_complete(map) exp = params['exp_after_rest_method'] - self.assert_exp_map_layers(map, exp['map_layers'], exp['operates_on']) + http_method = REQUEST_METHOD_PATCH if rest_method == self.patch_publication else REQUEST_METHOD_POST # pylint: disable=W0143 + self.assert_exp_map_layers(map, exp['map_layers'], exp['operates_on'], http_method=http_method, + actor_name=rest_args.get('actor_name')) self.assert_exp_layer_maps(LAYER_HRANICE, [ (MAP_HRANICE, MAP_HRANICE_OPERATES_ON), (map, exp['operates_on'] or []), diff --git a/tests/static_data/__init__.py b/tests/static_data/__init__.py index 128aaa1c4..bd880e778 100644 --- a/tests/static_data/__init__.py +++ b/tests/static_data/__init__.py @@ -785,37 +785,6 @@ 'bbox': (3000, 3000, 5000, 5000), }, }, - (OWNER, MAP_TYPE, 'post_unauthorized_layer'): { - DEFINITION: [ - {'file_paths': ['sample/layman.map/internal_url_unauthorized_layer.json'], - 'access_rights': {'read': 'EVERYONE', - 'write': f"{OWNER},{OWNER2}", - }, - 'headers': HEADERS[OWNER], - }, - ], - TEST_DATA: { - 'layers': [(OWNER, LAYER_TYPE, 'post_private_sld'), (OWNER2, LAYER_TYPE, 'post_private_sld2'), ], - 'operates_on': {(OWNER, LAYER_TYPE, 'post_private_sld'), }, - 'users_can_write': [OWNER, OWNER2], - }, - }, - (OWNER, MAP_TYPE, 'patch_unauthorized_layer'): { - DEFINITION: [ - {'file_paths': ['sample/layman.map/internal_url_unauthorized_layer.json'], - 'access_rights': {'read': 'EVERYONE', - 'write': f"{OWNER},{OWNER2}", - }, - 'headers': HEADERS[OWNER], - }, - {'headers': HEADERS[OWNER2], } - ], - TEST_DATA: { - 'layers': [(OWNER, LAYER_TYPE, 'post_private_sld'), (OWNER2, LAYER_TYPE, 'post_private_sld2'), ], - 'operates_on': {(OWNER2, LAYER_TYPE, 'post_private_sld2'), }, - 'users_can_write': [OWNER, OWNER2], - }, - }, (WORKSPACE1, MAP_TYPE, 'test_publications_same_name_publ'): { DEFINITION: [ {}, @@ -854,9 +823,6 @@ LIST_QML_LAYERS = [(workspace, publ_type, publication) for (workspace, publ_type, publication), values in PUBLICATIONS.items() if publ_type == LAYER_TYPE and values[TEST_DATA].get('style_type') == 'qml'] -LIST_INTERNAL_MAPS = [(workspace, publ_type, publication) for (workspace, publ_type, publication), values in PUBLICATIONS.items() - if publ_type == MAP_TYPE and values[TEST_DATA].get('layers')] - WORKSPACES = {workspace for workspace, _, _ in PUBLICATIONS} assert len(WORKSPACES) > 0, WORKSPACES @@ -869,7 +835,6 @@ assert len(LIST_VECTOR_LAYERS) > 0, LIST_VECTOR_LAYERS assert len(LIST_SLD_LAYERS) > 0, LIST_SLD_LAYERS assert len(LIST_QML_LAYERS) > 0, LIST_QML_LAYERS -assert len(LIST_INTERNAL_MAPS) > 0, LIST_INTERNAL_MAPS assert any('normalized_overviews' in v[TEST_DATA] for v in PUBLICATIONS.values()) diff --git a/tests/static_data/multi_publications/__init__.py b/tests/static_data/multi_publications/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/static_data/multi_publications/publications_test.py b/tests/static_data/multi_publications/publications_test.py deleted file mode 100644 index 36d2c8b4b..000000000 --- a/tests/static_data/multi_publications/publications_test.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest -from layman import app -from layman.util import get_publication_info -from ... import static_data as data -from ..data import ensure_all_publications - - -@pytest.mark.timeout(600) -@pytest.mark.usefixtures('oauth2_provider_mock', 'ensure_layman') -def test_find_maps_containing_layer(): - ensure_all_publications() - - for l_workspace, l_type, layer in data.LIST_LAYERS: - expected_maps = {(workspace, publication) - for (workspace, publ_type, publication), values in data.PUBLICATIONS.items() - if publ_type == data.MAP_TYPE and (l_workspace, l_type, layer) in values[data.TEST_DATA].get('layers', [])} - - with app.app_context(): - result_maps = { - (mo['workspace'], mo['name']) - for mo in get_publication_info(l_workspace, l_type, layer, context={'keys': ['layer_maps']})['_layer_maps'] - } - assert result_maps == expected_maps diff --git a/tests/static_data/single_publication/layers_test.py b/tests/static_data/single_publication/layers_test.py index 9d8de3e28..efe75313d 100644 --- a/tests/static_data/single_publication/layers_test.py +++ b/tests/static_data/single_publication/layers_test.py @@ -29,6 +29,7 @@ } +@pytest.mark.timeout(600) @pytest.mark.parametrize('workspace, publ_type, publication', data.LIST_LAYERS) @pytest.mark.usefixtures('oauth2_provider_mock', 'ensure_layman') def test_info(workspace, publ_type, publication): diff --git a/tests/static_data/single_publication/maps_test.py b/tests/static_data/single_publication/maps_test.py deleted file mode 100644 index 151fc0815..000000000 --- a/tests/static_data/single_publication/maps_test.py +++ /dev/null @@ -1,41 +0,0 @@ -import json -import pytest - -from layman import app, util as layman_util -from test_tools import process_client -from ... import static_data as data -from ..data import ensure_publication - - -def assert_operates_on(workspace, mapname, expected_layers, authz_headers): - md_comparison = process_client.get_workspace_map_metadata_comparison(workspace, mapname, authz_headers) - operates_on = md_comparison['metadata_properties']['operates_on'] - assert (operates_on['equal']), json.dumps(operates_on, indent=2) - assert (operates_on['equal_or_null']), json.dumps(operates_on, indent=2) - assert len(operates_on['values'].values()) == 2 # GET Map File, CSW - - for operates_on_value in operates_on['values'].values(): - for (layer_uuid, layer_title) in expected_layers: - layer_record = next(rec for rec in operates_on_value - if rec['xlink:title'] == layer_title and layer_uuid in rec['xlink:href']) - assert layer_record, f"Layer uuid={layer_uuid}, title={layer_title} not found in operates_on value {json.dumps(operates_on_value, indent=2)}" - assert len(expected_layers) == len( - operates_on_value), f"Expected layers {expected_layers}, found {json.dumps(operates_on_value, indent=2)}" - - -@pytest.mark.parametrize('workspace, publ_type, publication', data.LIST_INTERNAL_MAPS) -@pytest.mark.usefixtures('oauth2_provider_mock', 'ensure_layman') -def test_map_with_unauthorized_layer(workspace, publ_type, publication): - ensure_publication(workspace, publ_type, publication) - - operates_on_layers = data.PUBLICATIONS[(workspace, publ_type, publication)][data.TEST_DATA]['operates_on'] - exp_operates_on = [] - for layer_workspace, layer_type, layer in operates_on_layers: - with app.app_context(): - info = layman_util.get_publication_info(layer_workspace, layer_type, layer, context={'keys': ['uuid', 'title']}) - uuid = info['uuid'] - title = info['title'] - exp_operates_on.append((uuid, title)) - - for headers in data.HEADERS.values(): - assert_operates_on(workspace, publication, exp_operates_on, authz_headers=headers) From 8d973e149987518a0677b4efbe4e90549fa26784 Mon Sep 17 00:00:00 2001 From: Jiri Kozel Date: Tue, 12 Sep 2023 20:30:34 +0200 Subject: [PATCH 6/6] Add _test postfix to map_layer_relation.py --- .../{map_layer_relation.py => map_layer_relation_test.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/dynamic_data/publications/map_layer_relation/{map_layer_relation.py => map_layer_relation_test.py} (100%) diff --git a/tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py b/tests/dynamic_data/publications/map_layer_relation/map_layer_relation_test.py similarity index 100% rename from tests/dynamic_data/publications/map_layer_relation/map_layer_relation.py rename to tests/dynamic_data/publications/map_layer_relation/map_layer_relation_test.py