• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geopython / pywps / 20381518796

19 Dec 2025 08:18PM UTC coverage: 83.74% (-0.4%) from 84.104%
20381518796

Pull #699

github

web-flow
Merge c0aa7db99 into 04f734b97
Pull Request #699: Split extra libraries and add more granular control over tests

63 of 98 new or added lines in 6 files covered. (64.29%)

5 existing lines in 1 file now uncovered.

5418 of 6470 relevant lines covered (83.74%)

0.84 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.43
/tests/test_execute.py
1
##################################################################
2
# Copyright 2018 Open Source Geospatial Foundation and others    #
3
# licensed under MIT, Please consult LICENSE.txt for details     #
4
##################################################################
5

6
from basic import TestBase
1✔
7
import pytest
1✔
8
from pywps import xml_util as etree
1✔
9
import json
1✔
10

11
import os.path
1✔
12
from pywps import Service, Process, LiteralOutput, LiteralInput,\
1✔
13
    BoundingBoxOutput, BoundingBoxInput, Format, ComplexInput, ComplexOutput, FORMATS
14
from pywps.validator.base import emptyvalidator
1✔
15
from pywps.validator.complexvalidator import validategml
1✔
16
from pywps.exceptions import InvalidParameterValue
1✔
17
from pywps import get_inputs_from_xml
1✔
18
from pywps import E, get_ElementMakerForVersion
1✔
19
from pywps.app.basic import get_xpath_ns
1✔
20
from pywps.tests import client_for, assert_response_success, assert_response_success_json
1✔
21
from pywps import configuration
1✔
22

23
from io import StringIO
1✔
24

25
netCDF4 = None
1✔
26
try:
1✔
27
    import netCDF4
1✔
28
except ImportError:
×
NEW
29
    pass
×
30

31
DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'data')
1✔
32

33
VERSION = "1.0.0"
1✔
34

35
WPS, OWS = get_ElementMakerForVersion(VERSION)
1✔
36

37
xpath_ns = get_xpath_ns(VERSION)
1✔
38

39

40
def create_ultimate_question():
1✔
41
    def handler(request, response):
1✔
42
        response.outputs['outvalue'].data = '42'
1✔
43
        return response
1✔
44

45
    return Process(handler=handler,
1✔
46
                   identifier='ultimate_question',
47
                   title='Ultimate Question',
48
                   outputs=[LiteralOutput('outvalue', 'Output Value', data_type='string')])
49

50

51
def create_greeter():
1✔
52
    def greeter(request, response):
1✔
53
        name = request.inputs['name'][0].data
1✔
54
        assert isinstance(name, str)
1✔
55
        response.outputs['message'].data = "Hello {}!".format(name)
1✔
56
        return response
1✔
57

58
    return Process(handler=greeter,
1✔
59
                   identifier='greeter',
60
                   title='Greeter',
61
                   inputs=[LiteralInput('name', 'Input name', data_type='string')],
62
                   outputs=[LiteralOutput('message', 'Output message', data_type='string')])
63

64

65
def create_translated_greeter():
1✔
66
    def greeter(request, response):
1✔
67
        name = request.inputs['name'][0].data
1✔
68
        response.outputs['message'].data = "Hello {}!".format(name)
1✔
69
        return response
1✔
70

71
    return Process(
1✔
72
        handler=greeter,
73
        identifier='greeter',
74
        title='Greeter',
75
        abstract='Say hello',
76
        inputs=[
77
            LiteralInput(
78
                'name',
79
                'Input name',
80
                data_type='string',
81
                abstract='Input description',
82
                translations={"fr-CA": {"title": "Nom", "abstract": "Description"}},
83
            )
84
        ],
85
        outputs=[
86
            LiteralOutput(
87
                'message',
88
                'Output message',
89
                data_type='string',
90
                abstract='Output description',
91
                translations={"fr-CA": {"title": "Message de retour", "abstract": "Description"}},
92
            )
93
        ],
94
        translations={"fr-CA": {"title": "Salutations", "abstract": "Dire allô"}},
95
    )
96

97

98
def create_bbox_process():
1✔
99
    def bbox_process(request, response):
1✔
100
        coords = request.inputs['mybbox'][0].data
1✔
101
        assert isinstance(coords, list)
1✔
102
        assert len(coords) == 4
1✔
103
        assert coords[0] == 15.0
1✔
104
        response.outputs['outbbox'].data = coords
1✔
105
        return response
1✔
106

107
    return Process(handler=bbox_process,
1✔
108
                   identifier='my_bbox_process',
109
                   title='Bbox process',
110
                   inputs=[BoundingBoxInput('mybbox', 'Input name', ["EPSG:4326"])],
111
                   outputs=[BoundingBoxOutput('outbbox', 'Output message', ["EPSG:4326"])])
