@@ -438,4 +438,197 @@ public void FullDeviceId_IsNonEmpty()
438438 Directory . Delete ( dataPath , true ) ;
439439 }
440440 }
441+
442+ [ Fact ]
443+ public void SetPermission_UpdatesRegistrationPermissions ( )
444+ {
445+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
446+ Directory . CreateDirectory ( dataPath ) ;
447+
448+ try
449+ {
450+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
451+
452+ client . SetPermission ( "camera.capture" , true ) ;
453+ client . SetPermission ( "screen.record" , false ) ;
454+
455+ var registrationField = typeof ( WindowsNodeClient ) . GetField (
456+ "_registration" ,
457+ BindingFlags . NonPublic | BindingFlags . Instance ) ;
458+ var reg = ( NodeRegistration ) registrationField ! . GetValue ( client ) ! ;
459+
460+ Assert . True ( reg . Permissions . ContainsKey ( "camera.capture" ) ) ;
461+ Assert . True ( reg . Permissions [ "camera.capture" ] ) ;
462+ Assert . True ( reg . Permissions . ContainsKey ( "screen.record" ) ) ;
463+ Assert . False ( reg . Permissions [ "screen.record" ] ) ;
464+ }
465+ finally
466+ {
467+ if ( Directory . Exists ( dataPath ) )
468+ Directory . Delete ( dataPath , true ) ;
469+ }
470+ }
471+
472+ [ Fact ]
473+ public void SetPermission_OverwritesPreviousValue ( )
474+ {
475+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
476+ Directory . CreateDirectory ( dataPath ) ;
477+
478+ try
479+ {
480+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
481+
482+ client . SetPermission ( "camera.capture" , true ) ;
483+ client . SetPermission ( "camera.capture" , false ) ;
484+
485+ var registrationField = typeof ( WindowsNodeClient ) . GetField (
486+ "_registration" ,
487+ BindingFlags . NonPublic | BindingFlags . Instance ) ;
488+ var reg = ( NodeRegistration ) registrationField ! . GetValue ( client ) ! ;
489+
490+ Assert . False ( reg . Permissions [ "camera.capture" ] ) ;
491+ }
492+ finally
493+ {
494+ if ( Directory . Exists ( dataPath ) )
495+ Directory . Delete ( dataPath , true ) ;
496+ }
497+ }
498+
499+ [ Fact ]
500+ public async Task DisconnectAsync_RaisesDisconnectedStatus ( )
501+ {
502+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
503+ Directory . CreateDirectory ( dataPath ) ;
504+
505+ try
506+ {
507+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
508+
509+ var statusChanges = new List < ConnectionStatus > ( ) ;
510+ client . StatusChanged += ( _ , s ) => statusChanges . Add ( s ) ;
511+
512+ await client . DisconnectAsync ( ) ;
513+
514+ Assert . Contains ( ConnectionStatus . Disconnected , statusChanges ) ;
515+ }
516+ finally
517+ {
518+ if ( Directory . Exists ( dataPath ) )
519+ Directory . Delete ( dataPath , true ) ;
520+ }
521+ }
522+
523+ [ Fact ]
524+ public async Task ProcessMessageAsync_InvalidJson_DoesNotThrow ( )
525+ {
526+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
527+ Directory . CreateDirectory ( dataPath ) ;
528+
529+ try
530+ {
531+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
532+
533+ var processMethod = typeof ( WindowsNodeClient ) . GetMethod (
534+ "ProcessMessageAsync" ,
535+ BindingFlags . NonPublic | BindingFlags . Instance ) ;
536+ Assert . NotNull ( processMethod ) ;
537+
538+ var task = ( Task ) processMethod ! . Invoke ( client , [ "not-valid-json!!" ] ) ! ;
539+ var ex = await Record . ExceptionAsync ( ( ) => task ) ;
540+ Assert . Null ( ex ) ;
541+ }
542+ finally
543+ {
544+ if ( Directory . Exists ( dataPath ) )
545+ Directory . Delete ( dataPath , true ) ;
546+ }
547+ }
548+
549+ [ Fact ]
550+ public async Task ProcessMessageAsync_NoTypeField_DoesNotThrow ( )
551+ {
552+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
553+ Directory . CreateDirectory ( dataPath ) ;
554+
555+ try
556+ {
557+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
558+
559+ var processMethod = typeof ( WindowsNodeClient ) . GetMethod (
560+ "ProcessMessageAsync" ,
561+ BindingFlags . NonPublic | BindingFlags . Instance ) ;
562+
563+ var task = ( Task ) processMethod ! . Invoke ( client , [ """{"ok":true}""" ] ) ! ;
564+ var ex = await Record . ExceptionAsync ( ( ) => task ) ;
565+ Assert . Null ( ex ) ;
566+ }
567+ finally
568+ {
569+ if ( Directory . Exists ( dataPath ) )
570+ Directory . Delete ( dataPath , true ) ;
571+ }
572+ }
573+
574+ [ Fact ]
575+ public async Task ProcessMessageAsync_UnknownMessageType_DoesNotThrow ( )
576+ {
577+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
578+ Directory . CreateDirectory ( dataPath ) ;
579+
580+ try
581+ {
582+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
583+
584+ var processMethod = typeof ( WindowsNodeClient ) . GetMethod (
585+ "ProcessMessageAsync" ,
586+ BindingFlags . NonPublic | BindingFlags . Instance ) ;
587+
588+ var task = ( Task ) processMethod ! . Invoke ( client , [ """{"type":"unknown_msg_type"}""" ] ) ! ;
589+ var ex = await Record . ExceptionAsync ( ( ) => task ) ;
590+ Assert . Null ( ex ) ;
591+ }
592+ finally
593+ {
594+ if ( Directory . Exists ( dataPath ) )
595+ Directory . Delete ( dataPath , true ) ;
596+ }
597+ }
598+
599+ [ Fact ]
600+ public void GatewayUrl_ReturnsDisplayUrl ( )
601+ {
602+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
603+ Directory . CreateDirectory ( dataPath ) ;
604+
605+ try
606+ {
607+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
608+ Assert . Equal ( "ws://localhost:18789" , client . GatewayUrl ) ;
609+ }
610+ finally
611+ {
612+ if ( Directory . Exists ( dataPath ) )
613+ Directory . Delete ( dataPath , true ) ;
614+ }
615+ }
616+
617+ [ Fact ]
618+ public void NodeId_IsNullBeforeConnection ( )
619+ {
620+ var dataPath = Path . Combine ( Path . GetTempPath ( ) , $ "openclaw-node-test-{ Guid . NewGuid ( ) : N} ") ;
621+ Directory . CreateDirectory ( dataPath ) ;
622+
623+ try
624+ {
625+ using var client = new WindowsNodeClient ( "ws://localhost:18789" , "test-token" , dataPath ) ;
626+ Assert . Null ( client . NodeId ) ;
627+ }
628+ finally
629+ {
630+ if ( Directory . Exists ( dataPath ) )
631+ Directory . Delete ( dataPath , true ) ;
632+ }
633+ }
441634}
0 commit comments