@@ -455,6 +455,10 @@ impl OpenShell for TestOpenShell {
455455 . profiles
456456 . into_iter ( )
457457 . filter_map ( |item| item. profile )
458+ . map ( |mut profile| {
459+ profile. resource_version = 1 ;
460+ profile
461+ } )
458462 . inspect ( |profile| {
459463 profiles. insert ( profile. id . clone ( ) , profile. clone ( ) ) ;
460464 } )
@@ -468,6 +472,72 @@ impl OpenShell for TestOpenShell {
468472 ) )
469473 }
470474
475+ async fn update_provider_profiles (
476+ & self ,
477+ request : tonic:: Request < openshell_core:: proto:: UpdateProviderProfilesRequest > ,
478+ ) -> Result < Response < openshell_core:: proto:: UpdateProviderProfilesResponse > , Status > {
479+ let mut profiles = self . state . profiles . lock ( ) . await ;
480+ let request = request. into_inner ( ) ;
481+ let mut profile = request
482+ . profile
483+ . and_then ( |item| item. profile )
484+ . ok_or_else ( || Status :: invalid_argument ( "provider profile is required" ) ) ?;
485+ let target_id = request. id ;
486+ if target_id != profile. id {
487+ return Ok ( Response :: new (
488+ openshell_core:: proto:: UpdateProviderProfilesResponse {
489+ diagnostics : vec ! [ openshell_core:: proto:: ProviderProfileDiagnostic {
490+ source: target_id. clone( ) ,
491+ profile_id: profile. id. clone( ) ,
492+ field: "id" . to_string( ) ,
493+ message: format!(
494+ "provider profile update target '{}' does not match payload id '{}'" ,
495+ target_id, profile. id
496+ ) ,
497+ severity: "error" . to_string( ) ,
498+ } ] ,
499+ profile : None ,
500+ updated : false ,
501+ } ,
502+ ) ) ;
503+ }
504+ let Some ( current) = profiles. get ( & target_id) else {
505+ return Ok ( Response :: new (
506+ openshell_core:: proto:: UpdateProviderProfilesResponse {
507+ diagnostics : vec ! [ openshell_core:: proto:: ProviderProfileDiagnostic {
508+ source: target_id. clone( ) ,
509+ profile_id: target_id. clone( ) ,
510+ field: "id" . to_string( ) ,
511+ message: format!( "custom provider profile '{target_id}' does not exist" ) ,
512+ severity: "error" . to_string( ) ,
513+ } ] ,
514+ profile : None ,
515+ updated : false ,
516+ } ,
517+ ) ) ;
518+ } ;
519+ let expected_resource_version = if request. expected_resource_version != 0 {
520+ request. expected_resource_version
521+ } else {
522+ profile. resource_version
523+ } ;
524+ if expected_resource_version == 0 || expected_resource_version != current. resource_version {
525+ return Err ( Status :: aborted ( format ! (
526+ "provider profile was modified concurrently (current resource_version: {})" ,
527+ current. resource_version
528+ ) ) ) ;
529+ }
530+ profile. resource_version = current. resource_version + 1 ;
531+ profiles. insert ( profile. id . clone ( ) , profile. clone ( ) ) ;
532+ Ok ( Response :: new (
533+ openshell_core:: proto:: UpdateProviderProfilesResponse {
534+ diagnostics : Vec :: new ( ) ,
535+ profile : Some ( profile) ,
536+ updated : true ,
537+ } ,
538+ ) )
539+ }
540+
471541 async fn lint_provider_profiles (
472542 & self ,
473543 _request : tonic:: Request < openshell_core:: proto:: LintProviderProfilesRequest > ,
@@ -1366,6 +1436,31 @@ binaries: [/usr/bin/custom]
13661436 run:: provider_profile_import ( & ts. endpoint , Some ( & profile_path) , None , & ts. tls )
13671437 . await
13681438 . expect ( "profile import" ) ;
1439+ let exported_yaml =
1440+ run:: provider_profile_export_text ( & ts. endpoint , "custom-api" , "yaml" , & ts. tls )
1441+ . await
1442+ . expect ( "profile export text" ) ;
1443+ assert ! ( exported_yaml. contains( "resource_version: 1" ) ) ;
1444+ let updated_yaml = exported_yaml
1445+ . replace (
1446+ "display_name: Custom API" ,
1447+ "display_name: Custom API Updated" ,
1448+ )
1449+ . replace ( "host: api.custom.example" , "host: api.updated.example" ) ;
1450+ std:: fs:: write ( & profile_path, updated_yaml) . unwrap ( ) ;
1451+ run:: provider_profile_update ( & ts. endpoint , "custom-api" , & profile_path, & ts. tls )
1452+ . await
1453+ . expect ( "profile update" ) ;
1454+ assert_eq ! (
1455+ ts. state
1456+ . profiles
1457+ . lock( )
1458+ . await
1459+ . get( "custom-api" )
1460+ . and_then( |profile| profile. endpoints. first( ) )
1461+ . map( |endpoint| endpoint. host. as_str( ) ) ,
1462+ Some ( "api.updated.example" )
1463+ ) ;
13691464 run:: provider_profile_export ( & ts. endpoint , "custom-api" , "yaml" , & ts. tls )
13701465 . await
13711466 . expect ( "profile export" ) ;
0 commit comments