1
1
# coding=utf-8
2
2
"""Define basic fixtures."""
3
3
4
+ import os
5
+
4
6
# First patch httplib
5
- try :
6
- from ddtrace import config , patch , tracer
7
+ tracer = None
8
+ if "false" != os .getenv ("RECORD" , "false" ):
9
+ try :
10
+ from ddtrace import config , patch , tracer
7
11
8
- config .httplib ["distributed_tracing" ] = True
9
- patch (httplib = True )
10
- except ImportError :
11
- tracer = None
12
+ config .httplib ["distributed_tracing" ] = True
13
+ patch (httplib = True )
14
+ except ImportError :
15
+ pass
12
16
13
17
import importlib
14
18
import json
15
19
import logging
16
- import os
17
20
import re
18
21
import sys
19
22
import time
@@ -123,7 +126,10 @@ def pytest_bdd_apply_tag(tag, function):
123
126
124
127
def snake_case (value ):
125
128
s1 = re .sub ("(.)([A-Z][a-z]+)" , r"\1_\2" , value )
126
- return re .sub ("([a-z0-9])([A-Z])" , r"\1_\2" , s1 ).lower ()
129
+ s1 = re .sub ("([a-z0-9])([A-Z])" , r"\1_\2" , s1 ).lower ()
130
+ s1 = re .sub (r"\W" , "_" , s1 )
131
+ s1 = re .sub (r"_+$" , "" , s1 )
132
+ return re .sub (r"__+" , "_" , s1 )
127
133
128
134
129
135
def glom (value , path ):
@@ -173,17 +179,28 @@ def __str__(self):
173
179
174
180
175
181
@pytest .fixture
176
- def fixtures (request , unique , unique_lower ):
177
- """Return a mapping with all defined fixtures."""
178
- ctx = {}
182
+ def context (vcr_cassette , request , unique , unique_lower ):
183
+ """
184
+ Return a mapping with all defined fixtures, all objects created by `given` steps,
185
+ and the undo operations to perform after a test scenario.
186
+ """
187
+ ctx = {"undo_operations" : []}
179
188
for f in request .fixturenames :
180
- if f == "fixtures " :
189
+ if f == "context " :
181
190
continue
182
191
try :
183
192
ctx [f ] = request .getfixturevalue (f )
184
193
except Exception :
185
194
pass
186
- return ctx
195
+ yield ctx
196
+ for undo in reversed (ctx ["undo_operations" ]):
197
+ if vcr_cassette .record_mode != "none" :
198
+ number_of_interactions = len (vcr_cassette .data )
199
+ try :
200
+ undo ()
201
+ except Exception as e :
202
+ warnings .warn (str (e ))
203
+ vcr_cassette .data = vcr_cassette .data [:number_of_interactions ]
187
204
188
205
189
206
@pytest .fixture (scope = "module" , autouse = True )
@@ -226,10 +243,11 @@ def freezer(vcr_cassette_name, vcr_cassette, vcr):
226
243
if vcr_cassette .record_mode != "none" :
227
244
tzinfo = datetime .now ().astimezone ().tzinfo
228
245
freeze_at = datetime .now ().replace (tzinfo = tzinfo ).isoformat ()
229
- with open (
230
- os .path .join (vcr .cassette_library_dir , vcr_cassette_name + ".frozen" ), "w+" ,
231
- ) as f :
232
- f .write (freeze_at )
246
+ if vcr_cassette .record_mode == "all" :
247
+ with open (
248
+ os .path .join (vcr .cassette_library_dir , vcr_cassette_name + ".frozen" ), "w+" ,
249
+ ) as f :
250
+ f .write (freeze_at )
233
251
else :
234
252
with open (
235
253
os .path .join (vcr .cassette_library_dir , vcr_cassette_name + ".frozen" ), "r" ,
@@ -276,25 +294,27 @@ def client(_package, configuration, record_mode, vcr_cassette):
276
294
277
295
278
296
@given (parsers .parse ('an instance of "{name}" API' ))
279
- def api (package_name , client , name ):
297
+ def api (context , package_name , client , name ):
280
298
"""Return an API instance."""
281
299
module_name = snake_case (name )
282
300
package = importlib .import_module (f"{ package_name } .api.{ module_name } _api" )
283
- return {
301
+ context [ "api" ] = {
284
302
"api" : getattr (package , name + "Api" )(client ),
285
303
"calls" : [],
286
304
}
287
305
306
+
288
307
@given (parsers .parse ('operation "{name}" enabled' ))
289
308
def operation_enabled (client , name ):
290
309
"""Enable the unstable operation specific in the clause."""
291
310
client .configuration .unstable_operations [snake_case (name )] = True
292
311
293
312
294
313
@given (parsers .parse ('new "{name}" request' ))
295
- def api_request (api , name ):
314
+ def api_request (context , name ):
296
315
"""Call an endpoint."""
297
- return {
316
+ api = context ["api" ]
317
+ context ["api_request" ] = {
298
318
"api" : api ["api" ],
299
319
"request" : getattr (api ["api" ], snake_case (name )),
300
320
"args" : [],
@@ -312,22 +332,29 @@ def api_request(api, name):
312
332
313
333
314
334
@given (parsers .parse ("body {data}" ))
315
- def request_body (fixtures , api_request , data ):
335
+ def request_body (context , data ):
316
336
"""Set request body."""
317
337
import json
318
338
from jinja2 import Template
319
339
320
- tpl = Template (data ).render (** fixtures )
321
- body = api_request ["kwargs" ]["body" ] = json .loads (tpl )
322
-
323
- return body
340
+ tpl = Template (data ).render (** context )
341
+ context ["api_request" ]["kwargs" ]["body" ] = json .loads (tpl )
324
342
325
343
326
344
@given (parsers .parse ('request contains "{name}" parameter from "{path}"' ))
327
- def request_parameter (fixtures , api_request , name , path ):
345
+ def request_parameter (context , name , path ):
328
346
"""Set request parameter."""
329
- api_request ["kwargs" ][name ] = parameter = glom (fixtures , path )
330
- return parameter
347
+ context ["api_request" ]["kwargs" ][snake_case (name )] = glom (context , path )
348
+
349
+
350
+ @given (parsers .parse ('request contains "{name}" parameter with value {value}' ))
351
+ def request_parameter_with_value (context , name , value ):
352
+ """Set request parameter."""
353
+ import json
354
+ from jinja2 import Template
355
+
356
+ tpl = Template (value ).render (** context )
357
+ context ["api_request" ]["kwargs" ][snake_case (name )] = json .loads (tpl )
331
358
332
359
333
360
def undo (api_request , client ):
@@ -343,16 +370,24 @@ def undo(api_request, client):
343
370
elif operation_id == "create_team" :
344
371
client .configuration .unstable_operations ["delete_team" ] = True
345
372
return api_request ["api" ].delete_team (api_request ["response" ][0 ].data .id )
346
- elif operation_id in {"update_user" , "add_permission_to_role" , "add_user_to_role" , "send_invitations" }:
373
+ elif operation_id in {
374
+ "update_user" ,
375
+ "add_permission_to_role" ,
376
+ "add_user_to_role" ,
377
+ "send_invitations" ,
378
+ "aggregate_logs" ,
379
+ "list_logs" ,
380
+ }:
347
381
return
348
382
elif api_request ["request" ].settings ["http_method" ] == "PATCH" :
349
383
return
350
384
raise NotImplementedError (operation_id )
351
385
352
386
353
387
@when ("the request is sent" )
354
- def execute_request (vcr_cassette , api_request , client ):
388
+ def execute_request (context , vcr_cassette , client ):
355
389
"""Execute the prepared request."""
390
+ api_request = context ["api_request" ]
356
391
api_request ["response" ] = api_request ["request" ].call_with_http_info (
357
392
* api_request ["args" ], ** api_request ["kwargs" ]
358
393
)
@@ -369,41 +404,41 @@ def execute_request(vcr_cassette, api_request, client):
369
404
370
405
371
406
@then (parsers .parse ('I should get an instance of "{name}"' ))
372
- def i_should_get_an_instace_of (package_name , api , name ):
407
+ def i_should_get_an_instace_of (context , package_name , name ):
373
408
"""I should get an instace."""
374
409
module_name = snake_case (name )
375
410
package = importlib .import_module (f"{ package_name } .model.{ module_name } " )
376
- assert isinstance (api_request ["response" ][0 ], getattr (package , name ))
411
+ assert isinstance (context [ " api_request" ] ["response" ][0 ], getattr (package , name ))
377
412
378
413
379
414
@then (parsers .parse ('I should get a list of "{name}" objects' ))
380
- def i_should_get_a_list_of_objects (package_name , api , name ):
415
+ def i_should_get_a_list_of_objects (context , package_name , name ):
381
416
"""I should get an instace."""
382
417
module_name = snake_case (name )
383
418
package = importlib .import_module (f"{ package_name } .model.{ module_name } " )
384
419
cls = getattr (package , name )
385
- assert all (isinstance (obj , cls ) for obj in api_request ["response" ][0 ])
420
+ assert all (isinstance (obj , cls ) for obj in context [ " api_request" ] ["response" ][0 ])
386
421
387
422
388
423
@then (parsers .parse ("the response status is {status:d} {description}" ))
389
- def the_status_is (api_request , status , description ):
424
+ def the_status_is (context , status , description ):
390
425
"""Check the status."""
391
- assert status == api_request ["response" ][1 ]
426
+ assert status == context [ " api_request" ] ["response" ][1 ]
392
427
393
428
394
429
@then (parsers .parse ('the response "{response_path}" is equal to {value}' ))
395
- def expect_equal (api_request , fixtures , response_path , value ):
430
+ def expect_equal (context , response_path , value ):
396
431
from jinja2 import Template
397
432
398
- response_value = glom (api_request ["response" ][0 ], response_path )
399
- test_value = json .loads (Template (value ).render (** fixtures ))
433
+ response_value = glom (context [ " api_request" ] ["response" ][0 ], response_path )
434
+ test_value = json .loads (Template (value ).render (** context ))
400
435
assert test_value == response_value
401
436
402
437
403
438
@then (parsers .parse ('the response "{response_path}" has the same value as "{fixture_path}"' ))
404
- def expect_equal_value (api_request , fixtures , response_path , fixture_path ):
405
- fixture_value = glom (fixtures , fixture_path )
406
- response_value = glom (api_request ["response" ][0 ], response_path )
439
+ def expect_equal_value (context , response_path , fixture_path ):
440
+ fixture_value = glom (context , fixture_path )
441
+ response_value = glom (context [ " api_request" ] ["response" ][0 ], response_path )
407
442
assert fixture_value == response_value
408
443
409
444
@@ -414,6 +449,6 @@ def expect_equal_value(api_request, fixtures, response_path, fixture_length):
414
449
415
450
416
451
@then (parsers .parse ('the response "{response_path}" is false' ))
417
- def expect_false (api_request , response_path ):
418
- response_value = glom (api_request ["response" ][0 ], response_path )
452
+ def expect_false (context , response_path ):
453
+ response_value = glom (context [ " api_request" ] ["response" ][0 ], response_path )
419
454
assert not response_value
0 commit comments