@@ -833,7 +833,7 @@ class StreamCombinatorsSuite extends Fs2Suite {
833833 .assertEquals(0 .millis)
834834 }
835835
836- test(" Propagation: upstream failures are propagated downstream" ) {
836+ test(" Upstream failures are propagated downstream" ) {
837837
838838 case object SevenNotAllowed extends NoStackTrace
839839
@@ -847,25 +847,41 @@ class StreamCombinatorsSuite extends Fs2Suite {
847847 downstream.compile.lastOrError.intercept[SevenNotAllowed .type ]
848848 }
849849
850- test(" Propagation: upstream cancellation is propagated downstream" ) {
850+ test(" Upstream interruption causes immediate downstream termination with all elements being released " ) {
851851
852- def source (counter : Ref [IO , Int ]): Stream [IO , Int ] = {
853- Stream
854- .unfold(0 )(s => Some (s, s + 1 ))
855- .covary[IO ]
856- .meteredStartImmediately(1 .second)
857- .evalTap(counter.set)
858- .interruptAfter(5.5 .seconds)
859- }
852+ val sourceTimeout = 5.5 .seconds
853+ val downstreamTimeout = sourceTimeout + 2 .seconds
860854
861- def downstream (counter : Ref [IO , Int ]): Stream [IO , Chunk [Int ]] =
862- source(counter).groupWithin(Int .MaxValue , 1 .day)
863-
864- (for {
865- counter <- Ref .of[IO , Int ](0 )
866- _ <- downstream(counter).compile.drain
867- c <- counter.get
868- } yield c).assertEquals(5 )
855+ TestControl
856+ .executeEmbed(
857+ Ref [IO ]
858+ .of(0 .millis)
859+ .flatMap { ref =>
860+ val source : Stream [IO , Int ] =
861+ Stream
862+ .unfold(0 )(s => Some (s, s + 1 ))
863+ .covary[IO ]
864+ .meteredStartImmediately(1 .second)
865+ .interruptAfter(sourceTimeout)
866+
867+ // large chunkSize and timeout (no emissions expected in the window
868+ // specified, unless source ends, due to interruption or
869+ // natural termination (i.e runs out of elements)
870+ val downstream : Stream [IO , Chunk [Int ]] =
871+ source.groupWithin(Int .MaxValue / 2 + 4 , 1 .day)
872+
873+ downstream.compile.lastOrError
874+ .map(_.toList)
875+ .timeout(downstreamTimeout)
876+ .flatTap(_ => IO .monotonic.flatMap(ref.set))
877+ .flatMap(emit => ref.get.map(timeLapsed => (timeLapsed, emit)))
878+ }
879+ )
880+ .assertEquals(
881+ // downstream ended immediately (i.e timeLapsed = sourceTimeout)
882+ // emitting whatever was accumulated at the time of interruption
883+ (sourceTimeout, List (0 , 1 , 2 , 3 , 4 , 5 ))
884+ )
869885 }
870886 }
871887
0 commit comments