112

113

114
def create_complex_proces(mime_type: str = 'gml'):
1✔
115
    def complex_proces(request, response):
1✔
116
        response.outputs['complex'].data = request.inputs['complex'][0].data_as_json()
1✔
117
        return response
1✔
118

119
    if mime_type == 'gml':
1✔
120
        frmt = Format(mime_type='application/gml', extension=".gml")  # this is unknown mimetype
1✔
121
    elif mime_type == 'geojson':
1✔
122
        frmt = FORMATS.GEOJSON
1✔
123
    else:
124
        raise Exception(f'Unknown mime type {mime_type}')
×
125

126
    return Process(handler=complex_proces,
1✔
127
                   identifier='my_complex_process',
128
                   title='Complex process',
129
                   inputs=[
130
                       ComplexInput(
131
                           'complex',
132
                           'Complex input',
133
                           min_occurs=0,
134
                           default="DEFAULT COMPLEX DATA",
135
                           supported_formats=[frmt])
136
                   ],
137
                   outputs=[
138
                       ComplexOutput(
139
                           'complex',
140
                           'Complex output',
141
                           supported_formats=[frmt])
142
                   ])
143

144

145
def create_complex_nc_process():
1✔
146
    def complex_proces(request, response):
1✔
147
        from pywps.dependencies import netCDF4 as nc
1✔
148
        url = request.inputs['dods'][0].url
1✔
149
        with nc.Dataset(url) as D:
1✔
150
            response.outputs['conventions'].data = D.Conventions
1✔
151

152
        response.outputs['outdods'].url = url
1✔
153
        response.outputs['ncraw'].file = os.path.join(DATA_DIR, 'netcdf', 'time.nc')
1✔
154
        response.outputs['ncraw'].data_format = FORMATS.NETCDF
1✔
155
        return response
1✔
156

157
    return Process(handler=complex_proces,
1✔
158
                   identifier='my_opendap_process',
159
                   title='Opendap process',
160
                   inputs=[
161
                       ComplexInput(
162
                           'dods',
163
                           'Opendap input',
164
                           supported_formats=[Format('DODS'), Format('NETCDF')],
165
                           #   mode=MODE.STRICT
166
                       )
167
                   ],
168
                   outputs=[
169
                       LiteralOutput(
170
                           'conventions',
171
                           'NetCDF convention',
172
                       ),
173
                       ComplexOutput('outdods', 'Opendap output',
174
                                     supported_formats=[FORMATS.DODS, ],
175
                                     as_reference=True),
176
                       ComplexOutput('ncraw', 'NetCDF raw data output',
177
                                     supported_formats=[FORMATS.NETCDF, ],
178
                                     as_reference=False)
179
                   ])
180

181

182
def create_mimetype_process():
1✔
183
    def _handler(request, response):
1✔
184
        response.outputs['mimetype'].data = response.outputs['mimetype'].data_format.mime_type
1✔
185
        return response
1✔
186

187
    frmt_txt = Format(mime_type='text/plain')
1✔
188
    frmt_txt2 = Format(mime_type='text/plain+test')
1✔
189

190
    return Process(handler=_handler,
1✔
191
                   identifier='get_mimetype_process',
192
                   title='Get mimeType process',
193
                   inputs=[],
194
                   outputs=[
195
                       ComplexOutput(
196
                           'mimetype',
197
                           'mimetype of requested output',
198
                           supported_formats=[frmt_txt, frmt_txt2])
199
                   ])
200

201

202
def create_metalink_process():
1✔
203
    from processes.metalinkprocess import MultipleOutputs
1✔
204
    return MultipleOutputs()
1✔
205

206

207
def get_output(doc):
1✔
208
    """Return the content of LiteralData, Reference or ComplexData."""
209

210
    output = {}
1✔
211
    for output_el in xpath_ns(doc, '/wps:ExecuteResponse'
1✔
212
                                   '/wps:ProcessOutputs/wps:Output'):
213
        [identifier_el] = xpath_ns(output_el, './ows:Identifier')
1✔
214

215
        lit_el = xpath_ns(output_el, './wps:Data/wps:LiteralData')
1✔
216
        if lit_el != []:
1✔
217
            output[identifier_el.text] = lit_el[0].text
1✔
218

219
        ref_el = xpath_ns(output_el, './wps:Reference')
1✔
220
        if ref_el != []:
1✔
221
            output[identifier_el.text] = ref_el[0].attrib['href']
×
222

