1
+ """ Test the pyodata integration with httpx client
2
+
3
+ - it provided sync, requests like interface
4
+ - it provides asyncio interface as well - FOCUS OF THIS TEST MODULE
5
+
6
+ https://www.python-httpx.org/
7
+ """
8
+
9
+ import httpx
10
+ from httpx import Response
11
+ import respx
12
+ import pytest
13
+
14
+ import pyodata .v2 .service
15
+ from pyodata import Client
16
+ from pyodata .exceptions import PyODataException , HttpError
17
+ from pyodata .v2 .model import ParserError , PolicyWarning , PolicyFatal , PolicyIgnore , Config
18
+
19
+ SERVICE_URL = 'http://example.com'
20
+
21
+ def test_invalid_odata_version ():
22
+ """Check handling of request for invalid OData version implementation"""
23
+
24
+ with pytest .raises (PyODataException ) as e_info :
25
+ pyodata .Client (SERVICE_URL , httpx , 'INVALID VERSION' )
26
+
27
+ assert str (e_info .value ).startswith ('No implementation for selected odata version' )
28
+
29
+
30
+ def test_create_client_for_local_metadata (metadata ):
31
+ """Check client creation for valid use case with local metadata"""
32
+
33
+ client = pyodata .Client (SERVICE_URL , httpx , metadata = metadata )
34
+
35
+ assert isinstance (client , pyodata .v2 .service .Service )
36
+ assert client .schema .is_valid == True
37
+ assert len (client .schema .entity_sets ) != 0
38
+
39
+
40
+ @pytest .mark .parametrize ("content_type" , ['application/xml' , 'application/atom+xml' , 'text/xml' ])
41
+ def test_create_service_application (respx_mock , metadata , content_type ):
42
+ """Check client creation for valid MIME types"""
43
+
44
+ # Note: respx_mock is provided by respx package as pytest helper
45
+ headers = httpx .Headers (
46
+ {'Content-Type' : content_type }
47
+ )
48
+
49
+ respx_mock .get (f"{ SERVICE_URL } /$metadata" ).mock (
50
+ return_value = Response (status_code = 200 ,
51
+ content = metadata ,
52
+ headers = headers ,
53
+ )
54
+ )
55
+
56
+ client = pyodata .Client (SERVICE_URL , httpx )
57
+ assert isinstance (client , pyodata .v2 .service .Service )
58
+
59
+ # one more test for '/' terminated url
60
+ client = pyodata .Client (SERVICE_URL + '/' , httpx )
61
+ assert isinstance (client , pyodata .v2 .service .Service )
62
+ assert client .schema .is_valid
63
+
64
+
65
+ def test_metadata_not_reachable (respx_mock ):
66
+ """Check handling of not reachable service metadata"""
67
+
68
+ headers = httpx .Headers (
69
+ {'Content-Type' : 'text/html' }
70
+ )
71
+
72
+ respx_mock .get (f"{ SERVICE_URL } /$metadata" ).mock (
73
+ return_value = Response (status_code = 404 ,
74
+ headers = headers ,
75
+ )
76
+ )
77
+
78
+ with pytest .raises (HttpError ) as e_info :
79
+ pyodata .Client (SERVICE_URL , httpx )
80
+
81
+ assert str (e_info .value ).startswith ('Metadata request failed' )
82
+
83
+
84
+ def test_metadata_saml_not_authorized (respx_mock ):
85
+ """Check handling of not SAML / OAuth unauthorized response"""
86
+
87
+ headers = httpx .Headers (
88
+ {'Content-Type' : 'text/html; charset=utf-8' }
89
+ )
90
+
91
+ respx_mock .get (f"{ SERVICE_URL } /$metadata" ).mock (
92
+ return_value = Response (status_code = 200 ,
93
+ headers = headers ,
94
+ )
95
+ )
96
+
97
+ with pytest .raises (HttpError ) as e_info :
98
+ pyodata .Client (SERVICE_URL , httpx )
99
+
100
+ assert str (e_info .value ).startswith ('Metadata request did not return XML, MIME type:' )
101
+
102
+
103
+ def test_client_custom_configuration (respx_mock ,metadata ):
104
+ """Check client creation for custom configuration"""
105
+
106
+ headers = httpx .Headers (
107
+ {'Content-Type' : 'application/xml' }
108
+ )
109
+
110
+ respx_mock .get (f"{ SERVICE_URL } /$metadata" ).mock (
111
+ return_value = Response (status_code = 200 ,
112
+ headers = headers ,
113
+ content = metadata ,
114
+ )
115
+ )
116
+
117
+ namespaces = {
118
+ 'edmx' : "customEdmxUrl.com" ,
119
+ 'edm' : 'customEdmUrl.com'
120
+ }
121
+
122
+ custom_config = Config (
123
+ xml_namespaces = namespaces ,
124
+ default_error_policy = PolicyFatal (),
125
+ custom_error_policies = {
126
+ ParserError .ANNOTATION : PolicyWarning (),
127
+ ParserError .ASSOCIATION : PolicyIgnore ()
128
+ })
129
+
130
+ with pytest .raises (PyODataException ) as e_info :
131
+ client = pyodata .Client (SERVICE_URL , httpx , config = custom_config , namespaces = namespaces )
132
+
133
+ assert str (e_info .value ) == 'You cannot pass namespaces and config at the same time'
134
+
135
+ with pytest .warns (DeprecationWarning ,match = 'Passing namespaces directly is deprecated. Use class Config instead' ):
136
+ client = pyodata .Client (SERVICE_URL , httpx , namespaces = namespaces )
137
+
138
+ assert isinstance (client , pyodata .v2 .service .Service )
139
+ assert client .schema .config .namespaces == namespaces
140
+
141
+ client = pyodata .Client (SERVICE_URL , httpx , config = custom_config )
142
+
143
+ assert isinstance (client , pyodata .v2 .service .Service )
144
+ assert client .schema .config == custom_config
0 commit comments