@@ -18,7 +18,9 @@ use definition::WorldName;
18
18
pub struct TargetEnvironment {
19
19
name : String ,
20
20
trigger_worlds : HashMap < TriggerType , CandidateWorlds > ,
21
+ trigger_capabilities : HashMap < TriggerType , Vec < String > > ,
21
22
unknown_trigger : UnknownTrigger ,
23
+ unknown_capabilities : Vec < String > ,
22
24
}
23
25
24
26
impl TargetEnvironment {
@@ -52,6 +54,13 @@ impl TargetEnvironment {
52
54
. or_else ( || self . unknown_trigger . worlds ( ) )
53
55
. unwrap_or ( NO_WORLDS )
54
56
}
57
+
58
+ /// Lists all host capabilities supported for the given trigger type in this environment.
59
+ pub fn capabilities ( & self , trigger_type : & TriggerType ) -> & [ String ] {
60
+ self . trigger_capabilities
61
+ . get ( trigger_type)
62
+ . unwrap_or ( & self . unknown_capabilities )
63
+ }
55
64
}
56
65
57
66
/// How a `TargetEnvironment` should validate components associated with trigger types
@@ -229,7 +238,9 @@ mod test {
229
238
TargetEnvironment {
230
239
name : "test" . to_owned ( ) ,
231
240
trigger_worlds : [ ( "s" . to_owned ( ) , candidate_worlds) ] . into_iter ( ) . collect ( ) ,
241
+ trigger_capabilities : Default :: default ( ) ,
232
242
unknown_trigger : UnknownTrigger :: Deny ,
243
+ unknown_capabilities : Default :: default ( ) ,
233
244
}
234
245
}
235
246
@@ -242,7 +253,9 @@ mod test {
242
253
TargetEnvironment {
243
254
name : "test" . to_owned ( ) ,
244
255
trigger_worlds : [ ] . into_iter ( ) . collect ( ) ,
256
+ trigger_capabilities : Default :: default ( ) ,
245
257
unknown_trigger : UnknownTrigger :: Allow ( candidate_worlds) ,
258
+ unknown_capabilities : Default :: default ( ) ,
246
259
}
247
260
}
248
261
@@ -260,7 +273,7 @@ mod test {
260
273
assert ! ( env. supports_trigger_type( & "s" . to_owned( ) ) ) ;
261
274
assert ! ( !env. supports_trigger_type( & "t" . to_owned( ) ) ) ;
262
275
263
- let component = crate :: ComponentToValidate :: new ( "scomp" , "scomp.wasm" , wasm) ;
276
+ let component = crate :: ComponentToValidate :: new ( "scomp" , "scomp.wasm" , wasm, vec ! [ ] ) ;
264
277
let errs =
265
278
crate :: validate_component_against_environments ( & [ env] , & "s" . to_owned ( ) , & component)
266
279
. await ;
@@ -291,7 +304,7 @@ mod test {
291
304
292
305
assert ! ( env. supports_trigger_type( & non_existent_trigger) ) ;
293
306
294
- let component = crate :: ComponentToValidate :: new ( "comp" , "comp.wasm" , wasm) ;
307
+ let component = crate :: ComponentToValidate :: new ( "comp" , "comp.wasm" , wasm, vec ! [ ] ) ;
295
308
let errs = crate :: validate_component_against_environments (
296
309
& [ env] ,
297
310
& non_existent_trigger,
@@ -308,6 +321,46 @@ mod test {
308
321
) ;
309
322
}
310
323
324
+ #[ tokio:: test]
325
+ async fn can_validate_component_with_host_requirement ( ) {
326
+ let wit_path = PathBuf :: from ( SIMPLE_WIT_DIR ) ;
327
+
328
+ let wit_text = tokio:: fs:: read_to_string ( wit_path. join ( "world.wit" ) )
329
+ . await
330
+ . unwrap ( ) ;
331
+ let wasm =
generate_dummy_component ( & wit_text
, "spin:test/[email protected] " ) ;
332
+
333
+ let mut env = target_simple_world ( & wit_path) ;
334
+ env. trigger_capabilities . insert (
335
+ "s" . to_owned ( ) ,
336
+ vec ! [
337
+ "local_spline_reticulation" . to_owned( ) ,
338
+ "nice_cup_of_tea" . to_owned( ) ,
339
+ ] ,
340
+ ) ;
341
+
342
+ assert ! ( env. supports_trigger_type( & "s" . to_owned( ) ) ) ;
343
+ assert ! ( !env. supports_trigger_type( & "t" . to_owned( ) ) ) ;
344
+
345
+ let component = crate :: ComponentToValidate :: new (
346
+ "cscomp" ,
347
+ "cscomp.wasm" ,
348
+ wasm,
349
+ vec ! [ "nice_cup_of_tea" . to_string( ) ] ,
350
+ ) ;
351
+ let errs =
352
+ crate :: validate_component_against_environments ( & [ env] , & "s" . to_owned ( ) , & component)
353
+ . await ;
354
+ assert ! (
355
+ errs. is_empty( ) ,
356
+ "{}" ,
357
+ errs. iter( )
358
+ . map( |e| e. to_string( ) )
359
+ . collect:: <Vec <_>>( )
360
+ . join( "\n " )
361
+ ) ;
362
+ }
363
+
311
364
#[ tokio:: test]
312
365
async fn unavailable_import_invalidates_component ( ) {
313
366
let wit_path = PathBuf :: from ( SIMPLE_WIT_DIR ) ;
@@ -319,7 +372,7 @@ mod test {
319
372
320
373
let env = target_simple_world ( & wit_path) ;
321
374
322
- let component = crate :: ComponentToValidate :: new ( "nscomp" , "nscomp.wasm" , wasm) ;
375
+ let component = crate :: ComponentToValidate :: new ( "nscomp" , "nscomp.wasm" , wasm, vec ! [ ] ) ;
323
376
let errs =
324
377
crate :: validate_component_against_environments ( & [ env] , & "s" . to_owned ( ) , & component)
325
378
. await ;
@@ -346,7 +399,7 @@ mod test {
346
399
347
400
let env = target_simple_world ( & wit_path) ;
348
401
349
- let component = crate :: ComponentToValidate :: new ( "tdscomp" , "tdscomp.wasm" , wasm) ;
402
+ let component = crate :: ComponentToValidate :: new ( "tdscomp" , "tdscomp.wasm" , wasm, vec ! [ ] ) ;
350
403
let errs =
351
404
crate :: validate_component_against_environments ( & [ env] , & "s" . to_owned ( ) , & component)
352
405
. await ;
@@ -359,6 +412,39 @@ mod test {
359
412
) ;
360
413
}
361
414
415
+ #[ tokio:: test]
416
+ async fn unsupported_host_req_invalidates_component ( ) {
417
+ let wit_path = PathBuf :: from ( SIMPLE_WIT_DIR ) ;
418
+
419
+ let wit_text = tokio:: fs:: read_to_string ( wit_path. join ( "world.wit" ) )
420
+ . await
421
+ . unwrap ( ) ;
422
+ let wasm =
generate_dummy_component ( & wit_text
, "spin:test/[email protected] " ) ;
423
+
424
+ let env = target_simple_world ( & wit_path) ;
425
+
426
+ assert ! ( env. supports_trigger_type( & "s" . to_owned( ) ) ) ;
427
+ assert ! ( !env. supports_trigger_type( & "t" . to_owned( ) ) ) ;
428
+
429
+ let component = crate :: ComponentToValidate :: new (
430
+ "cscomp" ,
431
+ "cscomp.wasm" ,
432
+ wasm,
433
+ vec ! [ "nice_cup_of_tea" . to_string( ) ] ,
434
+ ) ;
435
+ let errs =
436
+ crate :: validate_component_against_environments ( & [ env] , & "s" . to_owned ( ) , & component)
437
+ . await ;
438
+ assert ! ( !errs. is_empty( ) ) ;
439
+
440
+ let err = errs[ 0 ] . to_string ( ) ;
441
+ assert ! (
442
+ err. contains( "Component cscomp can't run in environment test" ) ,
443
+ "unexpected error {err}"
444
+ ) ;
445
+ assert ! ( err. contains( "nice_cup_of_tea" ) , "unexpected error {err}" ) ;
446
+ }
447
+
362
448
fn generate_dummy_component ( wit : & str , world : & str ) -> Vec < u8 > {
363
449
let mut resolve = wit_parser:: Resolve :: default ( ) ;
364
450
let package_id = resolve. push_str ( "test" , wit) . expect ( "should parse WIT" ) ;
0 commit comments