Fix issue with allFinished(), allFutures(), one() behavior when Futures passed are already finished. (#89)

Added test.
This commit is contained in:
Eugene Kabanov 2020-04-06 13:56:24 +03:00 committed by GitHub
parent cbd8e03823
commit 4e2810cfe0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 62 additions and 5 deletions

View File

@ -693,10 +693,13 @@ proc allFutures*[T](futs: varargs[Future[T]]): Future[void] =
nfuts[i].removeCallback(cb)
for fut in nfuts:
fut.addCallback(cb)
if not(fut.finished()):
fut.addCallback(cb)
else:
inc(completedFutures)
retFuture.cancelCallback = cancellation
if len(nfuts) == 0:
if len(nfuts) == 0 or len(nfuts) == completedFutures:
retFuture.complete()
return retFuture
@ -730,10 +733,13 @@ proc allFinished*[T](futs: varargs[Future[T]]): Future[seq[Future[T]]] =
fut.removeCallback(cb)
for fut in nfuts:
fut.addCallback(cb)
if not(fut.finished()):
fut.addCallback(cb)
else:
inc(completedFutures)
retFuture.cancelCallback = cancellation
if len(nfuts) == 0:
if len(nfuts) == 0 or len(nfuts) == completedFutures:
retFuture.complete(nfuts)
return retFuture
@ -744,7 +750,7 @@ proc one*[T](futs: varargs[Future[T]]): Future[Future[T]] =
##
## If the argument is empty, the returned future FAILS immediately.
##
## On success returned Future will hold index in ``futs`` array.
## On success returned Future will hold finished Future[T].
##
## On cancel futures in ``futs`` WILL NOT BE cancelled.
var retFuture = newFuture[Future[T]]("chronos.one()")
@ -769,6 +775,12 @@ proc one*[T](futs: varargs[Future[T]]): Future[Future[T]] =
if not(nfuts[i].finished()):
nfuts[i].removeCallback(cb)
# If one of the Future[T] already finished we return it as result
for fut in nfuts:
if fut.finished():
retFuture.complete(fut)
return retFuture
for fut in nfuts:
fut.addCallback(cb)

View File

@ -520,6 +520,21 @@ suite "Future[T] behavior test suite":
# 10 * 10 completed futures = 100
result += completedFutures
proc testAllCompleted(operation: int): bool =
proc client1(): Future[int] {.async.} =
result = 1
proc client2(): Future[int] {.async.} =
if true:
raise newException(ValueError, "")
if operation == 1:
var fut = allFutures(client1(), client2())
result = fut.finished() and not(fut.failed())
elif operation == 2:
var fut = allFinished(client1(), client2())
result = fut.finished() and not(fut.failed()) and (len(fut.read()) == 2)
proc testOneZero(): bool =
var tseq = newSeq[Future[int]]()
var fut = one(tseq)
@ -645,6 +660,30 @@ suite "Future[T] behavior test suite":
result = true
proc testOneCompleted(): bool =
proc client1(): Future[int] {.async.} =
result = 1
proc client2(): Future[int] {.async.} =
if true:
raise newException(ValueError, "")
proc client3(): Future[int] {.async.} =
await sleepAsync(100.milliseconds)
result = 3
var f10 = client1()
var f20 = client2()
var f30 = client3()
var fut1 = one(f30, f10, f20)
var f11 = client1()
var f21 = client2()
var f31 = client3()
var fut2 = one(f31, f21, f11)
result = fut1.finished() and not(fut1.failed()) and fut1.read() == f10 and
fut2.finished() and not(fut2.failed()) and fut2.read() == f21
proc testCancelIter(): bool =
var completed = 0
@ -854,6 +893,10 @@ suite "Future[T] behavior test suite":
check testAllFuturesVarargs() == 30
test "allFutures(varargs) test":
check testAllFuturesSeq() == 300
test "allFutures() already completed test":
check testAllCompleted(1) == true
test "allFinished() already completed test":
check testAllCompleted(2) == true
test "one(zero) test":
check testOneZero() == true
@ -861,6 +904,8 @@ suite "Future[T] behavior test suite":
check testOneVarargs() == true
test "one(seq) test":
check testOneSeq() == true
test "one() already completed test":
check testOneCompleted() == true
test "cancel() async procedure test":
check testCancelIter() == true