From af72dc11e74923b63245ca14a992566bebd198bb Mon Sep 17 00:00:00 2001 From: Arvo Bendi Date: Tue, 14 Feb 2023 16:40:10 +0200 Subject: [PATCH] fix: correctly evaluate predicates in HttpWaitStrategy (#450) --- src/http-wait-strategy.test.ts | 30 ++++++++++++++++++++++++++++++ src/http-wait-strategy.ts | 10 ++++++++-- src/retry-strategy.ts | 8 ++++---- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/src/http-wait-strategy.test.ts b/src/http-wait-strategy.test.ts index b3c662928..ceb18798a 100644 --- a/src/http-wait-strategy.test.ts +++ b/src/http-wait-strategy.test.ts @@ -27,6 +27,16 @@ describe("HttpWaitStrategy", () => { await container.stop(); }); + it("should timeout for mismatching status code", async () => { + await expect(() => + new GenericContainer("cristianrgreco/testcontainer:1.1.14") + .withExposedPorts(8080) + .withStartupTimeout(3000) + .withWaitStrategy(Wait.forHttp("/unknown-path", 8080).forStatusCode(200)) + .start() + ).rejects.toThrowError("URL /unknown-path not accessible after 3000ms for"); + }); + it("should wait for status code matching", async () => { const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") .withExposedPorts(8080) @@ -42,6 +52,16 @@ describe("HttpWaitStrategy", () => { await container.stop(); }); + it("should timeout for falsy status code matching", async () => { + await expect(() => + new GenericContainer("cristianrgreco/testcontainer:1.1.14") + .withExposedPorts(8080) + .withStartupTimeout(3000) + .withWaitStrategy(Wait.forHttp("/hello-world", 8080).forStatusCodeMatching(() => false)) + .start() + ).rejects.toThrowError("URL /hello-world not accessible after 3000ms for"); + }); + it("should wait for response body predicate", async () => { const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") .withExposedPorts(8080) @@ -55,6 +75,16 @@ describe("HttpWaitStrategy", () => { await container.stop(); }); + it("should timeout for falsy response body predicate", async () => { + await expect(() => + new GenericContainer("cristianrgreco/testcontainer:1.1.14") + .withExposedPorts(8080) + .withStartupTimeout(3000) + .withWaitStrategy(Wait.forHttp("/hello-world", 8080).forResponsePredicate(() => false)) + .start() + ).rejects.toThrowError("URL /hello-world not accessible after 3000ms for"); + }); + it("should set method", async () => { const container = await new GenericContainer("cristianrgreco/testcontainer:1.1.14") .withExposedPorts(8080) diff --git a/src/http-wait-strategy.ts b/src/http-wait-strategy.ts index 885fd5afd..110e30816 100644 --- a/src/http-wait-strategy.ts +++ b/src/http-wait-strategy.ts @@ -83,13 +83,19 @@ export class HttpWaitStrategy extends AbstractWaitStrategy { return undefined; } }, - (response) => { + async (response) => { if (response === undefined) { return false; } else if (!this.predicates.length) { return response.ok; } else { - return this.predicates.every((predicate) => predicate(response)); + for (const predicate of this.predicates) { + const result = await predicate(response); + if (!result) { + return false; + } + } + return true; } }, () => { diff --git a/src/retry-strategy.ts b/src/retry-strategy.ts index 6753653b1..72b2dae0e 100644 --- a/src/retry-strategy.ts +++ b/src/retry-strategy.ts @@ -3,7 +3,7 @@ import { Clock, SystemClock, Time } from "./clock"; export interface RetryStrategy { retryUntil( fn: () => Promise, - predicate: (result: T) => boolean, + predicate: (result: T) => boolean | Promise, onTimeout: () => U, timeout: number ): Promise; @@ -14,7 +14,7 @@ abstract class AbstractRetryStrategy implements RetryStrategy { public abstract retryUntil( fn: () => Promise, - predicate: (result: T) => boolean, + predicate: (result: T) => boolean | Promise, onTimeout: () => U, timeout: number ): Promise; @@ -35,7 +35,7 @@ export class IntervalRetryStrategy extends AbstractRetryStrategy { public async retryUntil( fn: (attempt: number) => Promise, - predicate: (result: T) => boolean, + predicate: (result: T) => boolean | Promise, onTimeout: () => U, timeout: number ): Promise { @@ -44,7 +44,7 @@ export class IntervalRetryStrategy extends AbstractRetryStrategy { let attemptNumber = 0; let result = await fn(attemptNumber++); - while (!predicate(result)) { + while (!(await predicate(result))) { if (this.hasTimedOut(timeout, startTime)) { return onTimeout(); }