223
        data_el = xpath_ns(output_el, './wps:Data/wps:ComplexData')
1✔
224
        if data_el != []:
1✔
225
            if data_el[0].text:
×
226
                output[identifier_el.text] = data_el[0].text
×
227
            else:  # XML children
228
                ch = list(data_el[0])[0]
×
229
                output[identifier_el.text] = etree.tostring(ch)
×
230

231
    return output
1✔
232

233

234
class ExecuteTest(TestBase):
1✔
235
    """Test for Exeucte request KVP request"""
236

237
    @pytest.mark.online
1✔
238
    @pytest.mark.requires_netcdf4
1✔
239
    @pytest.mark.skipif(netCDF4 is None, reason='netCDF4 libraries are required for this test')
1✔
240
    def test_dods(self):
1✔
241
        my_process = create_complex_nc_process()
1✔
242
        service = Service(processes=[my_process])
1✔
243

244
        href = "http://test.opendap.org:80/opendap/netcdf/examples/sresa1b_ncar_ccsm3_0_run1_200001.nc"
1✔
245

246
        """ # Is this how the request should be written ?
1✔
247
        request_doc = WPS.Execute(
248
            OWS.Identifier('my_opendap_process'),
249
            WPS.DataInputs(
250
                WPS.Input(
251
                    OWS.Identifier('dods'),
252
                    WPS.Reference(
253
                        WPS.Body('request body'),
254
                        {'{http://www.w3.org/1999/xlink}href': href},
255
                        method='POST'
256
                    )
257
                    #WPS.Data(WPS.ComplexData(href=href, mime_type='application/x-ogc-dods'))
258
                    # This form is not supported yet. Should it be ?
259
                )
260
            ),
261
            version='1.0.0'
262
        )
263
        resp = client.post_xml(doc=request_doc)
264
        assert_response_success(resp)
265
        """
266

267
        class FakeRequest():
1✔
268
            identifier = 'my_opendap_process'
1✔
269
            service = 'wps'
1✔
270
            operation = 'execute'
1✔
271
            version = '1.0.0'
1✔
272
            raw = True,
1✔
273
            inputs = {'dods': [{
1✔
274
                'identifier': 'dods',
275
                'href': href,
276
            }]}
277
            store_execute = False
1✔
278
            lineage = False
1✔
279
            outputs = ['conventions']
1✔
280
            language = "en-US"
1✔
281

282
        request = FakeRequest()
1✔
283
        resp = service.execute('my_opendap_process', request, 'fakeuuid')
1✔
284

285
        if resp.outputs["conventions"].data is None:
1✔
NEW
286
            pytest.xfail("Network is likely unavailable or test.opendap.org is offline")
×
287

288
        self.assertEqual(resp.outputs['conventions'].data, 'CF-1.0')
1✔
289
        self.assertEqual(resp.outputs['outdods'].url, href)
1✔
290
        self.assertTrue(resp.outputs['outdods'].as_reference)
1✔
291
        self.assertFalse(resp.outputs['ncraw'].as_reference)
1✔
292
        with open(os.path.join(DATA_DIR, 'netcdf', 'time.nc'), 'rb') as f:
1✔
293
            data = f.read()
1✔
294
        self.assertEqual(resp.outputs['ncraw'].data, data)
1✔
295

296
    def test_input_parser(self):
1✔
297
        """Test input parsing
298
        """
299
        my_process = create_complex_proces()
1✔
300
        service = Service(processes=[my_process])
1✔
301
        self.assertEqual(len(service.processes), 1)
1✔
302
        self.assertTrue(service.processes['my_complex_process'])
1✔
303

304
        class FakeRequest():
1✔
305
            identifier = 'complex_process'
1✔
306
            service = 'wps'
1✔
307
            operation = 'execute'
1✔
308
            version = '1.0.0'
1✔
309
            inputs = {'complex': [{
1✔
310
                'identifier': 'complex',
311
                'mimeType': 'text/gml',
312
                'data': 'the data'
313
            }]}
314
            language = "en-US"
1✔
315

316
        request = FakeRequest()
1✔
317

318
        try:
1✔
319
            service.execute('my_complex_process', request, 'fakeuuid')
1✔
320
        except InvalidParameterValue as e:
1✔
321
            self.assertEqual(e.locator, 'mimeType')
1✔
322

323
        request.inputs['complex'][0]['mimeType'] = 'application/gml'
1✔
324
        parsed_inputs = service.create_complex_inputs(my_process.inputs[0],
1✔
325
                                                      request.inputs['complex'])
326

327
        # TODO parse outputs and their validators too
328

