15
15
16
16
*/
17
17
18
- use std:: { collections:: HashMap , vec} ;
19
-
20
- use anyhow:: Ok ;
21
18
use common:: {
22
19
chat_completions:: CHAT_COMPLETIONS_ENDPOINT ,
23
20
chunker:: CHUNKER_UNARY_ENDPOINT ,
@@ -38,8 +35,7 @@ use fms_guardrails_orchestr8::{
38
35
detector:: { ContentAnalysisRequest , ContentAnalysisResponse } ,
39
36
openai:: {
40
37
ChatCompletion , ChatCompletionChoice , ChatCompletionMessage , ChatDetections , Content ,
41
- DetectorConfig , InputDetectionResult , Message , OrchestratorWarning ,
42
- OutputDetectionResult , Role ,
38
+ InputDetectionResult , Message , OrchestratorWarning , OutputDetectionResult , Role ,
43
39
} ,
44
40
} ,
45
41
models:: {
@@ -164,9 +160,13 @@ async fn no_detections() -> Result<(), anyhow::Error> {
164
160
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
165
161
. json ( & json ! ( {
166
162
"model" : MODEL_ID ,
167
- "detectors" : DetectorConfig {
168
- input: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
169
- output: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
163
+ "detectors" : {
164
+ "input" : {
165
+ detector_name: { } ,
166
+ } ,
167
+ "output" : {
168
+ detector_name: { } ,
169
+ } ,
170
170
} ,
171
171
"messages" : messages,
172
172
} ) )
@@ -288,9 +288,11 @@ async fn input_detections() -> Result<(), anyhow::Error> {
288
288
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
289
289
. json ( & json ! ( {
290
290
"model" : MODEL_ID ,
291
- "detectors" : DetectorConfig {
292
- input: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
293
- output: HashMap :: new( ) ,
291
+ "detectors" : {
292
+ "input" : {
293
+ detector_name: { } ,
294
+ } ,
295
+ "output" : { }
294
296
} ,
295
297
"messages" : messages,
296
298
} ) )
@@ -445,9 +447,11 @@ async fn input_client_error() -> Result<(), anyhow::Error> {
445
447
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
446
448
. json ( & json ! ( {
447
449
"model" : MODEL_ID ,
448
- "detectors" : DetectorConfig {
449
- input: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
450
- output: HashMap :: new( ) ,
450
+ "detectors" : {
451
+ "input" : {
452
+ detector_name: { } ,
453
+ } ,
454
+ "output" : { }
451
455
} ,
452
456
"messages" : messages_chunker_error. clone( ) ,
453
457
} ) )
@@ -463,9 +467,11 @@ async fn input_client_error() -> Result<(), anyhow::Error> {
463
467
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
464
468
. json ( & json ! ( {
465
469
"model" : MODEL_ID ,
466
- "detectors" : DetectorConfig {
467
- input: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
468
- output: HashMap :: new( ) ,
470
+ "detectors" : {
471
+ "input" : {
472
+ detector_name: { } ,
473
+ } ,
474
+ "output" : { }
469
475
} ,
470
476
"messages" : messages_detector_error. clone( ) ,
471
477
} ) )
@@ -481,9 +487,11 @@ async fn input_client_error() -> Result<(), anyhow::Error> {
481
487
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
482
488
. json ( & json ! ( {
483
489
"model" : MODEL_ID ,
484
- "detectors" : DetectorConfig {
485
- input: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
486
- output: HashMap :: new( ) ,
490
+ "detectors" : {
491
+ "input" : {
492
+ detector_name: { } ,
493
+ } ,
494
+ "output" : { }
487
495
} ,
488
496
"messages" : messages_chat_completions_error. clone( ) ,
489
497
} ) )
@@ -664,9 +672,11 @@ async fn output_detections() -> Result<(), anyhow::Error> {
664
672
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
665
673
. json ( & json ! ( {
666
674
"model" : MODEL_ID ,
667
- "detectors" : DetectorConfig {
668
- input: HashMap :: new( ) ,
669
- output: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
675
+ "detectors" : {
676
+ "input" : { } ,
677
+ "output" : {
678
+ detector_name: { } ,
679
+ } ,
670
680
} ,
671
681
"messages" : messages,
672
682
} ) )
@@ -840,9 +850,11 @@ async fn output_client_error() -> Result<(), anyhow::Error> {
840
850
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
841
851
. json ( & json ! ( {
842
852
"model" : MODEL_ID ,
843
- "detectors" : DetectorConfig {
844
- input: HashMap :: new( ) ,
845
- output: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
853
+ "detectors" : {
854
+ "input" : { } ,
855
+ "output" : {
856
+ detector_name: { } ,
857
+ } ,
846
858
} ,
847
859
"messages" : messages_chunker_error. clone( ) ,
848
860
} ) )
@@ -858,9 +870,11 @@ async fn output_client_error() -> Result<(), anyhow::Error> {
858
870
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
859
871
. json ( & json ! ( {
860
872
"model" : MODEL_ID ,
861
- "detectors" : DetectorConfig {
862
- input: HashMap :: new( ) ,
863
- output: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
873
+ "detectors" : {
874
+ "input" : { } ,
875
+ "output" : {
876
+ detector_name: { } ,
877
+ } ,
864
878
} ,
865
879
"messages" : messages_detector_error. clone( ) ,
866
880
} ) )
@@ -876,9 +890,11 @@ async fn output_client_error() -> Result<(), anyhow::Error> {
876
890
. post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
877
891
. json ( & json ! ( {
878
892
"model" : MODEL_ID ,
879
- "detectors" : DetectorConfig {
880
- input: HashMap :: new( ) ,
881
- output: HashMap :: from( [ ( detector_name. into( ) , DetectorParams :: new( ) ) ] ) ,
893
+ "detectors" : {
894
+ "input" : { } ,
895
+ "output" : {
896
+ detector_name: { } ,
897
+ } ,
882
898
} ,
883
899
"messages" : messages_chat_completions_error. clone( ) ,
884
900
} ) )
@@ -891,3 +907,135 @@ async fn output_client_error() -> Result<(), anyhow::Error> {
891
907
892
908
Ok ( ( ) )
893
909
}
910
+
911
+ // Validate that invalid orchestrator requests returns 422 error
912
+ #[ test( tokio:: test) ]
913
+ async fn orchestrator_validation_error ( ) -> Result < ( ) , anyhow:: Error > {
914
+ // Start orchestrator server and its dependencies
915
+ let orchestrator_server = TestOrchestratorServer :: builder ( )
916
+ . config_path ( ORCHESTRATOR_CONFIG_FILE_PATH )
917
+ . build ( )
918
+ . await ?;
919
+
920
+ let messages = vec ! [ Message {
921
+ content: Some ( Content :: Text ( "Hi there!" . to_string( ) ) ) ,
922
+ role: Role :: User ,
923
+ ..Default :: default ( )
924
+ } ] ;
925
+
926
+ // Invalid input detector scenario
927
+ let response = orchestrator_server
928
+ . post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
929
+ . json ( & json ! ( {
930
+ "model" : MODEL_ID ,
931
+ "detectors" : {
932
+ "input" : {
933
+ ANSWER_RELEVANCE_DETECTOR : { } ,
934
+ } ,
935
+ "output" : { }
936
+ } ,
937
+ "messages" : messages. clone( ) ,
938
+ } ) )
939
+ . send ( )
940
+ . await ?;
941
+
942
+ let results = response. json :: < OrchestratorError > ( ) . await ?;
943
+ debug ! ( "{results:#?}" ) ;
944
+ assert_eq ! (
945
+ results,
946
+ OrchestratorError {
947
+ code: 422 ,
948
+ details: format!(
949
+ "detector `{}` is not supported by this endpoint" ,
950
+ ANSWER_RELEVANCE_DETECTOR
951
+ )
952
+ } ,
953
+ "failed on invalid input detector scenario"
954
+ ) ;
955
+
956
+ // Non-existing input detector scenario
957
+ let response = orchestrator_server
958
+ . post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
959
+ . json ( & json ! ( {
960
+ "model" : MODEL_ID ,
961
+ "detectors" : {
962
+ "input" : {
963
+ NON_EXISTING_DETECTOR : { } ,
964
+ } ,
965
+ "output" : { }
966
+ } ,
967
+ "messages" : messages. clone( ) ,
968
+ } ) )
969
+ . send ( )
970
+ . await ?;
971
+
972
+ let results = response. json :: < OrchestratorError > ( ) . await ?;
973
+ debug ! ( "{results:#?}" ) ;
974
+ assert_eq ! (
975
+ results,
976
+ OrchestratorError {
977
+ code: 404 ,
978
+ details: format!( "detector `{}` not found" , NON_EXISTING_DETECTOR )
979
+ } ,
980
+ "failed on non-existing input detector scenario"
981
+ ) ;
982
+
983
+ // Invalid output detector scenario
984
+ let response = orchestrator_server
985
+ . post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
986
+ . json ( & json ! ( {
987
+ "model" : MODEL_ID ,
988
+ "detectors" : {
989
+ "input" : { } ,
990
+ "output" : {
991
+ ANSWER_RELEVANCE_DETECTOR : { } ,
992
+ } ,
993
+ } ,
994
+ "messages" : messages. clone( ) ,
995
+ } ) )
996
+ . send ( )
997
+ . await ?;
998
+
999
+ let results = response. json :: < OrchestratorError > ( ) . await ?;
1000
+ debug ! ( "{results:#?}" ) ;
1001
+ assert_eq ! (
1002
+ results,
1003
+ OrchestratorError {
1004
+ code: 422 ,
1005
+ details: format!(
1006
+ "detector `{}` is not supported by this endpoint" ,
1007
+ ANSWER_RELEVANCE_DETECTOR
1008
+ )
1009
+ } ,
1010
+ "failed on invalid output detector scenario"
1011
+ ) ;
1012
+
1013
+ // Non-existing output detector scenario
1014
+ let response = orchestrator_server
1015
+ . post ( ORCHESTRATOR_CHAT_COMPLETIONS_DETECTION_ENDPOINT )
1016
+ . json ( & json ! ( {
1017
+ "model" : MODEL_ID ,
1018
+ "detectors" : {
1019
+ "input" : { } ,
1020
+ "output" : {
1021
+ NON_EXISTING_DETECTOR : { } ,
1022
+ }
1023
+ } ,
1024
+ "messages" : messages. clone( ) ,
1025
+ } ) )
1026
+ . send ( )
1027
+ . await ?;
1028
+
1029
+ let results = response. json :: < OrchestratorError > ( ) . await ?;
1030
+ debug ! ( "{results:#?}" ) ;
1031
+ assert_eq ! (
1032
+ results,
1033
+ OrchestratorError {
1034
+ code: 404 ,
1035
+ details: format!( "detector `{}` not found" , NON_EXISTING_DETECTOR )
1036
+ } ,
1037
+ "failed on non-existing input detector scenario"
1038
+ ) ;
1039
+
1040
+ Ok ( ( ) )
1041
+ }
0 commit comments