1
1
use crate :: scenarios:: function_mappings:: {
2
2
collect_function_calls, initialize_api_instance, ApiInstances ,
3
3
} ;
4
- use chrono:: DateTime ;
4
+ use chrono:: { DateTime , Duration } ;
5
5
use cucumber:: {
6
6
event:: ScenarioFinished ,
7
7
gherkin:: { Feature , Rule , Scenario } ,
8
8
given, then, when, World ,
9
9
} ;
10
10
use datadog_api_client:: datadog:: configuration:: Configuration ;
11
- use handlebars:: Handlebars ;
11
+ use handlebars:: { Context , Handlebars , Helper , Output , RenderContext , RenderError } ;
12
12
use log:: debug;
13
13
use regex:: Regex ;
14
14
use reqwest_middleware:: ClientBuilder ;
@@ -20,6 +20,7 @@ use std::{
20
20
env,
21
21
fs:: { create_dir_all, read_to_string, File } ,
22
22
io:: BufReader ,
23
+ ops:: Add ,
23
24
path:: PathBuf ,
24
25
time:: SystemTime ,
25
26
} ;
@@ -39,7 +40,7 @@ struct UndoOperation {
39
40
parameters : HashMap < String , Value > ,
40
41
}
41
42
42
- #[ derive( Debug , Default , World ) ]
43
+ #[ derive( Default , World ) ]
43
44
pub struct DatadogWorld {
44
45
pub api_version : i32 ,
45
46
pub config : Configuration ,
@@ -54,6 +55,14 @@ pub struct DatadogWorld {
54
55
undo_operations : Vec < UndoOperation > ,
55
56
}
56
57
58
+ // Workaround to suppress cucumber's debug output - the DatadogWorld
59
+ // struct debug output is overly verbose and not useful
60
+ impl std:: fmt:: Debug for DatadogWorld {
61
+ fn fmt ( & self , _: & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
62
+ Ok ( ( ) )
63
+ }
64
+ }
65
+
57
66
pub async fn before_scenario (
58
67
feature : & Feature ,
59
68
_rule : Option < & Rule > ,
@@ -144,7 +153,7 @@ pub async fn before_scenario(
144
153
// res.headers.remove_entry("content-security-policy");
145
154
// });
146
155
// vcr_client_builder.with(middleware).build()
147
- panic ! ( "sdk's shouldn't be recording, that's the spec repo's job ." ) ;
156
+ panic ! ( "Use the cassette transform in datadog-api-spec instead. This recording mode is only here for completeness ." ) ;
148
157
}
149
158
_ => {
150
159
frozen_time = DateTime :: parse_from_rfc3339 (
@@ -387,9 +396,79 @@ fn lookup(path: &String, object: &Value) -> Option<Value> {
387
396
return object. pointer ( & json_pointer) . cloned ( ) ;
388
397
}
389
398
399
+ fn relative_time_helper ( h : & Helper , c : & Context ) -> DateTime < chrono:: Utc > {
400
+ // get parameter from helper or throw an error
401
+ let v = h. param ( 0 ) . unwrap ( ) . render ( ) ;
402
+ let time_helper_re = Regex :: new ( r"now(?: *([+-]) *(\d+)([smhdMy]))?" ) . unwrap ( ) ;
403
+ let caps = time_helper_re
404
+ . captures ( & v)
405
+ . expect ( "failed to parse timeISO template function" ) ;
406
+ let time = chrono:: DateTime :: from_timestamp ( c. data ( ) . get ( "now" ) . unwrap ( ) . as_i64 ( ) . unwrap ( ) , 0 )
407
+ . unwrap ( ) ;
408
+ if caps. get ( 1 ) . is_some ( ) {
409
+ let diff = str:: parse :: < i64 > (
410
+ & ( caps. get ( 1 ) . unwrap ( ) . as_str ( ) . to_string ( ) + caps. get ( 2 ) . unwrap ( ) . as_str ( ) ) ,
411
+ )
412
+ . unwrap ( ) ;
413
+ match caps. get ( 3 ) . unwrap ( ) . as_str ( ) {
414
+ "s" => time. add ( Duration :: seconds ( diff) ) ,
415
+ "m" => time. add ( Duration :: minutes ( diff) ) ,
416
+ "h" => time. add ( Duration :: hours ( diff) ) ,
417
+ "d" => time. add ( Duration :: days ( diff) ) ,
418
+ "M" => time. add ( Duration :: weeks ( diff * 4 ) ) ,
419
+ "y" => time. add ( Duration :: weeks ( diff * 52 ) ) ,
420
+ _ => panic ! ( "invalid time unit" ) ,
421
+ }
422
+ } else {
423
+ time
424
+ }
425
+ }
426
+
427
+ fn timeISO_helper (
428
+ h : & Helper ,
429
+ _: & Handlebars ,
430
+ c : & Context ,
431
+ _: & mut RenderContext ,
432
+ out : & mut dyn Output ,
433
+ ) -> Result < ( ) , RenderError > {
434
+ write ! ( out, "{}" , relative_time_helper( h, c) . to_rfc3339( ) ) ?;
435
+ Ok ( ( ) )
436
+ }
437
+
438
+ fn timestamp_helper (
439
+ h : & Helper ,
440
+ _: & Handlebars ,
441
+ c : & Context ,
442
+ _: & mut RenderContext ,
443
+ out : & mut dyn Output ,
444
+ ) -> Result < ( ) , RenderError > {
445
+ write ! (
446
+ out,
447
+ "{}" ,
448
+ relative_time_helper( h, c)
449
+ . signed_duration_since( DateTime :: UNIX_EPOCH )
450
+ . num_seconds( )
451
+ ) ?;
452
+ Ok ( ( ) )
453
+ }
454
+
390
455
fn template ( string : String , fixtures : & Value ) -> String {
391
- Handlebars :: new ( )
392
- . render_template ( string. as_str ( ) , & fixtures)
456
+ let time_helper_re = Regex :: new ( r"(?:timestamp|timeISO)\([^{}]*\)" ) . unwrap ( ) ;
457
+ let helper_parsed_string = time_helper_re
458
+ . replace_all ( & string, |caps : & regex:: Captures | {
459
+ caps. get ( 0 )
460
+ . unwrap ( )
461
+ . as_str ( )
462
+ . replace ( '(' , " " )
463
+ . replace ( ')' , "" )
464
+ } )
465
+ . to_string ( ) ;
466
+
467
+ let mut handlebars = Handlebars :: new ( ) ;
468
+ handlebars. register_helper ( "timeISO" , Box :: new ( timeISO_helper) ) ;
469
+ handlebars. register_helper ( "timestamp" , Box :: new ( timestamp_helper) ) ;
470
+ handlebars
471
+ . render_template ( helper_parsed_string. as_str ( ) , & fixtures)
393
472
. expect ( "failed to apply template" )
394
473
}
395
474
0 commit comments