329
        self.assertEqual(parsed_inputs[0].data_format.validate, emptyvalidator)
1✔
330

331
        request.inputs['complex'][0]['mimeType'] = 'application/xml+gml'
1✔
332
        try:
1✔
333
            parsed_inputs = service.create_complex_inputs(my_process.inputs[0],
1✔
334
                                                          request.inputs['complex'])
335
        except InvalidParameterValue as e:
1✔
336
            self.assertEqual(e.locator, 'mimeType')
1✔
337

338
        try:
1✔
339
            my_process.inputs[0].data_format = Format(mime_type='application/xml+gml')
1✔
340
        except InvalidParameterValue as e:
1✔
341
            self.assertEqual(e.locator, 'mimeType')
1✔
342

343
        frmt = Format(mime_type='application/xml+gml', validate=validategml)
1✔
344
        self.assertEqual(frmt.validate, validategml)
1✔
345

346
        my_process.inputs[0].supported_formats = [frmt]
1✔
347
        my_process.inputs[0].data_format = Format(mime_type='application/xml+gml')
1✔
348
        parsed_inputs = service.create_complex_inputs(my_process.inputs[0],
1✔
349
                                                      request.inputs['complex'])
350

351
        self.assertEqual(parsed_inputs[0].data_format.validate, validategml)
1✔
352

353
    def test_input_default(self):
1✔
354
        """Test input parsing
355
        """
356
        my_process = create_complex_proces()
1✔
357
        service = Service(processes=[my_process])
1✔
358
        self.assertEqual(len(service.processes), 1)
1✔
359
        self.assertTrue(service.processes['my_complex_process'])
1✔
360

361
        class FakeRequest():
1✔
362
            identifier = 'complex_process'
1✔
363
            service = 'wps'
1✔
364
            operation = 'execute'
1✔
365
            version = '1.0.0'
1✔
366
            inputs = {}
1✔
367
            raw = False
1✔
368
            outputs = {}
1✔
369
            store_execute = False
1✔
370
            lineage = False
1✔
371
            language = "en-US"
1✔
372

373
        request = FakeRequest()
1✔
374
        response = service.execute('my_complex_process', request, 'fakeuuid')
1✔
375
        self.assertEqual(response.outputs['complex'].data, 'DEFAULT COMPLEX DATA')
1✔
376

377
    def test_output_mimetype(self):
1✔
378
        """Test input parsing
379
        """
380
        my_process = create_mimetype_process()
1✔
381
        service = Service(processes=[my_process])
1✔
382
        self.assertEqual(len(service.processes), 1)
1✔
383
        self.assertTrue(service.processes['get_mimetype_process'])
1✔
384

385
        class FakeRequest():
1✔
386
            def __init__(self, mimetype):
1✔
387
                self.outputs = {'mimetype': {
1✔
388
                    'identifier': 'mimetype',
389
                    'mimetype': mimetype,
390
                    'data': 'the data'
391
                }}
392

393
            identifier = 'get_mimetype_process'
1✔
394
            service = 'wps'
1✔
395
            operation = 'execute'
1✔
396
            version = '1.0.0'
1✔
397
            inputs = {}
1✔
398
            raw = False
1✔
399
            store_execute = False
1✔
400
            lineage = False
1✔
401
            language = "en-US"
1✔
402

403
        # valid mimetype
404
        request = FakeRequest('text/plain+test')
1✔
405
        response = service.execute('get_mimetype_process', request, 'fakeuuid')
1✔
406
        self.assertEqual(response.outputs['mimetype'].data, 'text/plain+test')
1✔
407

408
        # non valid mimetype
409
        request = FakeRequest('text/xml')
1✔
410
        with self.assertRaises(InvalidParameterValue):
1✔
411
            response = service.execute('get_mimetype_process', request, 'fakeuuid')
1✔
412

413
    def test_metalink(self):
1✔
414
        client = client_for(Service(processes=[create_metalink_process()]))
1✔
415
        resp = client.get('?Request=Execute&identifier=multiple-outputs')
1✔
416
        assert resp.status_code == 400
1✔
417

418
    def test_missing_process_error(self):
1✔
419
        client = client_for(Service(processes=[create_ultimate_question()]))
1✔
420
        resp = client.get('?Request=Execute&identifier=foo')
1✔
421
        assert resp.status_code == 400
1✔
422

423
    def test_get_with_no_inputs(self):
1✔
424
        client = client_for(Service(processes=[create_ultimate_question()]))
1✔
425
        resp = client.get('?service=wps&version=1.0.0&Request=Execute&identifier=ultimate_question')
1✔
426
        assert_response_success(resp)
1✔
427

