From 19122e617768a13cbca0f3dadd4d599167857f32 Mon Sep 17 00:00:00 2001 From: Saulius Skliutas <24278440+saskliutas@users.noreply.github.com> Date: Thu, 10 Mar 2022 16:39:51 +0200 Subject: [PATCH 1/3] Avoid infinite loop when building paged requests response --- .../PresentationManager.ts | 17 +++++++---------- .../src/test/PresentationManager.test.ts | 11 +++++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/presentation/frontend/src/presentation-frontend/PresentationManager.ts b/presentation/frontend/src/presentation-frontend/PresentationManager.ts index b75570040b82..7c47970e1cfe 100644 --- a/presentation/frontend/src/presentation-frontend/PresentationManager.ts +++ b/presentation/frontend/src/presentation-frontend/PresentationManager.ts @@ -481,11 +481,8 @@ interface PagedGeneratorCreateProps { get: (pageStart: Required, requestIndex: number) => Promise<{ total: number, items: TPagedResponseItem[] }>; } async function createPagedGeneratorResponse(props: PagedGeneratorCreateProps) { - const requestedPageStart = props.page?.start ?? 0; - const requestedPageSize = props.page?.size ?? 0; - let pageStart = requestedPageStart; - let pageSize = requestedPageSize; - let receivedItemsCount = 0; + let pageStart = props.page?.start ?? 0; + let pageSize = props.page?.size ?? 0; let requestIndex = 0; const firstPage = await props.get({ start: pageStart, size: pageSize }, requestIndex++); @@ -496,21 +493,21 @@ async function createPagedGeneratorResponse(props: PagedGene while (true) { for (const item of partialResult.items) { yield item; - ++receivedItemsCount; } + const receivedItemsCount = partialResult.items.length; if (partialResult.total !== 0 && receivedItemsCount === 0) { if (pageStart >= partialResult.total) throw new Error(`Requested page with start index ${pageStart} is out of bounds. Total number of items: ${partialResult.total}`); throw new Error("Paged request returned non zero total count but no items"); } - if (requestedPageSize !== 0 && receivedItemsCount >= requestedPageSize || receivedItemsCount >= (partialResult.total - requestedPageStart)) + if (pageSize !== 0 && receivedItemsCount >= pageSize || receivedItemsCount >= (partialResult.total - pageStart)) break; - if (requestedPageSize !== 0) - pageSize = requestedPageSize - receivedItemsCount; - pageStart = requestedPageStart + receivedItemsCount; + if (pageSize !== 0) + pageSize -= receivedItemsCount; + pageStart += receivedItemsCount; partialResult = await props.get({ start: pageStart, size: pageSize }, requestIndex++); } diff --git a/presentation/frontend/src/test/PresentationManager.test.ts b/presentation/frontend/src/test/PresentationManager.test.ts index 9d1578c6b54a..15afe215cb4e 100644 --- a/presentation/frontend/src/test/PresentationManager.test.ts +++ b/presentation/frontend/src/test/PresentationManager.test.ts @@ -1343,6 +1343,17 @@ describe("PresentationManager", () => { expect(result).to.deep.eq({ total: 0, items: [] }); }); + it("returns zero response when partial request returns less items then requested", async () => { + const getter = sinon.stub(); + getter.onFirstCall().resolves({ total: 5, items: [2, 3] }); + getter.onSecondCall().resolves({ total: 5, items: [] }); + const result = await buildPagedArrayResponse({ start: 1 }, getter); + expect(getter).to.be.calledTwice; + expect(getter.firstCall).to.be.calledWith({ start: 1, size: 0 }); + expect(getter.secondCall).to.be.calledWith({ start: 3, size: 0 }); + expect(result).to.deep.eq({ total: 0, items: [] }); + }); + }); }); From 73512fd0df9aa086991adf6c5b2a90e5ef3153a6 Mon Sep 17 00:00:00 2001 From: Saulius Skliutas <24278440+saskliutas@users.noreply.github.com> Date: Thu, 10 Mar 2022 16:41:04 +0200 Subject: [PATCH 2/3] Rush change --- ...on-fix_paged_request_response_2022-03-10-14-40.json | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 common/changes/@itwin/presentation-frontend/presentation-fix_paged_request_response_2022-03-10-14-40.json diff --git a/common/changes/@itwin/presentation-frontend/presentation-fix_paged_request_response_2022-03-10-14-40.json b/common/changes/@itwin/presentation-frontend/presentation-fix_paged_request_response_2022-03-10-14-40.json new file mode 100644 index 000000000000..be02401a44f7 --- /dev/null +++ b/common/changes/@itwin/presentation-frontend/presentation-fix_paged_request_response_2022-03-10-14-40.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/presentation-frontend", + "comment": "Fix paged requests result accumulation resulting in infinite loop.", + "type": "none" + } + ], + "packageName": "@itwin/presentation-frontend" +} \ No newline at end of file From 73c0be87defb85153d280db5394aacaa50da663e Mon Sep 17 00:00:00 2001 From: Saulius Skliutas <24278440+saskliutas@users.noreply.github.com> Date: Thu, 10 Mar 2022 17:01:54 +0200 Subject: [PATCH 3/3] Update presentation/frontend/src/test/PresentationManager.test.ts Co-authored-by: Grigas <35135765+grigasp@users.noreply.github.com> --- presentation/frontend/src/test/PresentationManager.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/presentation/frontend/src/test/PresentationManager.test.ts b/presentation/frontend/src/test/PresentationManager.test.ts index 15afe215cb4e..2e5461bfde1e 100644 --- a/presentation/frontend/src/test/PresentationManager.test.ts +++ b/presentation/frontend/src/test/PresentationManager.test.ts @@ -1343,7 +1343,7 @@ describe("PresentationManager", () => { expect(result).to.deep.eq({ total: 0, items: [] }); }); - it("returns zero response when partial request returns less items then requested", async () => { + it("returns zero response when partial request returns less items than requested", async () => { const getter = sinon.stub(); getter.onFirstCall().resolves({ total: 5, items: [2, 3] }); getter.onSecondCall().resolves({ total: 5, items: [] });