@@ -153,15 +153,42 @@ mod tests {
153153 use crate :: env:: Env ;
154154 use crate :: tests:: { LIVE_TEST_RESOURCE , LIVE_TEST_SCOPES } ;
155155 use azure_core:: http:: headers:: Headers ;
156- use azure_core:: http:: { Method , RawResponse , Request , StatusCode } ;
156+ use azure_core:: http:: { Method , RawResponse , Request , StatusCode , Url } ;
157+ use azure_core:: time:: OffsetDateTime ;
157158 use azure_core:: Bytes ;
158- use azure_core_test:: http:: MockHttpClient ;
159+ use azure_core_test:: { http:: MockHttpClient , recorded } ;
159160 use futures:: FutureExt ;
161+ use std:: env;
160162 use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
161163 use std:: time:: { SystemTime , UNIX_EPOCH } ;
162164
163165 const EXPIRES_ON : & str = "EXPIRES_ON" ;
164166
167+ async fn run_deployed_test (
168+ authority : & str ,
169+ storage_name : & str ,
170+ id : Option < UserAssignedId > ,
171+ ) -> azure_core:: Result < ( ) > {
172+ let id_param = id. map_or ( "" . to_string ( ) , |id| match id {
173+ UserAssignedId :: ClientId ( id) => format ! ( "client-id={id}&" ) ,
174+ UserAssignedId :: ObjectId ( id) => format ! ( "object-id={id}&" ) ,
175+ UserAssignedId :: ResourceId ( id) => format ! ( "resource-id={id}&" ) ,
176+ } ) ;
177+ let url = format ! (
178+ "http://{authority}/api?test=managed-identity&{id_param}storage-name={storage_name}"
179+ ) ;
180+ let u = Url :: parse ( & url) . expect ( "invalid URL" ) ;
181+ let client = azure_core:: http:: new_http_client ( ) ;
182+ let req = Request :: new ( u, Method :: Get ) ;
183+
184+ let res = client. execute_request ( & req) . await . expect ( "request failed" ) ;
185+ let status = res. status ( ) ;
186+ let body = res. into_body ( ) . collect_string ( ) . await ?;
187+ assert_eq ! ( StatusCode :: Ok , status, "Test app responded with '{body}'" ) ;
188+
189+ Ok ( ( ) )
190+ }
191+
165192 async fn run_supported_source_test (
166193 env : Env ,
167194 options : Option < ManagedIdentityCredentialOptions > ,
@@ -256,6 +283,27 @@ mod tests {
256283 ) ;
257284 }
258285
286+ #[ recorded:: test( live) ]
287+ async fn aci_user_assigned_live ( ) -> azure_core:: Result < ( ) > {
288+ if env:: var ( "CI_HAS_DEPLOYED_RESOURCES" ) . is_err ( ) {
289+ println ! ( "Skipped: ACI live tests require deployed resources" ) ;
290+ return Ok ( ( ) ) ;
291+ }
292+ let ip = env:: var ( "IDENTITY_ACI_IP_USER_ASSIGNED" ) . expect ( "IDENTITY_ACI_IP_USER_ASSIGNED" ) ;
293+ let storage_name = env:: var ( "IDENTITY_STORAGE_NAME_USER_ASSIGNED" )
294+ . expect ( "IDENTITY_STORAGE_NAME_USER_ASSIGNED" ) ;
295+ let client_id = env:: var ( "IDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID" )
296+ . expect ( "IDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID" ) ;
297+ run_deployed_test (
298+ & format ! ( "{}:8080" , ip) ,
299+ & storage_name,
300+ Some ( UserAssignedId :: ClientId ( client_id) ) ,
301+ )
302+ . await ?;
303+
304+ Ok ( ( ) )
305+ }
306+
259307 async fn run_app_service_test ( options : Option < ManagedIdentityCredentialOptions > ) {
260308 let endpoint = "http://localhost/metadata/identity/oauth2/token" ;
261309 let x_id_header = "x-id-header" ;
@@ -369,6 +417,27 @@ mod tests {
369417 ) ;
370418 }
371419
420+ async fn run_imds_live_test ( id : Option < UserAssignedId > ) -> azure_core:: Result < ( ) > {
421+ if std:: env:: var ( "IDENTITY_IMDS_AVAILABLE" ) . is_err ( ) {
422+ println ! ( "Skipped: IMDS isn't available" ) ;
423+ return Ok ( ( ) ) ;
424+ }
425+
426+ let credential = ManagedIdentityCredential :: new ( Some ( ManagedIdentityCredentialOptions {
427+ user_assigned_id : id,
428+ ..Default :: default ( )
429+ } ) )
430+ . expect ( "valid credential" ) ;
431+
432+ let token = credential. get_token ( LIVE_TEST_SCOPES , None ) . await ?;
433+
434+ assert ! ( !token. token. secret( ) . is_empty( ) ) ;
435+ assert_eq ! ( time:: UtcOffset :: UTC , token. expires_on. offset( ) ) ;
436+ assert ! ( token. expires_on. unix_timestamp( ) > OffsetDateTime :: now_utc( ) . unix_timestamp( ) ) ;
437+
438+ Ok ( ( ) )
439+ }
440+
372441 async fn run_imds_test ( options : Option < ManagedIdentityCredentialOptions > ) {
373442 let mut model = Request :: new (
374443 "http://169.254.169.254/metadata/identity/oauth2/token"
@@ -408,11 +477,6 @@ mod tests {
408477 ) . await ;
409478 }
410479
411- #[ tokio:: test]
412- async fn imds ( ) {
413- run_imds_test ( None ) . await ;
414- }
415-
416480 #[ tokio:: test]
417481 async fn imds_client_id ( ) {
418482 run_imds_test ( Some ( ManagedIdentityCredentialOptions {
@@ -442,6 +506,16 @@ mod tests {
442506 . await ;
443507 }
444508
509+ #[ tokio:: test]
510+ async fn imds_system_assigned ( ) {
511+ run_imds_test ( None ) . await ;
512+ }
513+
514+ #[ recorded:: test( live) ]
515+ async fn imds_system_assigned_live ( ) -> azure_core:: Result < ( ) > {
516+ run_imds_live_test ( None ) . await
517+ }
518+
445519 #[ tokio:: test]
446520 async fn requires_one_scope ( ) {
447521 let credential = ManagedIdentityCredential :: new ( None ) . expect ( "valid credential" ) ;
0 commit comments