428
        assert get_output(resp.xml) == {'outvalue': '42'}
1✔
429

430
    def test_post_with_no_inputs(self):
1✔
431
        request = {
1✔
432
            'identifier': 'ultimate_question',
433
            'version': '1.0.0'
434
        }
435
        result = {'outvalue': '42'}
1✔
436

437
        client = client_for(Service(processes=[create_ultimate_question()]))
1✔
438
        request_doc = WPS.Execute(
1✔
439
            OWS.Identifier(request['identifier']),
440
            version=request['version']
441
        )
442

443
        resp = client.post_xml(doc=request_doc)
1✔
444
        assert_response_success(resp)
1✔
445
        assert get_output(resp.xml) == result
1✔
446

447
        resp = client.post_json(doc=request)
1✔
448
        assert_response_success_json(resp, result)
1✔
449

450
    def test_post_with_string_input(self):
1✔
451
        request = {
1✔
452
            'identifier': 'greeter',
453
            'version': '1.0.0',
454
            'inputs': {
455
                'name': 'foo'
456
            },
457
        }
458
        result = {'message': "Hello foo!"}
1✔
459

460
        client = client_for(Service(processes=[create_greeter()]))
1✔
461
        request_doc = WPS.Execute(
1✔
462
            OWS.Identifier(request['identifier']),
463
            WPS.DataInputs(
464
                WPS.Input(
465
                    OWS.Identifier('name'),
466
                    WPS.Data(WPS.LiteralData(request['inputs']['name']))
467
                )
468
            ),
469
            version=request['version']
470
        )
471
        resp = client.post_xml(doc=request_doc)
1✔
472
        assert_response_success(resp)
1✔
473
        assert get_output(resp.xml) == result
1✔
474

475
        resp = client.post_json(doc=request)
1✔
476
        assert_response_success_json(resp, result)
1✔
477

478
    def test_bbox(self):
1✔
479
        client = client_for(Service(processes=[create_bbox_process()]))
1✔
480
        request_doc = WPS.Execute(
1✔
481
            OWS.Identifier('my_bbox_process'),
482
            WPS.DataInputs(
483
                WPS.Input(
484
                    OWS.Identifier('mybbox'),
485
                    WPS.Data(WPS.BoundingBoxData(
486
                        OWS.LowerCorner('15.0 50.0'),
487
                        OWS.UpperCorner('16.0 51.0'),
488
                    ))
489
                )
490
            ),
491
            version='1.0.0'
492
        )
493
        resp = client.post_xml(doc=request_doc)
1✔
494
        assert_response_success(resp)
1✔
495

496
        [output] = xpath_ns(resp.xml, '/wps:ExecuteResponse'
1✔
497
                                      '/wps:ProcessOutputs/wps:Output')
498
        self.assertEqual('outbbox', xpath_ns(
1✔
499
            output,
500
            './ows:Identifier')[0].text)
501

502
        lower_corner = xpath_ns(output, './wps:Data/wps:BoundingBoxData/ows:LowerCorner')[0].text
1✔
503
        lower_corner = lower_corner.strip().replace('  ', ' ')
1✔
504
        self.assertEqual('15.0 50.0', lower_corner)
1✔
505

506
        upper_corner = xpath_ns(output, './wps:Data/wps:BoundingBoxData/ows:UpperCorner')[0].text
1✔
507
        upper_corner = upper_corner.strip().replace('  ', ' ')
1✔
508
        self.assertEqual('16.0 51.0', upper_corner)
1✔
509

510
    def test_bbox_rest(self):
1✔
511
        client = client_for(Service(processes=[create_bbox_process()]))
1✔
512
        bbox = [15.0, 50.0, 16.0, 51.0]
1✔
513
        request = dict(
1✔
514
            identifier='my_bbox_process',
515
            version='1.0.0',
516
            inputs={
517
                'mybbox': {
518
                    "type": "bbox",
519
                    'bbox': bbox,
520
                }
521
            },
522
        )
523
        result = {'outbbox': bbox}
1✔
524

525
        resp = client.post_json(doc=request)
1✔
526
        assert_response_success_json(resp, result)
1✔
527

528
    def test_geojson_input_rest(self):
1✔
529
        geojson = os.path.join(DATA_DIR, 'json', 'point.geojson')
1✔
530
        with open(geojson) as f:
1✔
531
            p = json.load(f)
1✔
532

533
        my_process = create_complex_proces('geojson')
1✔
534
        client = client_for(Service(processes=[my_process]))
1✔
535

536
        request = dict(
1✔
537
            identifier='my_complex_process',
538
            version='1.0.0',
539
            inputs={
540
                'complex': {
541
                    "type": "complex",
542
                    'data': p
543
                }
544
            },
545
        )
