@@ -8,6 +8,7 @@ import * as Effect from "effect/Effect";
88import * as FileSystem from "effect/FileSystem" ;
99import * as Fiber from "effect/Fiber" ;
1010import * as Path from "effect/Path" ;
11+ import * as Stream from "effect/Stream" ;
1112import { HttpClient , HttpClientResponse } from "effect/http" ;
1213import * as ChildProcessSpawner from "effect/process/ChildProcessSpawner" ;
1314
@@ -22,12 +23,13 @@ interface HarnessOptions {
2223 readonly mode ?: "web" | "desktop" ;
2324 readonly managed ?: boolean ;
2425 readonly preflight ?: "ready" | "blocked" ;
26+ readonly beforeDownload ?: Effect . Effect < void > ;
2527 readonly requestUpdate ?: ServiceLauncherClient . ServiceLauncherClient [ "Service" ] [ "requestUpdate" ] ;
2628 readonly desktopAppUpdate ?: DesktopAppUpdate . DesktopAppUpdate [ "Service" ] ;
2729}
2830
2931const archiveBytes = new TextEncoder ( ) . encode ( "not really a tarball" ) ;
30- const releaseHttpClient = ( order : string [ ] ) =>
32+ const releaseHttpClient = ( order : string [ ] , beforeDownload ?: Effect . Effect < void > ) =>
3133 HttpClient . make ( ( request ) =>
3234 Effect . gen ( function * ( ) {
3335 if ( request . url . endsWith ( "/SHA256SUMS" ) ) {
@@ -40,6 +42,7 @@ const releaseHttpClient = (order: string[]) =>
4042 new Response ( `${ hex } t3-1.1.0-linux-x64.tar.gz\n` ) ,
4143 ) ;
4244 }
45+ if ( beforeDownload ) yield * beforeDownload ;
4346 order . push ( "download" ) ;
4447 return HttpClientResponse . fromWeb ( request , new Response ( archiveBytes ) ) ;
4548 } ) ,
@@ -116,7 +119,7 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* (
116119 run : ( ) => Effect . die ( "unexpected desktop app update run" ) ,
117120 } ,
118121 ) ,
119- Effect . provideService ( HttpClient . HttpClient , releaseHttpClient ( order ) ) ,
122+ Effect . provideService ( HttpClient . HttpClient , releaseHttpClient ( order , options . beforeDownload ) ) ,
120123 Effect . provideService ( HostProcess . Platform , "linux" ) ,
121124 Effect . provideService ( HostProcess . Architecture , "x64" ) ,
122125 Effect . provide ( ServerConfig . layer ( { ...config , mode : options . mode ?? "web" } ) ) ,
@@ -418,4 +421,46 @@ it.layer(NodeServices.layer)("server self update", (it) => {
418421 expect ( ( yield * Fiber . join ( first ) ) . updateId ) . toBe ( "launcher-id" ) ;
419422 } ) ,
420423 ) ;
424+
425+ it . effect ( "keeps preparing after the progress stream closes" , ( ) =>
426+ Effect . gen ( function * ( ) {
427+ const releaseDownload = yield * Deferred . make < void > ( ) ;
428+ const sawDownloading = yield * Deferred . make < void > ( ) ;
429+ const accepted = yield * Deferred . make < void > ( ) ;
430+ const { selfUpdate, order } = yield * makeHarness ( {
431+ beforeDownload : Deferred . await ( releaseDownload ) ,
432+ requestUpdate : ( ) =>
433+ Effect . sync ( ( ) => {
434+ order . push ( "accept" ) ;
435+ } ) . pipe ( Effect . andThen ( Deferred . succeed ( accepted , undefined ) ) , Effect . as ( "launcher-id" ) ) ,
436+ } ) ;
437+
438+ const consumed = yield * ServerSelfUpdate . updateProgressStream ( selfUpdate , {
439+ targetVersion : "1.1.0" ,
440+ } ) . pipe (
441+ Stream . tap ( ( event ) =>
442+ event . type === "progress" && event . stage === "downloading"
443+ ? Deferred . succeed ( sawDownloading , undefined )
444+ : Effect . void ,
445+ ) ,
446+ Stream . runDrain ,
447+ Effect . forkChild ,
448+ ) ;
449+
450+ yield * Deferred . await ( sawDownloading ) ;
451+ // The socket drop ends the stream. The download is still held.
452+ yield * Fiber . interrupt ( consumed ) ;
453+ expect ( ( yield * selfUpdate . update ( { targetVersion : "1.2.0" } ) . pipe ( Effect . flip ) ) . reason ) . toBe (
454+ "A server update is already in progress." ,
455+ ) ;
456+
457+ yield * Deferred . succeed ( releaseDownload , undefined ) ;
458+ // `installing` is offered only after the stream queue has shut down.
459+ yield * Deferred . await ( accepted ) ;
460+ expect ( order ) . toEqual ( [ "download" , "extract" , "preflight" , "accept" ] ) ;
461+ expect ( ( yield * selfUpdate . update ( { targetVersion : "1.1.0" } ) . pipe ( Effect . flip ) ) . reason ) . toBe (
462+ "A server update is already in progress." ,
463+ ) ;
464+ } ) ,
465+ ) ;
421466} ) ;
0 commit comments