Skip to content

Commit a9ae233

Browse files
committed
test: add test for request deduplication
1 parent 6aa83bd commit a9ae233

File tree

2 files changed

+56
-4
lines changed

2 files changed

+56
-4
lines changed

packages/client/src/client.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -352,14 +352,16 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
352352
}
353353
}
354354

355-
// Ensures that only one concurrent request is made for the same URL with the same method
355+
// Ensures that only one concurrent request is made for the same url-method tuple
356356
async #makeRequest (url: string, options: RequestInit): Promise<Response> {
357357
const key = `${options.method ?? 'GET'}-${url}`
358358

359-
// Check if there's already an in-flight request for this URL
359+
// Check if there's already an in-flight request for this url-method tuple
360360
const existingRequest = this.inFlightRequests.get(key)
361361
if (existingRequest != null) {
362-
return existingRequest
362+
const response = await existingRequest
363+
// Clone the response since it can only be consumed once
364+
return response.clone()
363365
}
364366

365367
// Create new request and track it
@@ -369,6 +371,8 @@ export class DefaultDelegatedRoutingV1HttpApiClient implements DelegatedRoutingV
369371
})
370372

371373
this.inFlightRequests.set(key, requestPromise)
372-
return requestPromise
374+
const response = await requestPromise
375+
// Return a clone for the first caller too, so all callers get a fresh response
376+
return response.clone()
373377
}
374378
}

packages/client/test/index.spec.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,4 +302,52 @@ describe('delegated-routing-v1-http-api-client', () => {
302302
const receivedRecord = new Uint8Array(await res.arrayBuffer())
303303
expect(marshalIPNSRecord(record)).to.equalBytes(receivedRecord)
304304
})
305+
306+
it('should deduplicate concurrent requests to the same URL', async () => {
307+
const cid = CID.parse('QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn')
308+
const providers = [{
309+
Protocol: 'transport-bitswap',
310+
Schema: 'bitswap',
311+
Metadata: 'gBI=',
312+
ID: (await generateKeyPair('Ed25519')).publicKey.toString(),
313+
Addrs: ['/ip4/41.41.41.41/tcp/1234']
314+
}]
315+
316+
// load providers for the router to fetch
317+
await fetch(`${process.env.ECHO_SERVER}/add-providers/${cid.toString()}`, {
318+
method: 'POST',
319+
body: providers.map(prov => JSON.stringify(prov)).join('\n')
320+
})
321+
322+
// Reset call count before our test
323+
await fetch(`${process.env.ECHO_SERVER}/reset-call-count`)
324+
325+
// Make multiple concurrent requests
326+
const results = await Promise.all([
327+
all(client.getProviders(cid)),
328+
all(client.getProviders(cid)),
329+
all(client.getProviders(cid)),
330+
all(client.getProviders(cid))
331+
])
332+
333+
// Get the number of times the server was called
334+
const callCountRes = await fetch(`${process.env.ECHO_SERVER}/get-call-count`)
335+
const callCount = parseInt(await callCountRes.text(), 10)
336+
337+
// Verify server was only called once
338+
expect(callCount).to.equal(1)
339+
340+
// Verify all results are the same
341+
console.log('-------', results)
342+
results.forEach(resultProviders => {
343+
expect(resultProviders.map(prov => ({
344+
id: prov.ID.toString(),
345+
// eslint-disable-next-line max-nested-callbacks
346+
addrs: prov.Addrs?.map(ma => ma.toString())
347+
}))).to.deep.equal(providers.map(prov => ({
348+
id: prov.ID,
349+
addrs: prov.Addrs
350+
})))
351+
})
352+
})
305353
})

0 commit comments

Comments
 (0)