546
        result = {'complex': p}
1✔
547

548
        resp = client.post_json(doc=request)
1✔
549
        assert_response_success_json(resp, result)
1✔
550

551
    def test_output_response_dataType(self):
1✔
552
        client = client_for(Service(processes=[create_greeter()]))
1✔
553
        request_doc = WPS.Execute(
1✔
554
            OWS.Identifier('greeter'),
555
            WPS.DataInputs(
556
                WPS.Input(
557
                    OWS.Identifier('name'),
558
                    WPS.Data(WPS.LiteralData('foo'))
559
                )
560
            ),
561
            version='1.0.0'
562
        )
563
        resp = client.post_xml(doc=request_doc)
1✔
564
        el = next(resp.xml.iter('{http://www.opengis.net/wps/1.0.0}LiteralData'))
1✔
565
        assert el.attrib['dataType'] == 'string'
1✔
566

567

568
class AllowedInputReferenceExecuteTest(TestBase):
1✔
569

570
    def setUp(self):
1✔
571
        super().setUp()
1✔
572
        self.allowedinputpaths = configuration.get_config_value('server', 'allowedinputpaths')
1✔
573
        configuration.CONFIG.set('server', 'allowedinputpaths', DATA_DIR)
1✔
574

575
    def test_geojson_input_reference_rest(self):
1✔
576
        geojson = os.path.join(DATA_DIR, 'json', 'point.geojson')
1✔
577
        with open(geojson) as f:
1✔
578
            p = json.load(f)
1✔
579

580
        my_process = create_complex_proces('geojson')
1✔
581
        client = client_for(Service(processes=[my_process]))
1✔
582

583
        request = dict(
1✔
584
            identifier='my_complex_process',
585
            version='1.0.0',
586
            inputs={
587
                'complex': {
588
                    "type": "reference",
589
                    "href": f"file:{geojson}"
590
                }
591
            },
592
        )
593
        result = {'complex': p}
1✔
594

595
        resp = client.post_json(doc=request)
1✔
596
        assert_response_success_json(resp, result)
1✔
597

598

599
class ExecuteTranslationsTest(TestBase):
1✔
600

601
    def setUp(self):
1✔
602
        super().setUp()
1✔
603
        configuration.get_config_value('server', 'language')
1✔
604
        configuration.CONFIG.set('server', 'language', 'en-US,fr-CA')
1✔
605

606
    def test_translations(self):
1✔
607
        client = client_for(Service(processes=[create_translated_greeter()]))
1✔
608

609
        request_doc = WPS.Execute(
1✔
610
            OWS.Identifier('greeter'),
611
            WPS.DataInputs(
612
                WPS.Input(
613
                    OWS.Identifier('name'),
614
                    WPS.Data(WPS.LiteralData('foo'))
615
                )
616
            ),
617
            WPS.ResponseForm(
618
                WPS.ResponseDocument(
619
                    lineage='true',
620
                )
621
            ),
622
            version='1.0.0',
623
            language='fr-CA',
624
        )
625
        resp = client.post_xml(doc=request_doc)
1✔
626

627
        assert resp.xpath('/wps:ExecuteResponse/@xml:lang')[0] == "fr-CA"
1✔
628

629
        process_title = [e.text for e in resp.xpath('//wps:Process/ows:Title')]
1✔
630
        assert process_title == ["Salutations"]
1✔
631
        process_abstract = [e.text for e in resp.xpath('//wps:Process/ows:Abstract')]
1✔
632
        assert process_abstract == ["Dire allô"]
1✔
633

634
        input_titles = [e.text for e in resp.xpath('//wps:Input/ows:Title')]
1✔
635
        assert input_titles == ["Nom"]
1✔
636
        input_abstract = [e.text for e in resp.xpath('//wps:Input/ows:Abstract')]
1✔
637
        assert input_abstract == ["Description"]
1✔
638

639
        output_titles = [e.text for e in resp.xpath('//wps:OutputDefinitions/wps:Output/ows:Title')]
1✔
640
        assert output_titles == ["Message de retour"]
1✔
641
        output_abstract = [e.text for e in resp.xpath('//wps:OutputDefinitions/wps:Output/ows:Abstract')]
1✔
642
        assert output_abstract == ["Description"]
1✔
643

644
        output_titles = [e.text for e in resp.xpath('//wps:ProcessOutputs/wps:Output/ows:Title')]
1✔
645
        assert output_titles == ["Message de retour"]
