@@ -5,12 +5,15 @@ use std::io;
5
5
use std:: io:: prelude:: * ;
6
6
7
7
use crate :: common:: LambdaEventBuilder ;
8
+ use http:: HeaderMap ;
9
+ use http:: Request ;
8
10
use http:: { Method , Response } ;
9
11
use httpmock:: {
10
12
Method :: { DELETE , GET , POST , PUT } ,
11
13
MockServer ,
12
14
} ;
13
15
use hyper:: { body, Body } ;
16
+ use lambda_http:: Context ;
14
17
use lambda_web_adapter:: { Adapter , AdapterOptions , LambdaInvokeMode , Protocol } ;
15
18
use tower:: { Service , ServiceBuilder } ;
16
19
@@ -158,7 +161,13 @@ async fn test_http_basic_request() {
158
161
159
162
// // Call the adapter service with basic request
160
163
let req = LambdaEventBuilder :: new ( ) . with_path ( "/hello" ) . build ( ) ;
161
- let response = adapter. call ( req. into ( ) ) . await . expect ( "Request failed" ) ;
164
+
165
+ // We convert to Request object because it allows us to add
166
+ // the lambda Context
167
+ let mut request = Request :: from ( req) ;
168
+ add_lambda_context_to_request ( & mut request) ;
169
+
170
+ let response = adapter. call ( request) . await . expect ( "Request failed" ) ;
162
171
163
172
// Assert endpoint was called once
164
173
hello. assert ( ) ;
@@ -202,8 +211,13 @@ async fn test_http_headers() {
202
211
. with_header ( "foo" , "bar" )
203
212
. build ( ) ;
204
213
214
+ // We convert to Request object because it allows us to add
215
+ // the Lambda Context
216
+ let mut request = Request :: from ( req) ;
217
+ add_lambda_context_to_request ( & mut request) ;
218
+
205
219
// Call the adapter service with request
206
- let response = adapter. call ( req . into ( ) ) . await . expect ( "Request failed" ) ;
220
+ let response = adapter. call ( request ) . await . expect ( "Request failed" ) ;
207
221
208
222
// Assert endpoint was called once
209
223
test_endpoint. assert ( ) ;
@@ -245,8 +259,13 @@ async fn test_http_path_encoding() {
245
259
// Prepare request
246
260
let req = LambdaEventBuilder :: new ( ) . with_path ( "/Año_1234" ) . build ( ) ;
247
261
262
+ // We convert to Request object because it allows us to add
263
+ // the lambda Context
264
+ let mut request = Request :: from ( req) ;
265
+ add_lambda_context_to_request ( & mut request) ;
266
+
248
267
// Call the adapter service with request
249
- let response = adapter. call ( req . into ( ) ) . await . expect ( "Request failed" ) ;
268
+ let response = adapter. call ( request ) . await . expect ( "Request failed" ) ;
250
269
251
270
// Assert endpoint was called once
252
271
test_endpoint. assert ( ) ;
@@ -293,8 +312,13 @@ async fn test_http_query_params() {
293
312
. with_query ( "fizz" , "buzz" )
294
313
. build ( ) ;
295
314
315
+ // We convert to Request object because it allows us to add
316
+ // the lambda Context
317
+ let mut request = Request :: from ( req) ;
318
+ add_lambda_context_to_request ( & mut request) ;
319
+
296
320
// Call the adapter service with request
297
- let response = adapter. call ( req . into ( ) ) . await . expect ( "Request failed" ) ;
321
+ let response = adapter. call ( request ) . await . expect ( "Request failed" ) ;
298
322
299
323
// Assert endpoint was called once
300
324
test_endpoint. assert ( ) ;
@@ -354,11 +378,20 @@ async fn test_http_post_put_delete() {
354
378
. with_method ( Method :: DELETE )
355
379
. with_path ( "/" )
356
380
. build ( ) ;
381
+ // We convert to Request object because it allows us to add the lambda Context
382
+ let mut post_request = Request :: from ( post_req) ;
383
+ add_lambda_context_to_request ( & mut post_request) ;
384
+
385
+ let mut put_request = Request :: from ( put_req) ;
386
+ add_lambda_context_to_request ( & mut put_request) ;
387
+
388
+ let mut delete_request = Request :: from ( delete_req) ;
389
+ add_lambda_context_to_request ( & mut delete_request) ;
357
390
358
391
// Call the adapter service with requests
359
- let post_response = adapter. call ( post_req . into ( ) ) . await . expect ( "Request failed" ) ;
360
- let put_response = adapter. call ( put_req . into ( ) ) . await . expect ( "Request failed" ) ;
361
- let delete_response = adapter. call ( delete_req . into ( ) ) . await . expect ( "Request failed" ) ;
392
+ let post_response = adapter. call ( post_request ) . await . expect ( "Request failed" ) ;
393
+ let put_response = adapter. call ( put_request ) . await . expect ( "Request failed" ) ;
394
+ let delete_response = adapter. call ( delete_request ) . await . expect ( "Request failed" ) ;
362
395
363
396
// Assert endpoints were called
364
397
post_endpoint. assert ( ) ;
@@ -407,7 +440,13 @@ async fn test_http_compress() {
407
440
. with_path ( "/hello" )
408
441
. with_header ( "accept-encoding" , "gzip" )
409
442
. build ( ) ;
410
- let response = svc. call ( req. into ( ) ) . await . expect ( "Request failed" ) ;
443
+
444
+ // We convert to Request object because it allows us to add
445
+ // the lambda Context
446
+ let mut request = Request :: from ( req) ;
447
+ add_lambda_context_to_request ( & mut request) ;
448
+
449
+ let response = svc. call ( request) . await . expect ( "Request failed" ) ;
411
450
412
451
// Assert endpoint was called once
413
452
hello. assert ( ) ;
@@ -453,7 +492,13 @@ async fn test_http_compress_disallowed_type() {
453
492
. with_path ( "/hello" )
454
493
. with_header ( "accept-encoding" , "gzip" )
455
494
. build ( ) ;
456
- let response = adapter. call ( req. into ( ) ) . await . expect ( "Request failed" ) ;
495
+
496
+ // We convert to Request object because it allows us to add
497
+ // the lambda Context
498
+ let mut request = Request :: from ( req) ;
499
+ add_lambda_context_to_request ( & mut request) ;
500
+
501
+ let response = adapter. call ( request) . await . expect ( "Request failed" ) ;
457
502
458
503
// Assert endpoint was called once
459
504
hello. assert ( ) ;
@@ -506,7 +551,13 @@ async fn test_http_compress_already_compressed() {
506
551
. with_path ( "/hello" )
507
552
. with_header ( "accept-encoding" , "gzip" )
508
553
. build ( ) ;
509
- let response = svc. call ( req. into ( ) ) . await . expect ( "Request failed" ) ;
554
+
555
+ // We convert to Request object because it allows us to add
556
+ // the lambda Context
557
+ let mut request = Request :: from ( req) ;
558
+ add_lambda_context_to_request ( & mut request) ;
559
+
560
+ let response = svc. call ( request) . await . expect ( "Request failed" ) ;
510
561
511
562
// Assert endpoint was called once
512
563
hello. assert ( ) ;
@@ -521,6 +572,54 @@ async fn test_http_compress_already_compressed() {
521
572
) ;
522
573
}
523
574
575
+ #[ tokio:: test]
576
+ async fn test_http_lambda_context_header ( ) {
577
+ // Start app server
578
+ let app_server = MockServer :: start ( ) ;
579
+
580
+ // An endpoint that expects and returns headers
581
+ let test_endpoint = app_server. mock ( |when, then| {
582
+ when. method ( GET ) . path ( "/" ) . header_exists ( "x-amzn-lambda-context" ) ;
583
+ then. status ( 200 ) . header ( "fizz" , "buzz" ) . body ( "OK" ) ;
584
+ } ) ;
585
+
586
+ // Initialize adapter and do readiness check
587
+ let mut adapter = Adapter :: new ( & AdapterOptions {
588
+ host : app_server. host ( ) ,
589
+ port : app_server. port ( ) . to_string ( ) ,
590
+ readiness_check_port : app_server. port ( ) . to_string ( ) ,
591
+ readiness_check_path : "/healthcheck" . to_string ( ) ,
592
+ readiness_check_protocol : Protocol :: Http ,
593
+ async_init : false ,
594
+ base_path : None ,
595
+ compression : false ,
596
+ enable_tls : false ,
597
+ tls_server_name : None ,
598
+ tls_cert_file : None ,
599
+ invoke_mode : LambdaInvokeMode :: Buffered ,
600
+ } ) ;
601
+
602
+ // Prepare request
603
+ let req = LambdaEventBuilder :: new ( ) . with_path ( "/" ) . build ( ) ;
604
+
605
+ // We convert to Request object because it allows us to add
606
+ // the Lambda Context
607
+ let mut request = Request :: from ( req) ;
608
+ add_lambda_context_to_request ( & mut request) ;
609
+
610
+ // Call the adapter service with request
611
+ let response = adapter. call ( request) . await . expect ( "Request failed" ) ;
612
+
613
+ // Assert endpoint was called once
614
+ test_endpoint. assert ( ) ;
615
+
616
+ // and response has expected content
617
+ assert_eq ! ( 200 , response. status( ) ) ;
618
+ assert ! ( response. headers( ) . contains_key( "fizz" ) ) ;
619
+ assert_eq ! ( "buzz" , response. headers( ) . get( "fizz" ) . unwrap( ) ) ;
620
+ assert_eq ! ( "OK" , body_to_string( response) . await ) ;
621
+ }
622
+
524
623
async fn body_to_string ( res : Response < Body > ) -> String {
525
624
let body_bytes = body:: to_bytes ( res. into_body ( ) ) . await . unwrap ( ) ;
526
625
String :: from_utf8_lossy ( & body_bytes) . to_string ( )
@@ -537,3 +636,17 @@ fn decode_reader(bytes: &[u8]) -> io::Result<String> {
537
636
gz. read_to_string ( & mut s) ?;
538
637
Ok ( s)
539
638
}
639
+
640
+ fn add_lambda_context_to_request ( request : & mut Request < lambda_http:: Body > ) {
641
+ // create a HeaderMap to build the lambda context
642
+ let mut headers = HeaderMap :: new ( ) ;
643
+ headers. insert ( "lambda-runtime-aws-request-id" , "my_id" . parse ( ) . unwrap ( ) ) ;
644
+ headers. insert ( "lambda-runtime-deadline-ms" , "123" . parse ( ) . unwrap ( ) ) ;
645
+ headers. insert ( "lambda-runtime-client-context" , "{}" . parse ( ) . unwrap ( ) ) ;
646
+
647
+ // converts HeaderMap to Context
648
+ let context = Context :: try_from ( headers) . expect ( "Couldn't convert HeaderMap to Context" ) ;
649
+
650
+ // add Context to the request
651
+ request. extensions_mut ( ) . insert ( context) ;
652
+ }
0 commit comments