@@ -16,7 +16,7 @@ async fn new_entity_store() {
1616
1717proptest ! {
1818 #[ test]
19- fn it_works_for_any_registration_order( registrations in model:: walk( 3 ) ) {
19+ fn it_works_for_any_registration_order( registrations in model:: walk( 6 ) ) {
2020 tokio:: runtime:: Builder :: new_current_thread( )
2121 . enable_all( )
2222 . build( )
@@ -25,9 +25,9 @@ proptest! {
2525 let ( mut entity_store, _mqtt_output) = entity:: server( "device-under-test" ) ;
2626 let mut state = model:: State :: new( ) ;
2727
28- for step in registrations {
29- let expected_updates = state. apply( step . clone( ) ) ;
30- let actual_updates = match entity_store. handle( step . into( ) ) . await {
28+ for ( protocol , action ) in registrations {
29+ let expected_updates = state. apply( protocol , action . clone( ) ) ;
30+ let actual_updates = match entity_store. handle( ( protocol , action ) . into( ) ) . await {
3131 EntityStoreResponse :: Create ( Ok ( registered_entities) ) => {
3232 registered_entities
3333 . iter( )
@@ -115,6 +115,14 @@ mod model {
115115 use tedge_api:: entity:: EntityType ;
116116 use tedge_api:: entity_store:: EntityRegistrationMessage ;
117117 use tedge_api:: mqtt_topics:: EntityTopicId ;
118+ use tedge_api:: mqtt_topics:: MqttSchema ;
119+
120+ #[ derive( Debug , Copy , Clone , Eq , PartialEq ) ]
121+ #[ allow( clippy:: upper_case_acronyms) ]
122+ pub enum Protocol {
123+ HTTP ,
124+ MQTT ,
125+ }
118126
119127 #[ derive( Debug , Clone ) ]
120128 pub enum Action {
@@ -206,17 +214,23 @@ mod model {
206214 }
207215 }
208216
217+ impl From < Action > for EntityRegistrationMessage {
218+ fn from ( action : Action ) -> Self {
219+ EntityRegistrationMessage {
220+ topic_id : action. topic_id ( ) ,
221+ external_id : None ,
222+ r#type : action. target_type ( ) ,
223+ parent : action. parent_topic_id ( ) ,
224+ other : action. properties ( ) ,
225+ }
226+ }
227+ }
228+
209229 impl From < Action > for EntityStoreRequest {
210230 fn from ( action : Action ) -> Self {
211231 match & action {
212232 Action :: AddDevice { .. } | Action :: AddService { .. } => {
213- let registration = EntityRegistrationMessage {
214- topic_id : action. topic_id ( ) ,
215- external_id : None ,
216- r#type : action. target_type ( ) ,
217- parent : action. parent_topic_id ( ) ,
218- other : action. properties ( ) ,
219- } ;
233+ let registration = EntityRegistrationMessage :: from ( action) ;
220234 EntityStoreRequest :: Create ( registration)
221235 }
222236
@@ -227,6 +241,19 @@ mod model {
227241 }
228242 }
229243
244+ impl From < ( Protocol , Action ) > for EntityStoreRequest {
245+ fn from ( ( protocol, action) : ( Protocol , Action ) ) -> Self {
246+ match protocol {
247+ Protocol :: HTTP => EntityStoreRequest :: from ( action) ,
248+ Protocol :: MQTT => {
249+ let registration = EntityRegistrationMessage :: from ( action) ;
250+ let message = registration. to_mqtt_message ( & MqttSchema :: default ( ) ) ;
251+ EntityStoreRequest :: MqttMessage ( message)
252+ }
253+ }
254+ }
255+ }
256+
230257 type PropMap = serde_json:: Map < String , serde_json:: Value > ;
231258
232259 pub struct State {
@@ -240,35 +267,60 @@ mod model {
240267 entities : HashMap :: default ( ) ,
241268 registered : HashSet :: default ( ) ,
242269 } ;
243- state. apply ( Action :: AddDevice {
244- topic : "" . to_string ( ) ,
245- props : vec ! [ ] ,
246- } ) ;
270+ state. apply (
271+ Protocol :: HTTP ,
272+ Action :: AddDevice {
273+ topic : "" . to_string ( ) ,
274+ props : vec ! [ ] ,
275+ } ,
276+ ) ;
247277 state
248278 }
249279
250- pub fn apply ( & mut self , action : Action ) -> HashSet < EntityTopicId > {
280+ pub fn apply ( & mut self , protocol : Protocol , action : Action ) -> HashSet < EntityTopicId > {
251281 let topic = action. topic_id ( ) ;
252282
253283 match action {
254284 Action :: AddDevice { .. } | Action :: AddService { .. } => {
285+ let parent = action. parent_topic_id ( ) ;
286+
287+ if let Some ( parent) = parent. as_ref ( ) {
288+ if protocol == Protocol :: HTTP && !self . registered . contains ( parent) {
289+ // Under HTTP, registering a child before its parent is an error
290+ return HashSet :: new ( ) ;
291+ }
292+ }
293+
255294 if self . entities . contains_key ( & topic) {
256295 HashSet :: new ( )
257296 } else {
258297 let entity_type = action. target_type ( ) ;
259- let parent = action. parent_topic_id ( ) ;
260298 self . entities . insert (
261299 topic. clone ( ) ,
262300 ( entity_type, parent. clone ( ) , action. properties ( ) ) ,
263301 ) ;
264- self . register ( topic, parent)
302+
303+ let new_entities = self . register ( topic, parent) ;
304+ if protocol == Protocol :: HTTP {
305+ new_entities
306+ } else {
307+ // Under MQTT, no response is sent back
308+ HashSet :: new ( )
309+ }
265310 }
266311 }
267312
268313 Action :: RemDevice { .. } | Action :: RemService { .. } => {
269314 if self . entities . contains_key ( & topic) {
270315 self . entities . remove ( & topic) ;
271- self . deregister ( topic)
316+
317+ let old_entities = self . deregister ( topic) ;
318+ if protocol == Protocol :: HTTP {
319+ old_entities
320+ } else {
321+ // Under MQTT, no response is sent back
322+ HashSet :: new ( )
323+ }
272324 } else {
273325 HashSet :: new ( )
274326 }
@@ -357,6 +409,16 @@ mod model {
357409 }
358410 }
359411
412+ prop_compose ! {
413+ pub fn random_protocol( ) ( protocol in "[hm]" ) -> Protocol {
414+ if protocol == "h" {
415+ Protocol :: HTTP
416+ } else {
417+ Protocol :: MQTT
418+ }
419+ }
420+ }
421+
360422 prop_compose ! {
361423 pub fn random_name( ) ( id in "[abc]{1,3}" ) -> String {
362424 id. to_string( )
@@ -376,43 +438,56 @@ mod model {
376438 }
377439
378440 prop_compose ! {
379- pub fn random_prop( ) ( key in random_key( ) , value in random_value( ) ) -> ( String , String ) {
441+ pub fn random_prop( ) (
442+ key in random_key( ) ,
443+ value in random_value( )
444+ ) -> ( String , String ) {
380445 ( key, value)
381446 }
382447 }
383448
384449 prop_compose ! {
385- pub fn random_props( max_length: usize )
386- ( vec in prop:: collection:: vec( random_prop( ) , 0 ..max_length) ) -> Vec <( String , String ) >
387- {
450+ pub fn random_props( max_length: usize ) (
451+ vec in prop:: collection:: vec( random_prop( ) ,
452+ 0 ..max_length)
453+ ) -> Vec <( String , String ) >
454+ {
388455 vec
389- }
456+ }
390457 }
391458
392459 prop_compose ! {
393- pub fn pick_random_or_new( names: Vec <String >) ( id in 0 ..( names. len( ) +1 ) , name in random_name( ) ) -> String {
460+ pub fn pick_random_or_new( names: Vec <String >) (
461+ id in 0 ..( names. len( ) +1 ) ,
462+ name in random_name( )
463+ ) -> String {
394464 names. get( id) . map( |n| n. to_owned( ) ) . unwrap_or( name)
395465 }
396466 }
397467
398468 prop_compose ! {
399- pub fn random_action_on( topic: String ) ( action in 1 ..5 , props in random_props( 2 ) ) -> Action {
469+ pub fn random_action_on( topic: String ) (
470+ protocol in random_protocol( ) ,
471+ action in 1 ..5 ,
472+ props in random_props( 2 )
473+ ) -> ( Protocol , Action ) {
400474 let topic = topic. to_owned( ) ;
401- match action {
475+ let action = match action {
402476 1 => Action :: AddDevice { topic, props } ,
403477 2 => Action :: AddService { topic, props } ,
404478 3 => Action :: RemService { topic } ,
405479 _ => Action :: RemDevice { topic } ,
406- }
480+ } ;
481+ ( protocol, action)
407482 }
408483 }
409484
410- pub fn random_action ( ) -> impl Strategy < Value = Action > {
485+ pub fn random_action ( ) -> impl Strategy < Value = ( Protocol , Action ) > {
411486 random_name ( ) . prop_flat_map ( random_action_on)
412487 }
413488
414- fn step ( actions : Vec < Action > ) -> impl Strategy < Value = Vec < Action > > {
415- let nodes = actions. iter ( ) . map ( |a | a. target ( ) . to_owned ( ) ) . collect ( ) ;
489+ fn step ( actions : Vec < ( Protocol , Action ) > ) -> impl Strategy < Value = Vec < ( Protocol , Action ) > > {
490+ let nodes = actions. iter ( ) . map ( |( _ , a ) | a. target ( ) . to_owned ( ) ) . collect ( ) ;
416491 pick_random_or_new ( nodes)
417492 . prop_flat_map ( random_action_on)
418493 . prop_flat_map ( move |action| {
@@ -422,7 +497,7 @@ mod model {
422497 } )
423498 }
424499
425- pub fn walk ( max_length : u32 ) -> impl Strategy < Value = Vec < Action > > {
500+ pub fn walk ( max_length : u32 ) -> impl Strategy < Value = Vec < ( Protocol , Action ) > > {
426501 if max_length == 0 {
427502 Just ( vec ! [ ] ) . boxed ( )
428503 } else if max_length == 1 {
0 commit comments