1✔
646
        output_abstract = [e.text for e in resp.xpath('//wps:ProcessOutputs/wps:Output/ows:Abstract')]
1✔
647
        assert output_abstract == ["Description"]
1✔
648

649

650
class ExecuteXmlParserTest(TestBase):
1✔
651
    """Tests for Execute request XML Parser
652
    """
653

654
    def test_empty(self):
1✔
655
        request_doc = WPS.Execute(OWS.Identifier('foo'))
1✔
656
        assert get_inputs_from_xml(request_doc) == {}
1✔
657

658
    def test_one_string(self):
1✔
659
        request_doc = WPS.Execute(
1✔
660
            OWS.Identifier('foo'),
661
            WPS.DataInputs(
662
                WPS.Input(
663
                    OWS.Identifier('name'),
664
                    WPS.Data(WPS.LiteralData('foo'))),
665
                WPS.Input(
666
                    OWS.Identifier('name'),
667
                    WPS.Data(WPS.LiteralData('bar')))
668
            ))
669
        rv = get_inputs_from_xml(request_doc)
1✔
670
        self.assertTrue('name' in rv)
1✔
671
        self.assertEqual(len(rv['name']), 2)
1✔
672
        self.assertEqual(rv['name'][0]['data'], 'foo')
1✔
673
        self.assertEqual(rv['name'][1]['data'], 'bar')
1✔
674

675
    def test_two_strings(self):
1✔
676
        request_doc = WPS.Execute(
1✔
677
            OWS.Identifier('foo'),
678
            WPS.DataInputs(
679
                WPS.Input(
680
                    OWS.Identifier('name1'),
681
                    WPS.Data(WPS.LiteralData('foo'))),
682
                WPS.Input(
683
                    OWS.Identifier('name2'),
684
                    WPS.Data(WPS.LiteralData('bar')))))
685
        rv = get_inputs_from_xml(request_doc)
1✔
686
        self.assertEqual(rv['name1'][0]['data'], 'foo')
1✔
687
        self.assertEqual(rv['name2'][0]['data'], 'bar')
1✔
688

689
    def test_complex_input(self):
1✔
690
        the_data = E.TheData("hello world")
1✔
691
        request_doc = WPS.Execute(
1✔
692
            OWS.Identifier('foo'),
693
            WPS.DataInputs(
694
                WPS.Input(
695
                    OWS.Identifier('name'),
696
                    WPS.Data(
697
                        WPS.ComplexData(the_data, mimeType='text/foobar')))))
698
        rv = get_inputs_from_xml(request_doc)
1✔
699
        self.assertEqual(rv['name'][0]['mimeType'], 'text/foobar')
1✔
700
        rv_doc = etree.parse(StringIO(rv['name'][0]['data'])).getroot()
1✔
701
        self.assertEqual(rv_doc.tag, 'TheData')
1✔
702
        self.assertEqual(rv_doc.text, 'hello world')
1✔
703

704
    def test_complex_input_raw_value(self):
1✔
705
        the_data = '{ "plot":{ "Version" : "0.1" } }'
1✔
706

707
        request_doc = WPS.Execute(
1✔
708
            OWS.Identifier('foo'),
709
            WPS.DataInputs(
710
                WPS.Input(
711
                    OWS.Identifier('json'),
712
                    WPS.Data(
713
                        WPS.ComplexData(the_data, mimeType='application/json')))))
714
        rv = get_inputs_from_xml(request_doc)
1✔
715
        self.assertEqual(rv['json'][0]['mimeType'], 'application/json')
1✔
716
        json_data = json.loads(rv['json'][0]['data'])
1✔
717
        self.assertEqual(json_data['plot']['Version'], '0.1')
1✔
718

719
    def test_complex_input_base64_value(self):
1✔
720
        the_data = 'eyAicGxvdCI6eyAiVmVyc2lvbiIgOiAiMC4xIiB9IH0='
1✔
721

722
        request_doc = WPS.Execute(
1✔
723
            OWS.Identifier('foo'),
724
            WPS.DataInputs(
725
                WPS.Input(
726
                    OWS.Identifier('json'),
727
                    WPS.Data(
728
                        WPS.ComplexData(the_data,
729
                                        encoding='base64',
730
                                        mimeType='application/json')))))
731
        rv = get_inputs_from_xml(request_doc)
1✔
732
        self.assertEqual(rv['json'][0]['mimeType'], 'application/json')
1✔
733
        json_data = json.loads(rv['json'][0]['data'].decode())
1✔
734
        self.assertEqual(json_data['plot']['Version'], '0.1')
1✔
735

736
    def test_bbox_input(self):
