@@ -166,20 +166,13 @@ class OutdatedHostSocket {
166166}
167167
168168describe ( "updateOutdatedHost" , ( ) => {
169- it . effect . each ( [ false , true ] ) ( "updates host, progress loss=%s " , ( progressDisconnect ) =>
169+ it . effect ( "updates a protocol-1 host over a bare socket, then switches it back on " , ( ) =>
170170 Effect . gen ( function * ( ) {
171171 const blocked = orchestrationProtocolCompatibilityError ( descriptor ( undefined , "0.0.45" ) ) ;
172172 expect ( blocked ) . toMatchObject ( { serverUpdateRequired : true } ) ;
173173
174174 const sockets : Array < OutdatedHostSocket > = [ ] ;
175- let served : ExecutionEnvironmentDescriptor = {
176- ...descriptor ( undefined , "0.0.45" ) ,
177- capabilities : {
178- repositoryIdentity : true ,
179- serverSelfUpdate : "boot-service" ,
180- serverSelfUpdateProgress : progressDisconnect ,
181- } ,
182- } ;
175+ let served : ExecutionEnvironmentDescriptor = descriptor ( undefined , "0.0.45" ) ;
183176 const entries = yield * SubscriptionRef . make <
184177 ReadonlyMap < EnvironmentId , ConnectionCatalogEntry >
185178 > (
@@ -227,16 +220,10 @@ describe("updateOutdatedHost", () => {
227220 ) ,
228221 ) ;
229222
230- const stages : Array < string > = [ ] ;
231223 const result = yield * updateOutdatedHost (
232224 TARGET . environmentId ,
233225 { targetVersion : "0.0.46" } ,
234- ( stage ) =>
235- Effect . sync ( ( ) => {
236- stages . push ( stage ) ;
237- // Lose the transport only after the consumer has observed progress.
238- if ( stage === "downloading" ) sockets [ 0 ] ?. close ( ) ;
239- } ) ,
226+ ( ) => Effect . void ,
240227 ) . pipe (
241228 Effect . provide (
242229 Layer . mergeAll (
@@ -265,11 +252,8 @@ describe("updateOutdatedHost", () => {
265252
266253 expect ( sockets [ 0 ] ?. url ) . not . toContain ( "orchestrationProtocol" ) ;
267254 expect ( sockets [ 0 ] ?. requests . map ( ( request ) => request . tag ) ) . toEqual ( [
268- progressDisconnect
269- ? WS_METHODS . serverUpdateServerWithProgress
270- : WS_METHODS . serverUpdateServer ,
255+ WS_METHODS . serverUpdateServer ,
271256 ] ) ;
272- expect ( stages ) . toEqual ( progressDisconnect ? [ "downloading" , "resuming" ] : [ "resuming" ] ) ;
273257 expect ( result . targetVersion ) . toBe ( "0.0.46" ) ;
274258 expect ( calls ) . toEqual ( [ "compatibility:clear" , "enabled:true" ] ) ;
275259 } ) ,
@@ -344,4 +328,111 @@ describe("updateOutdatedHost", () => {
344328 expect ( opened ) . toBe ( false ) ;
345329 } ) ,
346330 ) ;
331+
332+ it . effect ( "resumes an outdated host update after progress transport loss" , ( ) =>
333+ Effect . gen ( function * ( ) {
334+ const blocked = orchestrationProtocolCompatibilityError ( descriptor ( undefined , "0.0.45" ) ) ;
335+ expect ( blocked ) . toMatchObject ( { serverUpdateRequired : true } ) ;
336+
337+ const sockets : Array < OutdatedHostSocket > = [ ] ;
338+ let served : ExecutionEnvironmentDescriptor = {
339+ ...descriptor ( undefined , "0.0.45" ) ,
340+ capabilities : {
341+ repositoryIdentity : true ,
342+ serverSelfUpdate : "boot-service" ,
343+ serverSelfUpdateProgress : true ,
344+ } ,
345+ } ;
346+ const entries = yield * SubscriptionRef . make <
347+ ReadonlyMap < EnvironmentId , ConnectionCatalogEntry >
348+ > (
349+ new Map ( [
350+ [
351+ TARGET . environmentId ,
352+ {
353+ target : TARGET ,
354+ profile : Option . none ( ) ,
355+ enabled : false ,
356+ unsupportedReason : blocked ?. message ?? "" ,
357+ serverUpdateRequired : true ,
358+ } ,
359+ ] ,
360+ ] ) ,
361+ ) ;
362+ const calls : Array < string > = [ ] ;
363+ const registry = EnvironmentRegistry . EnvironmentRegistry . of ( {
364+ entries,
365+ setCompatibility : ( _environmentId : EnvironmentId , error : unknown ) =>
366+ Effect . sync ( ( ) => calls . push ( `compatibility:${ error === null ? "clear" : "block" } ` ) ) ,
367+ setEnabled : ( _environmentId : EnvironmentId , enabled : boolean ) =>
368+ Effect . sync ( ( ) => calls . push ( `enabled:${ enabled } ` ) ) ,
369+ } as unknown as EnvironmentRegistry . EnvironmentRegistry [ "Service" ] ) ;
370+ const resolver = ConnectionResolver . ConnectionResolver . of ( {
371+ prepare : ( ) => Effect . die ( new Error ( "The update must bypass the protocol gate." ) ) ,
372+ prepareForUpdate : ( ) =>
373+ Effect . sync ( ( ) => served ) . pipe (
374+ Effect . map ( ( current ) => ( {
375+ descriptor : current ,
376+ prepared : {
377+ environmentId : TARGET . environmentId ,
378+ label : TARGET . label ,
379+ httpBaseUrl : TARGET . httpBaseUrl ,
380+ socketUrl : "wss://build.example.test/ws?wsTicket=ticket" ,
381+ httpAuthorization : null ,
382+ target : TARGET ,
383+ } ,
384+ } ) ) ,
385+ ) ,
386+ } ) ;
387+ const httpClient = HttpClient . make ( ( request ) =>
388+ Effect . sync ( ( ) =>
389+ HttpClientResponse . fromWeb ( request , new Response ( encodeDescriptor ( served ) ) ) ,
390+ ) ,
391+ ) ;
392+
393+ const stages : Array < string > = [ ] ;
394+ const result = yield * updateOutdatedHost (
395+ TARGET . environmentId ,
396+ { targetVersion : "0.0.46" } ,
397+ ( stage ) =>
398+ Effect . sync ( ( ) => {
399+ stages . push ( stage ) ;
400+ // Lose the transport only after the consumer has observed progress.
401+ if ( stage === "downloading" ) sockets [ 0 ] ?. close ( ) ;
402+ } ) ,
403+ ) . pipe (
404+ Effect . provide (
405+ Layer . mergeAll (
406+ Layer . succeed ( EnvironmentRegistry . EnvironmentRegistry , registry ) ,
407+ Layer . succeed ( ConnectionResolver . ConnectionResolver , resolver ) ,
408+ Layer . succeed (
409+ RelayEnvironmentDiscovery . RelayEnvironmentDiscovery ,
410+ RelayEnvironmentDiscovery . RelayEnvironmentDiscovery . of ( {
411+ state : yield * SubscriptionRef . make (
412+ RelayEnvironmentDiscovery . EMPTY_RELAY_ENVIRONMENT_DISCOVERY_STATE ,
413+ ) ,
414+ refresh : Effect . void ,
415+ } ) ,
416+ ) ,
417+ Layer . succeed ( HttpClient . HttpClient , httpClient ) ,
418+ Layer . succeed ( Socket . WebSocketConstructor , ( url ) => {
419+ const socket = new OutdatedHostSocket ( url , ( ) => {
420+ served = descriptor ( ORCHESTRATION_PROTOCOL_VERSION , "0.0.46" ) ;
421+ } ) ;
422+ sockets . push ( socket ) ;
423+ return socket as unknown as globalThis . WebSocket ;
424+ } ) ,
425+ ) ,
426+ ) ,
427+ ) ;
428+
429+ expect ( sockets [ 0 ] ?. url ) . not . toContain ( "orchestrationProtocol" ) ;
430+ expect ( sockets [ 0 ] ?. requests . map ( ( request ) => request . tag ) ) . toEqual ( [
431+ WS_METHODS . serverUpdateServerWithProgress ,
432+ ] ) ;
433+ expect ( stages ) . toEqual ( [ "downloading" , "resuming" ] ) ;
434+ expect ( result . targetVersion ) . toBe ( "0.0.46" ) ;
435+ expect ( calls ) . toEqual ( [ "compatibility:clear" , "enabled:true" ] ) ;
436+ } ) ,
437+ ) ;
347438} ) ;
0 commit comments