Skip to content

Commit d4d2c75

Browse files
[service-bus] Closing some open areas where we could mask errors, and fixing flaky tests to be more reliable. (#15761)
Making changes to simplify a flaky test (and hopefully make it more reliable). The main issue with the 'handle interrupted detach' method was that it relied on too many moving parts to work reliably. We could just eternally loop like we'd expect customers to do, but in the end we have a very simple test we're trying to perform - we want to receive, and while we're in the process of draining, cause a detach and have it early exit and reject/resolve immediately rather than waiting for the timeout. I reworked the test to make that simpler by just removing the unneeded connection.idle() and just calling directly into the onDetached method. Because it happens prior to rhea even seeing that we're draining we should reliably win that race each time. There were a couple of other things changed for this PR as well: - The max time per test was lowered accidentally. Bringing it back what's been used as the standard time in other libraries - Fixed a spot in receiveMessages() where, if the link had been closed, we'd falsly return an empty array instead of throwing an exception indicating the link closed. This didn't appear to be related to the bug but it's incorrect and can hide bugs so I'd rather just throw the error than eat the condition and return an empty array. It's rare, but when it does happen the empty array response isn't right either - we're probably in the middle of a connection reset/change event. Fixes #13461
1 parent f9efdf4 commit d4d2c75

File tree

8 files changed

+205
-80
lines changed

8 files changed

+205
-80
lines changed

sdk/servicebus/service-bus/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@
6060
"extract-api": "tsc -p . && api-extractor run --local",
6161
"format": "prettier --write --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"samples/**/*.{ts,js}\" \"src/**/*.ts\" \"test/**/*.ts\" \"samples-dev/**/*.ts\" \"*.{js,json}\"",
6262
"integration-test:browser": "karma start --single-run",
63-
"integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 120000 --full-trace \"dist-esm/test/internal/**/*.spec.js\" \"dist-esm/test/public/**/*.spec.js\"",
63+
"integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 1200000 --full-trace \"dist-esm/test/internal/**/*.spec.js\" \"dist-esm/test/public/**/*.spec.js\"",
6464
"integration-test": "npm run integration-test:node && npm run integration-test:browser",
6565
"lint:fix": "eslint package.json api-extractor.json src test --ext .ts --fix --fix-type [problem,suggestion]",
6666
"lint": "eslint package.json api-extractor.json src test --ext .ts -f html -o service-bus-lintReport.html || exit 0",
@@ -71,7 +71,7 @@
7171
"test:node": "npm run clean && npm run build:test:node && npm run integration-test:node",
7272
"test": "npm run test:node && npm run test:browser",
7373
"unit-test:browser": "echo skipped",
74-
"unit-test:node": "mocha -r esm -r ts-node/register --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 120000 --full-trace \"test/internal/unit/*.spec.ts\" \"test/internal/node/*.spec.ts\"",
74+
"unit-test:node": "mocha -r esm -r ts-node/register --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 1200000 --full-trace \"test/internal/unit/*.spec.ts\" \"test/internal/node/*.spec.ts\"",
7575
"unit-test": "npm run unit-test:node && npm run unit-test:browser",
7676
"docs": "typedoc --excludePrivate --excludeNotExported --excludeExternals --stripInternal --mode file --out ./dist/docs ./src"
7777
},

sdk/servicebus/service-bus/src/core/batchingReceiver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ export class BatchingReceiverLite {
281281

282282
if (receiver == null) {
283283
// (was somehow closed in between the init() and the return)
284-
return [];
284+
throw new ServiceBusError("Link closed before receiving messages.", "GeneralError");
285285
}
286286

287287
const messages = await new Promise<ServiceBusMessageImpl[]>((resolve, reject) =>

sdk/servicebus/service-bus/test/internal/backupMessageSettlement.spec.ts

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
ServiceBusMessageImpl,
2020
ServiceBusReceivedMessage
2121
} from "../../src/serviceBusMessage";
22+
import { disableCommonLoggers, enableCommonLoggers, testLogger } from "./utils/misc";
2223

2324
const should = chai.should();
2425
chai.use(chaiAsPromised);
@@ -256,10 +257,17 @@ describe("Message settlement After Receiver is Closed - Through ManagementLink",
256257
const testMessages = entityNames.usesSessions
257258
? TestMessage.getSessionSample()
258259
: TestMessage.getSample();
260+
261+
testLogger.info(`sending (and receiving) initial message`);
262+
259263
const msg = await sendReceiveMsg(testMessages);
260264

265+
testLogger.info(`Done sending initial messages`);
266+
261267
const msgDeliveryLink = (msg as ServiceBusMessageImpl).delivery.link.name;
262268

269+
testLogger.info(`About to close the underlying link.`);
270+
263271
if (entityNames.usesSessions) {
264272
await (receiver as ServiceBusReceiverImpl)["_context"].messageSessions[
265273
msgDeliveryLink
@@ -270,10 +278,18 @@ describe("Message settlement After Receiver is Closed - Through ManagementLink",
270278
].close();
271279
}
272280

281+
testLogger.info(
282+
`Underlying link should be closed: ${receiver.isClosed}. This will force us to use the management link to settle. Will now attempt to dead letter.`
283+
);
284+
273285
let errorWasThrown = false;
274286
try {
275287
await receiver.deadLetterMessage(msg);
288+
289+
testLogger.info(`Message has been dead lettered`);
276290
} catch (err) {
291+
testLogger.error(`Exception thrown`, err);
292+
277293
should.equal(
278294
err.message,
279295
`Failed to ${DispositionType.deadletter} the message as the AMQP link with which the message was received is no longer alive.`,
@@ -288,6 +304,9 @@ describe("Message settlement After Receiver is Closed - Through ManagementLink",
288304
should.equal(errorWasThrown, false, "Error was thrown for sessions without session-id");
289305
}
290306

307+
testLogger.info(
308+
`Creating a peek lock dead letter receiver and attempting to receive the dead lettered message`
309+
);
291310
receiver = await serviceBusClient.test.createPeekLockReceiver(entityNames);
292311

293312
if (!entityNames.usesSessions) {
@@ -310,22 +329,30 @@ describe("Message settlement After Receiver is Closed - Through ManagementLink",
310329
"MessageId is different than expected"
311330
);
312331

332+
testLogger.info(`Attempting to complete the message: ${deadLetterMsgsBatch[0].messageId}`);
313333
await receiver.completeMessage(deadLetterMsgsBatch[0]);
314-
315334
await testPeekMsgsLength(deadLetterReceiver, 0);
316335
} else {
317336
const messageBatch = await receiver.receiveMessages(1);
318-
await receiver.completeMessage(messageBatch[0]);
319337

338+
testLogger.info(`Attempting to complete the message: ${messageBatch[0].messageId}`);
339+
await receiver.completeMessage(messageBatch[0]);
320340
await testPeekMsgsLength(receiver, 0);
321341
}
342+
343+
testLogger.info(`Done testing dead letter`);
322344
}
323345

324346
it(
325347
noSessionTestClientType + ": deadLetter() moves message to deadletter queue",
326348
async function(): Promise<void> {
327-
await beforeEachTest(noSessionTestClientType);
328-
await testDeadletter();
349+
enableCommonLoggers();
350+
try {
351+
await beforeEachTest(noSessionTestClientType);
352+
await testDeadletter();
353+
} finally {
354+
disableCommonLoggers();
355+
}
329356
}
330357
);
331358

0 commit comments

Comments
 (0)