@@ -809,14 +809,15 @@ impl<P: Publisher> Handler<P> {
809
809
810
810
// Manifest validation
811
811
pub ( crate ) fn validate_manifest ( manifest : Manifest ) -> anyhow:: Result < ( ) > {
812
- let mut component_details: HashSet < String > = HashSet :: new ( ) ;
812
+ let mut name_registry: HashSet < String > = HashSet :: new ( ) ;
813
+ let mut required_capability_components: HashSet < String > = HashSet :: new ( ) ;
813
814
814
815
// Map of link names to a vector of provider references with that link name
815
816
let mut linkdef_map: HashMap < String , Vec < String > > = HashMap :: new ( ) ;
816
817
817
818
for component in manifest. spec . components . iter ( ) {
818
819
// Component name validation : each component (actors or providers) should have a unique name
819
- if !component_details . insert ( component. name . clone ( ) ) {
820
+ if !name_registry . insert ( component. name . clone ( ) ) {
820
821
return Err ( anyhow ! (
821
822
"Duplicate component name in manifest: {}" ,
822
823
component. name
@@ -864,7 +865,7 @@ pub(crate) fn validate_manifest(manifest: Manifest) -> anyhow::Result<()> {
864
865
properties : ActorProperties { image : image_name } ,
865
866
} = & component. properties
866
867
{
867
- if !component_details . insert ( image_name. to_string ( ) ) {
868
+ if !name_registry . insert ( image_name. to_string ( ) ) {
868
869
return Err ( anyhow ! (
869
870
"Duplicate image reference in manifest: {}" ,
870
871
image_name
@@ -888,14 +889,30 @@ pub(crate) fn validate_manifest(manifest: Manifest) -> anyhow::Result<()> {
888
889
{
889
890
if !linkdef_set. insert ( target_name. to_string ( ) ) {
890
891
return Err ( anyhow ! (
891
- "Duplicate target for linkdef in manifest: {}" ,
892
- target_name
892
+ "Duplicate target {} for component {} linkdef trait in manifest" ,
893
+ target_name,
894
+ component. name,
893
895
) ) ;
894
896
}
897
+
898
+ // Multiple components{ with type != 'capability'} can declare the same target, so we don't need to check for duplicates on insert
899
+ required_capability_components. insert ( target_name. to_string ( ) ) ;
895
900
}
896
901
}
897
902
}
898
903
}
904
+
905
+ let missing_capability_components = required_capability_components
906
+ . difference ( & name_registry)
907
+ . collect :: < Vec < & String > > ( ) ;
908
+
909
+ if !missing_capability_components. is_empty ( ) {
910
+ return Err ( anyhow ! (
911
+ "The following capability component(s) are missing from the manifest: {:?}" ,
912
+ missing_capability_components
913
+ ) ) ;
914
+ }
915
+
899
916
Ok ( ( ) )
900
917
}
901
918
@@ -957,9 +974,17 @@ mod test {
957
974
958
975
match validate_manifest ( manifest) {
959
976
Ok ( ( ) ) => panic ! ( "Should have detected duplicate linkdef" ) ,
977
+ Err ( e) => assert ! ( e. to_string( ) . contains( "Duplicate target" ) ) ,
978
+ }
979
+
980
+ let manifest = deserialize_yaml ( "./test/data/missing_capability_component.yaml" )
981
+ . expect ( "Should be able to parse" ) ;
982
+
983
+ match validate_manifest ( manifest) {
984
+ Ok ( ( ) ) => panic ! ( "Should have detected missing capability component" ) ,
960
985
Err ( e) => assert ! ( e
961
986
. to_string( )
962
- . contains( "Duplicate target for linkdef in manifest" ) ) ,
987
+ . contains( "The following capability component(s) are missing from the manifest: " ) ) ,
963
988
}
964
989
}
965
990
0 commit comments