Skip to content

Commit

Permalink
fix(e2e-tests): increase timeouts for AWS tests MONGOSH-1924 (#2286)
Browse files Browse the repository at this point in the history
This should hopefully address AWS auth test flakiness on s390x,
where DNS queries can take multiple seconds each due to the host CI
setup.
  • Loading branch information
addaleax authored Dec 4, 2024
1 parent 9b2fd8d commit 6c9a9b4
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 43 deletions.
38 changes: 29 additions & 9 deletions packages/e2e-tests/test/e2e-aws.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ function getConnectionString(username?: string, password?: string): string {
}

describe('e2e AWS AUTH', function () {
this.timeout(60_000); // AWS auth tests can take longer than the default timeout in CI
// AWS auth tests can take longer than the default timeout in CI
// DNS resolution for many hosts in particular can be time-intensive in some
// CI environments
this.timeout(80_000);
const initialWaitForPromptTimeoutOptions = { timeout: 60_000 };
let expectedAssumedRole: string;

before(function () {
Expand Down Expand Up @@ -128,7 +132,9 @@ describe('e2e AWS AUTH', function () {
AWS_SECRET_ACCESS_KEY,
],
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand All @@ -150,7 +156,9 @@ describe('e2e AWS AUTH', function () {
tokenDetails.token,
],
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand All @@ -165,7 +173,9 @@ describe('e2e AWS AUTH', function () {
const shell = this.startTestShell({
args: [getConnectionString(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)],
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand All @@ -186,7 +196,9 @@ describe('e2e AWS AUTH', function () {
)}`,
],
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand All @@ -208,7 +220,9 @@ describe('e2e AWS AUTH', function () {
AWS_SECRET_ACCESS_KEY,
},
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand All @@ -228,7 +242,9 @@ describe('e2e AWS AUTH', function () {
AWS_SESSION_TOKEN: tokenDetails.token,
},
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand All @@ -254,7 +270,9 @@ describe('e2e AWS AUTH', function () {
AWS_SECRET_ACCESS_KEY: 'invalid',
},
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand Down Expand Up @@ -282,7 +300,9 @@ describe('e2e AWS AUTH', function () {
AWS_SESSION_TOKEN: 'invalid',
},
});
const result = await shell.waitForPromptOrExit();
const result = await shell.waitForPromptOrExit(
initialWaitForPromptTimeoutOptions
);
expect(result.state).to.equal('prompt');

const connectionStatus = await shell.executeLine(
Expand Down
78 changes: 44 additions & 34 deletions packages/e2e-tests/test/test-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,40 +199,46 @@ export class TestShell {
});
}

async waitForPrompt(start = 0): Promise<void> {
await eventually(() => {
const output = this._output.slice(start);
const lines = output.split('\n');
const found = !!lines
.filter((l) => PROMPT_PATTERN.exec(l)) // a line that is the prompt must at least match the pattern
.find((l) => {
// in some situations the prompt occurs multiple times in the line (but only in tests!)
const prompts = l
.trim()
.replace(/>$/g, '')
.split('>')
.map((m) => m.trim());
// if there are multiple prompt parts they must all equal
if (prompts.length > 1) {
for (const p of prompts) {
if (p !== prompts[0]) {
return false;
async waitForPrompt(
start = 0,
opts: { timeout?: number } = {}
): Promise<void> {
await eventually(
() => {
const output = this._output.slice(start);
const lines = output.split('\n');
const found = !!lines
.filter((l) => PROMPT_PATTERN.exec(l)) // a line that is the prompt must at least match the pattern
.find((l) => {
// in some situations the prompt occurs multiple times in the line (but only in tests!)
const prompts = l
.trim()
.replace(/>$/g, '')
.split('>')
.map((m) => m.trim());
// if there are multiple prompt parts they must all equal
if (prompts.length > 1) {
for (const p of prompts) {
if (p !== prompts[0]) {
return false;
}
}
}
}
return true;
});
if (!found) {
throw new assert.AssertionError({
message: 'expected prompt',
expected: PROMPT_PATTERN.toString(),
actual:
this._output.slice(0, start) +
'[prompt search starts here]' +
output,
});
}
});
return true;
});
if (!found) {
throw new assert.AssertionError({
message: 'expected prompt',
expected: PROMPT_PATTERN.toString(),
actual:
this._output.slice(0, start) +
'[prompt search starts here]' +
output,
});
}
},
{ ...opts }
);
}

waitForExit(): Promise<number> {
Expand All @@ -248,9 +254,13 @@ export class TestShell {
return this.output;
}

async waitForPromptOrExit(): Promise<TestShellStartupResult> {
async waitForPromptOrExit(
opts: { timeout?: number; start?: number } = {}
): Promise<TestShellStartupResult> {
return Promise.race([
this.waitForPrompt().then(() => ({ state: 'prompt' } as const)),
this.waitForPrompt(opts.start ?? 0, opts).then(
() => ({ state: 'prompt' } as const)
),
this.waitForExit().then((c) => ({ state: 'exit', exitCode: c } as const)),
]);
}
Expand Down

0 comments on commit 6c9a9b4

Please sign in to comment.