From 765d1aa06b6575768a28e4532a3b3b876aeeefb4 Mon Sep 17 00:00:00 2001 From: krutoo Date: Thu, 31 Oct 2024 00:17:11 +0500 Subject: [PATCH 1/2] retry revision - middleware/retry: now retries by default when response is not ok - middleware/retry: loop conditions can be specified via config - middleware/retry: when response is received and it is not ok, it will be dumped (potential memory leaks) - middleware/retry: unit tests added - deps: upd - deps: std/assert removed --- .github/workflows/publish-jsr.yml | 2 +- .github/workflows/publish-npm.yml | 2 +- .github/workflows/tests.yml | 2 +- deno.json | 8 +- deno.lock | 299 +++++++-------------- src/fetch/__test__/applyMiddleware.test.ts | 90 +++---- src/middleware/__test__/retry.test.ts | 54 ++++ src/middleware/retry.ts | 44 ++- src/url/__test__/url.test.ts | 10 +- 9 files changed, 251 insertions(+), 260 deletions(-) create mode 100644 src/middleware/__test__/retry.test.ts diff --git a/.github/workflows/publish-jsr.yml b/.github/workflows/publish-jsr.yml index 26aada0..db8f369 100644 --- a/.github/workflows/publish-jsr.yml +++ b/.github/workflows/publish-jsr.yml @@ -28,7 +28,7 @@ jobs: - name: Unit tests run: | - deno test + deno task test - name: Set version run: | diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 3c3d957..39107a4 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -19,7 +19,7 @@ jobs: - name: Unit tests run: | - deno test + deno task test - uses: actions/setup-node@v3 with: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 19ca635..e3136c8 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -23,4 +23,4 @@ jobs: - name: Unit tests run: | - deno test + deno task test diff --git a/deno.json b/deno.json index b165444..83c2ac7 100644 --- a/deno.json +++ b/deno.json @@ -3,13 +3,13 @@ "version": "0.0.0", "tasks": { "lint": "deno check src/**/*.ts && deno lint && deno fmt --check", + "test": "deno test --allow-net", "build-npm": "deno run -A scripts/build-npm.ts" }, "imports": { - "@deno/dnt": "jsr:@deno/dnt@^0.41.0", - "@std/assert": "jsr:@std/assert@^0.220.1", - "@std/expect": "jsr:@std/expect@^1.0.5", - "@std/testing": "jsr:@std/testing@^0.220.1", + "@deno/dnt": "jsr:@deno/dnt@^0.41.3", + "@std/expect": "jsr:@std/expect@^1.0.6", + "@std/testing": "jsr:@std/testing@^1.0.3", "#fetch": "./src/fetch/mod.ts", "#response": "./src/response/mod.ts" }, diff --git a/deno.lock b/deno.lock index b6d5eef..1576f10 100644 --- a/deno.lock +++ b/deno.lock @@ -1,55 +1,68 @@ { "version": "4", "specifiers": { - "jsr:@deno/cache-dir@0.8": "0.8.0", - "jsr:@deno/dnt@0.41": "0.41.0", + "jsr:@david/code-block-writer@^13.0.2": "13.0.3", + "jsr:@deno/cache-dir@~0.10.3": "0.10.3", + "jsr:@deno/dnt@~0.41.3": "0.41.3", + "jsr:@deno/graph@~0.73.1": "0.73.1", + "jsr:@std/assert@0.223": "0.223.0", + "jsr:@std/assert@0.226": "0.226.0", "jsr:@std/assert@^1.0.6": "1.0.6", - "jsr:@std/assert@~0.218.2": "0.218.2", - "jsr:@std/assert@~0.220.1": "0.220.1", - "jsr:@std/bytes@~0.218.2": "0.218.2", - "jsr:@std/data-structures@~0.220.1": "0.220.1", - "jsr:@std/expect@^1.0.5": "1.0.5", - "jsr:@std/fmt@~0.218.2": "0.218.2", - "jsr:@std/fmt@~0.220.1": "0.220.1", - "jsr:@std/fs@~0.218.2": "0.218.2", - "jsr:@std/fs@~0.220.1": "0.220.1", + "jsr:@std/async@^1.0.5": "1.0.7", + "jsr:@std/bytes@0.223": "0.223.0", + "jsr:@std/data-structures@^1.0.4": "1.0.4", + "jsr:@std/expect@^1.0.6": "1.0.6", + "jsr:@std/fmt@0.223": "0.223.0", + "jsr:@std/fmt@1": "1.0.3", + "jsr:@std/fs@0.223": "0.223.0", + "jsr:@std/fs@1": "1.0.5", + "jsr:@std/fs@^1.0.4": "1.0.5", + "jsr:@std/fs@~0.229.3": "0.229.3", "jsr:@std/internal@^1.0.4": "1.0.4", - "jsr:@std/io@~0.218.2": "0.218.2", - "jsr:@std/path@~0.218.2": "0.218.2", - "jsr:@std/path@~0.220.1": "0.220.1", - "jsr:@std/testing@~0.220.1": "0.220.1", - "npm:@ts-morph/bootstrap@0.22": "0.22.0", - "npm:code-block-writer@^13.0.1": "13.0.1" + "jsr:@std/io@0.223": "0.223.0", + "jsr:@std/path@0.223": "0.223.0", + "jsr:@std/path@1": "1.0.7", + "jsr:@std/path@1.0.0-rc.1": "1.0.0-rc.1", + "jsr:@std/path@^1.0.6": "1.0.7", + "jsr:@std/path@^1.0.7": "1.0.7", + "jsr:@std/path@~0.225.2": "0.225.2", + "jsr:@std/testing@^1.0.3": "1.0.3", + "jsr:@ts-morph/bootstrap@0.24": "0.24.0", + "jsr:@ts-morph/common@0.24": "0.24.0" }, "jsr": { - "@deno/cache-dir@0.8.0": { - "integrity": "e87e80a404958f6350d903e6238b72afb92468378b0b32111f7a1e4916ac7fe7", + "@david/code-block-writer@13.0.3": { + "integrity": "f98c77d320f5957899a61bfb7a9bead7c6d83ad1515daee92dbacc861e13bb7f" + }, + "@deno/cache-dir@0.10.3": { + "integrity": "eb022f84ecc49c91d9d98131c6e6b118ff63a29e343624d058646b9d50404776", "dependencies": [ - "jsr:@std/fmt@~0.218.2", - "jsr:@std/fs@~0.218.2", + "jsr:@deno/graph", + "jsr:@std/fmt@0.223", + "jsr:@std/fs@0.223", "jsr:@std/io", - "jsr:@std/path@~0.218.2" + "jsr:@std/path@0.223" ] }, - "@deno/dnt@0.41.0": { - "integrity": "c196a0dee92f939d1d6720e39331d631e0dc5e4f08f1fd0301b17a7d91bb9c78", + "@deno/dnt@0.41.3": { + "integrity": "b2ef2c8a5111eef86cb5bfcae103d6a2938e8e649e2461634a7befb7fc59d6d2", "dependencies": [ + "jsr:@david/code-block-writer", "jsr:@deno/cache-dir", - "jsr:@std/fmt@~0.218.2", - "jsr:@std/fs@~0.218.2", - "jsr:@std/path@~0.218.2", - "npm:@ts-morph/bootstrap", - "npm:code-block-writer" + "jsr:@std/fmt@1", + "jsr:@std/fs@1", + "jsr:@std/path@1", + "jsr:@ts-morph/bootstrap" ] }, - "@std/assert@0.218.2": { - "integrity": "7f0a5a1a8cf86607cd6c2c030584096e1ffad27fc9271429a8cb48cfbdee5eaf" + "@deno/graph@0.73.1": { + "integrity": "cd69639d2709d479037d5ce191a422eabe8d71bb68b0098344f6b07411c84d41" }, - "@std/assert@0.220.1": { - "integrity": "88710d54f3afdd7a5761e7805abba1f56cd14e4b212feffeb3e73a9f77482425", - "dependencies": [ - "jsr:@std/fmt@~0.220.1" - ] + "@std/assert@0.223.0": { + "integrity": "eb8d6d879d76e1cc431205bd346ed4d88dc051c6366365b1af47034b0670be24" + }, + "@std/assert@0.226.0": { + "integrity": "0dfb5f7c7723c18cec118e080fec76ce15b4c31154b15ad2bd74822603ef75b3" }, "@std/assert@1.0.6": { "integrity": "1904c05806a25d94fe791d6d883b685c9e2dcd60e4f9fc30f4fc5cf010c72207", @@ -57,209 +70,101 @@ "jsr:@std/internal" ] }, - "@std/bytes@0.218.2": { - "integrity": "91fe54b232dcca73856b79a817247f4a651dbb60d51baafafb6408c137241670" + "@std/async@1.0.7": { + "integrity": "f4fadc0124432e37cba11e8b3880164661a664de00a65118d976848f32f96290" }, - "@std/data-structures@0.220.1": { - "integrity": "031c2982782f4284813c33f904d9e948fb369bc7f830d43fb05355c96a30435b" + "@std/bytes@0.223.0": { + "integrity": "84b75052cd8680942c397c2631318772b295019098f40aac5c36cead4cba51a8" }, - "@std/expect@1.0.5": { - "integrity": "8c7ac797e2ffe57becc6399c0f2fd06230cb9ef124d45229c6e592c563824af1", + "@std/data-structures@1.0.4": { + "integrity": "fa0e20c11eb9ba673417450915c750a0001405a784e2a4e0c3725031681684a0" + }, + "@std/expect@1.0.6": { + "integrity": "dffba969ca5ea6d7c39338d4985c9af2bfa6e080c710cc2b77756dd7657c369c", "dependencies": [ "jsr:@std/assert@^1.0.6", "jsr:@std/internal" ] }, - "@std/fmt@0.218.2": { - "integrity": "99526449d2505aa758b6cbef81e7dd471d8b28ec0dcb1491d122b284c548788a" + "@std/fmt@0.223.0": { + "integrity": "6deb37794127dfc7d7bded2586b9fc6f5d50e62a8134846608baf71ffc1a5208" + }, + "@std/fmt@1.0.3": { + "integrity": "97765c16aa32245ff4e2204ecf7d8562496a3cb8592340a80e7e554e0bb9149f" }, - "@std/fmt@0.220.1": { - "integrity": "3b1a698477a26b1dacbbee26db1a65030a005c6d71db3b3a0e59f8a638f04d7a" + "@std/fs@0.223.0": { + "integrity": "3b4b0550b2c524cbaaa5a9170c90e96cbb7354e837ad1bdaf15fc9df1ae9c31c" }, - "@std/fs@0.218.2": { - "integrity": "dd9431453f7282e8c577cc22c9e6d036055a9a980b5549f887d6012969fabcca", + "@std/fs@0.229.3": { + "integrity": "783bca21f24da92e04c3893c9e79653227ab016c48e96b3078377ebd5222e6eb", "dependencies": [ - "jsr:@std/assert@~0.218.2", - "jsr:@std/path@~0.218.2" + "jsr:@std/path@1.0.0-rc.1" ] }, - "@std/fs@0.220.1": { - "integrity": "7fe79c08e9e2ea6818b05f271ddba07eaed7e6dac7ce7cfb35e3f8521aa18fc1", + "@std/fs@1.0.5": { + "integrity": "41806ad6823d0b5f275f9849a2640d87e4ef67c51ee1b8fb02426f55e02fd44e", "dependencies": [ - "jsr:@std/path@~0.220.1" + "jsr:@std/path@^1.0.7" ] }, "@std/internal@1.0.4": { "integrity": "62e8e4911527e5e4f307741a795c0b0a9e6958d0b3790716ae71ce085f755422" }, - "@std/io@0.218.2": { - "integrity": "c64fbfa087b7c9d4d386c5672f291f607d88cb7d44fc299c20c713e345f2785f", + "@std/io@0.223.0": { + "integrity": "2d8c3c2ab3a515619b90da2c6ff5ea7b75a94383259ef4d02116b228393f84f1", "dependencies": [ - "jsr:@std/assert@~0.218.2", + "jsr:@std/assert@0.223", "jsr:@std/bytes" ] }, - "@std/path@0.218.2": { - "integrity": "b568fd923d9e53ad76d17c513e7310bda8e755a3e825e6289a0ce536404e2662", - "dependencies": [ - "jsr:@std/assert@~0.218.2" - ] - }, - "@std/path@0.220.1": { - "integrity": "cc63c1b5e5192e2f718dc2f365a3514fffb26cc0380959bab0f8fb5988a52f0c" - }, - "@std/testing@0.220.1": { - "integrity": "be77cc1df543f70217d450612637f9f6fcc6887f19fca89665ce08456ee1f290", - "dependencies": [ - "jsr:@std/assert@~0.220.1", - "jsr:@std/data-structures", - "jsr:@std/fmt@~0.220.1", - "jsr:@std/fs@~0.220.1", - "jsr:@std/path@~0.220.1" - ] - } - }, - "npm": { - "@nodelib/fs.scandir@2.1.5": { - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dependencies": [ - "@nodelib/fs.stat", - "run-parallel" - ] - }, - "@nodelib/fs.stat@2.0.5": { - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" - }, - "@nodelib/fs.walk@1.2.8": { - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dependencies": [ - "@nodelib/fs.scandir", - "fastq" - ] - }, - "@ts-morph/bootstrap@0.22.0": { - "integrity": "sha512-MI5q7pid4swAlE2lcHwHRa6rcjoIMyT6fy8uuZm8BGg7DHGi/H5bQ0GMZzbk3N0r/LfStMdOYPkl+3IwvfIQ2g==", - "dependencies": [ - "@ts-morph/common" - ] - }, - "@ts-morph/common@0.22.0": { - "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", - "dependencies": [ - "fast-glob", - "minimatch", - "mkdirp", - "path-browserify" - ] - }, - "balanced-match@1.0.2": { - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "brace-expansion@2.0.1": { - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": [ - "balanced-match" - ] - }, - "braces@3.0.2": { - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dependencies": [ - "fill-range" - ] - }, - "code-block-writer@13.0.1": { - "integrity": "sha512-c5or4P6erEA69TxaxTNcHUNcIn+oyxSRTOWV+pSYF+z4epXqNvwvJ70XPGjPNgue83oAFAPBRQYwpAJ/Hpe/Sg==" - }, - "fast-glob@3.3.2": { - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dependencies": [ - "@nodelib/fs.stat", - "@nodelib/fs.walk", - "glob-parent", - "merge2", - "micromatch" - ] - }, - "fastq@1.17.1": { - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dependencies": [ - "reusify" - ] - }, - "fill-range@7.0.1": { - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "@std/path@0.223.0": { + "integrity": "593963402d7e6597f5a6e620931661053572c982fc014000459edc1f93cc3989", "dependencies": [ - "to-regex-range" + "jsr:@std/assert@0.223" ] }, - "glob-parent@5.1.2": { - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "@std/path@0.225.2": { + "integrity": "0f2db41d36b50ef048dcb0399aac720a5348638dd3cb5bf80685bf2a745aa506", "dependencies": [ - "is-glob" + "jsr:@std/assert@0.226" ] }, - "is-extglob@2.1.1": { - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + "@std/path@1.0.0-rc.1": { + "integrity": "b8c00ae2f19106a6bb7cbf1ab9be52aa70de1605daeb2dbdc4f87a7cbaf10ff6" }, - "is-glob@4.0.3": { - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dependencies": [ - "is-extglob" - ] - }, - "is-number@7.0.0": { - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "merge2@1.4.1": { - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" - }, - "micromatch@4.0.5": { - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dependencies": [ - "braces", - "picomatch" - ] + "@std/path@1.0.7": { + "integrity": "76a689e07f0e15dcc6002ec39d0866797e7156629212b28f27179b8a5c3b33a1" }, - "minimatch@9.0.3": { - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "@std/testing@1.0.3": { + "integrity": "f98c2bee53860a5916727d7e7d3abe920dd6f9edace022e2d059f00d05c2cf42", "dependencies": [ - "brace-expansion" + "jsr:@std/assert@^1.0.6", + "jsr:@std/async", + "jsr:@std/data-structures", + "jsr:@std/fs@^1.0.4", + "jsr:@std/internal", + "jsr:@std/path@^1.0.6" ] }, - "mkdirp@3.0.1": { - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==" - }, - "path-browserify@1.0.1": { - "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" - }, - "picomatch@2.3.1": { - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" - }, - "queue-microtask@1.2.3": { - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" - }, - "reusify@1.0.4": { - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" - }, - "run-parallel@1.2.0": { - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "@ts-morph/bootstrap@0.24.0": { + "integrity": "a826a2ef7fa8a7c3f1042df2c034d20744d94da2ee32bf29275bcd4dffd3c060", "dependencies": [ - "queue-microtask" + "jsr:@ts-morph/common" ] }, - "to-regex-range@5.0.1": { - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "@ts-morph/common@0.24.0": { + "integrity": "12b625b8e562446ba658cdbe9ad77774b4bd96b992ae8bd34c60dbf24d06c1f3", "dependencies": [ - "is-number" + "jsr:@std/fs@~0.229.3", + "jsr:@std/path@~0.225.2" ] } }, "workspace": { "dependencies": [ - "jsr:@deno/dnt@0.41", - "jsr:@std/assert@~0.220.1", - "jsr:@std/expect@^1.0.5", - "jsr:@std/testing@~0.220.1" + "jsr:@deno/dnt@~0.41.3", + "jsr:@std/expect@^1.0.6", + "jsr:@std/testing@^1.0.3" ] } } diff --git a/src/fetch/__test__/applyMiddleware.test.ts b/src/fetch/__test__/applyMiddleware.test.ts index b8202d8..a5bde49 100644 --- a/src/fetch/__test__/applyMiddleware.test.ts +++ b/src/fetch/__test__/applyMiddleware.test.ts @@ -1,51 +1,49 @@ -import { assertEquals } from '@std/assert'; -import { describe, it } from '@std/testing/bdd'; +import { it } from '@std/testing/bdd'; +import { expect } from '@std/expect'; import { applyMiddleware } from '../apply-middleware.ts'; import type { Middleware } from '../types.ts'; -describe('applyMiddleware', () => { - it('should apply middleware in the order in which they are passed', async () => { - const log: string[] = []; - - const foo: Middleware = async (request, next) => { - log.push(''); - const result = await next(request); - log.push(''); - return result; - }; - - const bar: Middleware = async (request, next) => { - log.push(''); - const result = await next(request); - log.push(''); - return result; - }; - - const baz: Middleware = async (request, next) => { - log.push(''); - const result = await next(request); - log.push(''); - return result; - }; - - const enhancer = applyMiddleware(foo, bar, baz); - - const handler = enhancer(() => { - log.push(''); - return new Response('Test'); - }); - - await handler(new Request('https://fake.com/for-tests')); - - assertEquals(log, [ - // expected log - '', - '', - '', - '', - '', - '', - '', - ]); +it('should apply middleware in the order in which they are passed', async () => { + const log: string[] = []; + + const foo: Middleware = async (request, next) => { + log.push(''); + const result = await next(request); + log.push(''); + return result; + }; + + const bar: Middleware = async (request, next) => { + log.push(''); + const result = await next(request); + log.push(''); + return result; + }; + + const baz: Middleware = async (request, next) => { + log.push(''); + const result = await next(request); + log.push(''); + return result; + }; + + const enhancer = applyMiddleware(foo, bar, baz); + + const handler = enhancer(() => { + log.push(''); + return new Response('Test'); }); + + await handler(new Request('https://fake.com/for-tests')); + + expect(log).toEqual([ + // expected log + '', + '', + '', + '', + '', + '', + '', + ]); }); diff --git a/src/middleware/__test__/retry.test.ts b/src/middleware/__test__/retry.test.ts new file mode 100644 index 0000000..d733c2a --- /dev/null +++ b/src/middleware/__test__/retry.test.ts @@ -0,0 +1,54 @@ +import { afterAll, beforeAll, it } from '@std/testing/bdd'; +import { expect } from '@std/expect'; +import { applyMiddleware, configureFetch } from '#fetch'; +import { retry } from '../retry.ts'; +import { dump } from '#response'; + +const serverState = { counter: 3 }; +let server: ReturnType; + +beforeAll(() => { + server = Deno.serve((_req) => { + if (serverState.counter > 0) { + serverState.counter--; + return new Response('FAIL', { status: 400 }); + } + + return new Response('SUCCESS', { status: 200 }); + }); +}); + +afterAll(async () => { + await server.shutdown(); +}); + +it('Should fetch resource until it returns success response)', async () => { + const fetch = configureFetch(globalThis.fetch, applyMiddleware(retry({ count: 10 }))); + + expect(serverState.counter).toBe(3); + const response = await fetch( + new URL(`http://${server.addr.hostname}:${server.addr.port}`), + ); + + expect(serverState.counter).toBe(0); + expect(response.ok).toBe(true); + expect(await response.text()).toBe('SUCCESS'); + + await dump(response); +}); + +it('Should break fetch loop when attempt limit is reached', async () => { + const fetch = configureFetch(globalThis.fetch, applyMiddleware(retry({ count: 2 }))); + + serverState.counter = 5; + expect(serverState.counter).toBe(5); + const response = await fetch( + new URL(`http://${server.addr.hostname}:${server.addr.port}`), + ); + + expect(serverState.counter).toBe(3); + expect(response.ok).toBe(false); + expect(await response.text()).toBe('FAIL'); + + await dump(response); +}); diff --git a/src/middleware/retry.ts b/src/middleware/retry.ts index 8378768..95fdf78 100644 --- a/src/middleware/retry.ts +++ b/src/middleware/retry.ts @@ -1,19 +1,53 @@ import type { Middleware } from '#fetch'; +import { dump } from '#response'; + +/** Retry middleware config. */ +export interface RetryConfig { + /** Retries count. */ + count?: number; + + /** Should try again if received response is not OK. */ + whenNotOk?: boolean; + + /** Should try again if an exception is thrown. */ + whenCatch?: boolean; +} + +/** + * Returns a middleware that will retry the request until either: + * - or the retries count is exceeded; + * - or until a successful response is received. + * @param init Count or config. + * @returns Middleware. + */ +export function retry( + init: number | RetryConfig, +): Middleware { + const { count = 1, whenNotOk = true, whenCatch = true } = typeof init === 'number' + ? { count: init } + : init; -export function retry(count: number): Middleware { return async (request, next) => { let index = 0; while (true) { index++; + try { - return await next(request.clone()); + const response = await next(request.clone()); + + if (!response.ok && whenNotOk && index < count) { + await dump(response); + continue; + } + + return response; } catch (error) { - if (index < count) { + if (whenCatch && index < count) { continue; - } else { - throw error; } + + throw error; } } }; diff --git a/src/url/__test__/url.test.ts b/src/url/__test__/url.test.ts index 9c08f97..dbe3d83 100644 --- a/src/url/__test__/url.test.ts +++ b/src/url/__test__/url.test.ts @@ -1,8 +1,8 @@ -import { describe } from '@std/testing/bdd'; +import { it } from '@std/testing/bdd'; import { expect } from '@std/expect'; import { resetParams, setParams, withoutParams, withParams } from '../url.ts'; -describe('withParams', () => { +it('withParams', () => { const input = new URL('http://hello.com?foo=1&bar=2'); expect(input.searchParams.get('foo')).toBe('1'); @@ -15,7 +15,7 @@ describe('withParams', () => { expect(output.searchParams.get('baz')).toBe('4'); }); -describe('withoutParams', () => { +it('withoutParams', () => { const input = new URL('http://hello.com?foo=1&bar=2'); expect(input.searchParams.get('foo')).toBe('1'); @@ -28,7 +28,7 @@ describe('withoutParams', () => { expect(output.searchParams.get('baz')).toBe(null); }); -describe('setParams', () => { +it('setParams', () => { const input = new URL('http://hello.com?foo=1&bar=2'); expect(input.searchParams.get('foo')).toBe('1'); @@ -42,7 +42,7 @@ describe('setParams', () => { expect(output.searchParams.get('baz')).toBe('4'); }); -describe('resetParams', () => { +it('resetParams', () => { const input = new URL('http://hello.com?foo=1&bar=2'); expect(input.searchParams.get('foo')).toBe('1'); From 38177cd3cc85c17254a49fcbbabb17c796943222 Mon Sep 17 00:00:00 2001 From: krutoo Date: Thu, 31 Oct 2024 00:20:49 +0500 Subject: [PATCH 2/2] retry revision - middleware/retry: type RetryConfig now is exported from /middleware entrypoint --- src/middleware/mod.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/middleware/mod.ts b/src/middleware/mod.ts index 35445b9..4358417 100644 --- a/src/middleware/mod.ts +++ b/src/middleware/mod.ts @@ -9,7 +9,7 @@ export { type LogHandlerFactory, } from './log.ts'; -export { retry } from './retry.ts'; +export { retry, type RetryConfig } from './retry.ts'; export { validateStatus, type ValidateStatusOptions } from './validate-status.ts';