1✔
737
        request_doc = WPS.Execute(
1✔
738
            OWS.Identifier('request'),
739
            WPS.DataInputs(
740
                WPS.Input(
741
                    OWS.Identifier('bbox'),
742
                    WPS.Data(
743
                        WPS.BoundingBoxData(
744
                            OWS.LowerCorner('40 50'),
745
                            OWS.UpperCorner('60 70'))))))
746
        rv = get_inputs_from_xml(request_doc)
1✔
747
        bbox = rv['bbox'][0]
1✔
748
        # assert isinstance(bbox, BoundingBox)
749
        assert bbox['data'] == ['40', '50', '60', '70']
1✔
750
        # assert bbox.minx == '40'
751
        # assert bbox.miny == '50'
752
        # assert bbox.maxx == '60'
753
        # assert bbox.maxy == '70'
754

755
    def test_reference_post_input(self):
1✔
756
        request_doc = WPS.Execute(
1✔
757
            OWS.Identifier('foo'),
758
            WPS.DataInputs(
759
                WPS.Input(
760
                    OWS.Identifier('name'),
761
                    WPS.Reference(
762
                        WPS.Body('request body'),
763
                        {'{http://www.w3.org/1999/xlink}href': 'http://foo/bar/service'},
764
                        method='POST'
765
                    )
766
                )
767
            )
768
        )
769
        rv = get_inputs_from_xml(request_doc)
1✔
770
        self.assertEqual(rv['name'][0]['href'], 'http://foo/bar/service')
1✔
771
        self.assertEqual(rv['name'][0]['method'], 'POST')
1✔
772
        self.assertEqual(rv['name'][0]['body'], 'request body')
1✔
773

774
    def test_reference_post_bodyreference_input(self):
1✔
775
        request_doc = WPS.Execute(
1✔
776
            OWS.Identifier('foo'),
777
            WPS.DataInputs(
778
                WPS.Input(
779
                    OWS.Identifier('name'),
780
                    WPS.Reference(
781
                        WPS.BodyReference(
782
                            {'{http://www.w3.org/1999/xlink}href': 'http://foo/bar/reference'}),
783
                        {'{http://www.w3.org/1999/xlink}href': 'http://foo/bar/service'},
784
                        method='POST'
785
                    )
786
                )
787
            )
788
        )
789
        rv = get_inputs_from_xml(request_doc)
1✔
790
        self.assertEqual(rv['name'][0]['href'], 'http://foo/bar/service')
1✔
791
        self.assertEqual(rv['name'][0]['bodyreference'], 'http://foo/bar/reference')
1✔
792

793
    def test_build_input_file_name(self):
1✔
794
        from pywps.inout.basic import ComplexInput
1✔
795

796
        h = ComplexInput('ci')
1✔
797
        h.workdir = workdir = configuration.get_config_value('server', 'workdir')
1✔
798

799
        self.assertEqual(
1✔
800
            h._build_file_name('http://path/to/test.txt'),
801
            os.path.join(workdir, 'test.txt'))
802
        self.assertEqual(
1✔
803
            h._build_file_name('http://path/to/test'),
804
            os.path.join(workdir, 'test'))
805
        self.assertEqual(
1✔
806
            h._build_file_name('file://path/to/.config'),
807
            os.path.join(workdir, '.config'))
808
        self.assertEqual(
1✔
809
            h._build_file_name('https://path/to/test.txt?token=abc&expires_at=1234567'),
810
            os.path.join(workdir, 'test.txt'))
811

812
        h.supported_formats = [FORMATS.TEXT, ]
1✔
813
        h.data_format = FORMATS.TEXT
1✔
814
        self.assertEqual(
1✔
815
            h._build_file_name('http://path/to/test'),
816
            os.path.join(workdir, 'test.txt'))
817

818
        open(os.path.join(workdir, 'duplicate.html'), 'a').close()
1✔
819
        inpt_filename = h._build_file_name('http://path/to/duplicate.html')
1✔
820
        self.assertTrue(inpt_filename.startswith(os.path.join(workdir, 'duplicate_')))
1✔
821
        self.assertTrue(inpt_filename.endswith('.html'))
1✔
822

823

824
def load_tests(loader=None, tests=None, pattern=None):
1✔
825
    import unittest
×
826

827
    if not loader:
×
828
        loader = unittest.TestLoader()
×
829
    suite_list = [
×
830
        loader.loadTestsFromTestCase(ExecuteTest),
831
        loader.loadTestsFromTestCase(ExecuteTranslationsTest),
832
        loader.loadTestsFromTestCase(ExecuteXmlParserTest),
833
    ]
834
    return unittest.TestSuite(suite_list)
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc