11using Devolutions . Now . Policy . Api ;
2+ using Devolutions . Now . Policy . Client ;
23using UniGetUI . PackageEngine . AgentBroker ;
34using UniGetUI . PackageEngine . Serializable ;
45using UniGetUI . PackageEngine . Tests . Infrastructure . Builders ;
@@ -16,6 +17,12 @@ private static UniGetUI.PackageEngine.PackageClasses.Package BuildWinGetPackage(
1617 . WithId ( "Contoso.Test" )
1718 . Build ( ) ;
1819
20+ private static UniGetUI . PackageEngine . PackageClasses . Package BuildPipPackage ( )
21+ => new PackageBuilder ( )
22+ . WithManager ( new PackageManagerBuilder ( ) . WithName ( "Pip" ) . Build ( ) )
23+ . WithId ( "requests" )
24+ . Build ( ) ;
25+
1926 private static UniGetUI . PackageEngine . PackageClasses . Package BuildPowerShellPackage ( )
2027 => new PackageBuilder ( )
2128 . WithManager ( new PackageManagerBuilder ( ) . WithName ( "PowerShell" ) . Build ( ) )
@@ -100,6 +107,71 @@ public void Build_PackageScopeOverride_TakesPrecedenceOverSavedScope()
100107 Assert . Equal ( Scope . User , request . Options . Scope ) ;
101108 }
102109
110+ [ Fact ]
111+ public void Build_OmitsMachineScopeForPip ( )
112+ {
113+ var package = BuildPipPackage ( ) ;
114+ package . OverridenOptions . Scope = PackageScope . Global ;
115+ var options = new InstallOptions { InstallationScope = PackageScope . Machine } ;
116+
117+ var request = BrokerRequestBuilder . Build ( package , options , OperationType . Update ) ;
118+
119+ Assert . Null ( request . Options . Scope ) ;
120+ }
121+
122+ [ Fact ]
123+ public void Build_KeepsUserScopeForPip ( )
124+ {
125+ var package = BuildPipPackage ( ) ;
126+ package . OverridenOptions . Scope = PackageScope . User ;
127+
128+ var request = BrokerRequestBuilder . Build ( package , new InstallOptions ( ) , OperationType . Update ) ;
129+
130+ Assert . Equal ( Scope . User , request . Options . Scope ) ;
131+ }
132+
133+ [ Fact ]
134+ public void Build_OmitsAConfiguredMachineScopeForPip ( )
135+ {
136+ var package = BuildPipPackage ( ) ;
137+ var options = new InstallOptions { InstallationScope = PackageScope . Machine } ;
138+
139+ var request = BrokerRequestBuilder . Build ( package , options , OperationType . Install ) ;
140+
141+ Assert . Null ( request . Options . Scope ) ;
142+ }
143+
144+ [ Fact ]
145+ public void Build_KeepsAConfiguredMachineScopeForManagersThatResolveIt ( )
146+ {
147+ var package = BuildWinGetPackage ( ) ;
148+ var options = new InstallOptions { InstallationScope = PackageScope . Machine } ;
149+
150+ var request = BrokerRequestBuilder . Build ( package , options , OperationType . Install ) ;
151+
152+ Assert . Equal ( Scope . Machine , request . Options . Scope ) ;
153+ }
154+
155+ [ Fact ]
156+ public void Build_OmitsTheSourceUrlForPipButKeepsTheSourceName ( )
157+ {
158+ var package = BuildPipPackage ( ) ;
159+
160+ var request = BrokerRequestBuilder . Build ( package , new InstallOptions ( ) , OperationType . Update ) ;
161+
162+ Assert . Null ( request . Source . Url ) ;
163+ Assert . Equal ( package . Source . Name , request . Source . Name ) ;
164+ }
165+
166+ [ Fact ]
167+ public void Build_KeepsTheSourceUrlForOtherManagers ( )
168+ {
169+ var package = BuildWinGetPackage ( ) ;
170+
171+ var request = BrokerRequestBuilder . Build ( package , new InstallOptions ( ) , OperationType . Update ) ;
172+
173+ Assert . Equal ( package . Source . Url ? . ToString ( ) , request . Source . Url ) ;
174+ }
103175 [ Fact ]
104176 public void Build_DropArchAndScopeRetry_OmitsScopeAndArchitecture ( )
105177 {
@@ -310,4 +382,104 @@ public void Build_KeepsWinGetVersionsThatAreNotPlainVersions()
310382 Assert . Equal ( "2021 Update" , request . Package . Version ) ;
311383 }
312384
385+ [ Fact ]
386+ public async Task Build_PipUpdateRequest_ClearsTheBrokerCapabilityCheck ( )
387+ {
388+ var package = BuildPipPackage ( ) ;
389+ package . OverridenOptions . Scope = PackageScope . Global ;
390+
391+ var request = BrokerRequestBuilder . Build ( package , new InstallOptions ( ) , OperationType . Update ) ;
392+
393+ using var client = CreatePipBrokerClient ( ) ;
394+
395+ var execution = await client . Execute ( request , CancellationToken . None ) ;
396+
397+ Assert . Equal ( Decision . Allow , execution . Decision . Decision ) ;
398+ }
399+
400+ [ Fact ]
401+ public async Task Build_PipRequestWithAConfiguredMachineScope_ClearsTheBrokerCapabilityCheck ( )
402+ {
403+ var package = BuildPipPackage ( ) ;
404+ var options = new InstallOptions { InstallationScope = PackageScope . Machine } ;
405+
406+ var request = BrokerRequestBuilder . Build ( package , options , OperationType . Update ) ;
407+
408+ using var client = CreatePipBrokerClient ( ) ;
409+
410+ var execution = await client . Execute ( request , CancellationToken . None ) ;
411+
412+ Assert . Equal ( Decision . Allow , execution . Decision . Decision ) ;
413+ }
414+
415+ private const string TestEffectiveUser = "TESTDOMAIN\\ tester" ;
416+ private const string TestClientExecutablePath = "C:\\ test\\ unigetui.exe" ;
417+
418+ private static BrokerClient CreatePipBrokerClient ( )
419+ => new ( new BrokerClientOptions
420+ {
421+ Transport = new PipCapabilityTransport ( ) ,
422+ RequestedElevation = Elevation . Standard ,
423+ EffectiveUser = TestEffectiveUser ,
424+ ClientExecutablePath = TestClientExecutablePath ,
425+ ClientVersion = "0.0.0-tests" ,
426+ } ) ;
427+
428+ private sealed class PipCapabilityTransport : IBrokerTransport
429+ {
430+ public Transport Kind => Transport . HttpNamedPipe ;
431+
432+ public Task < BrokerTransportResponse > Send (
433+ BrokerTransportRequest request ,
434+ CancellationToken cancellationToken = default
435+ ) => request . Path switch
436+ {
437+ "/v1/capabilities" => Json ( BrokerSerializer . Serialize ( Capabilities ( ) ) ) ,
438+ "/v1/package-operations/execute" => Json ( BrokerSerializer . Serialize ( Execution ( ) ) ) ,
439+ _ => throw new BrokerClientException (
440+ BrokerClientErrorKind . InvalidRequest ,
441+ $ "Unexpected request path: { request . Path } ",
442+ request . Path
443+ ) ,
444+ } ;
445+
446+ public void Dispose ( ) { }
447+
448+ private static Task < BrokerTransportResponse > Json ( string body ) =>
449+ Task . FromResult ( new BrokerTransportResponse { StatusCode = 200 , Body = body } ) ;
450+
451+ private static CapabilitiesResponse Capabilities ( ) => new ( )
452+ {
453+ ResponseKind = BrokerApi . CapabilitiesResponseKind ,
454+ ResponseVersion = BrokerApi . Version ,
455+ MaxRequestBodyBytes = 1_000_000 ,
456+ Transports = [ Transport . HttpNamedPipe ] ,
457+ Managers =
458+ [
459+ new ManagerCapability
460+ {
461+ Manager = ManagerName . Pip ,
462+ Operations = [ Operation . Install , Operation . Update , Operation . Uninstall ] ,
463+ Scopes = [ Scope . User ] ,
464+ Architectures = [ Architecture . Neutral ] ,
465+ SupportsCustomParameters = false ,
466+ SupportsCustomInstallLocation = false ,
467+ SupportsCaptureOutput = true ,
468+ } ,
469+ ] ,
470+ } ;
471+
472+ private static ExecutionResponse Execution ( ) => new ( )
473+ {
474+ ResponseKind = BrokerApi . ExecutionResponseKind ,
475+ ResponseVersion = BrokerApi . Version ,
476+ Decision = new DecisionInfo { Decision = Decision . Allow } ,
477+ Operation = new OperationSubmission
478+ {
479+ OperationId = "test-pip-operation" ,
480+ Status = OperationStatus . Starting ,
481+ SubmittedAt = DateTimeOffset . UtcNow ,
482+ } ,
483+ } ;
484+ }
313485}
0 commit comments