mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Obs AI Assistant] Fix flaky e2e test (contextual insights for APM errors) (#184642)
Closes https://github.com/elastic/kibana/issues/184071 https://github.com/elastic/kibana/issues/184029 Fixes flaky e2e tests - set static `error.grouping_key`. This required a small change in synthtrace. - retry clicking on contextual insight component to ensure the accordion is open.
This commit is contained in:
parent
a46ea29bbd
commit
cf47eb5aa8
7 changed files with 59 additions and 31 deletions
|
@ -25,9 +25,11 @@ export class ApmError extends Serializable<ApmFields> {
|
|||
this.fields['error.grouping_name'] || this.fields['error.exception']?.[0]?.message;
|
||||
|
||||
const [data] = super.serialize();
|
||||
data['error.grouping_key'] = errorMessage
|
||||
? generateLongIdWithSeed(errorMessage)
|
||||
: generateLongId();
|
||||
|
||||
data['error.grouping_key'] =
|
||||
this.fields['error.grouping_key'] ??
|
||||
(errorMessage ? generateLongIdWithSeed(errorMessage) : generateLongId());
|
||||
|
||||
return [data];
|
||||
}
|
||||
|
||||
|
|
|
@ -72,9 +72,20 @@ export class Instance extends Entity<ApmFields> {
|
|||
'error.grouping_name': getErrorGroupingKey(message),
|
||||
});
|
||||
}
|
||||
error({ message, type, culprit }: { message: string; type?: string; culprit?: string }) {
|
||||
error({
|
||||
message,
|
||||
type,
|
||||
culprit,
|
||||
groupingKey,
|
||||
}: {
|
||||
message: string;
|
||||
type?: string;
|
||||
culprit?: string;
|
||||
groupingKey?: string;
|
||||
}) {
|
||||
return new ApmError({
|
||||
...this.fields,
|
||||
...(groupingKey ? { 'error.grouping_key': groupingKey } : {}),
|
||||
'error.exception': [{ message, ...(type ? { type } : {}) }],
|
||||
'error.culprit': culprit,
|
||||
});
|
||||
|
|
|
@ -60,7 +60,7 @@ export function InsightBase({
|
|||
return (
|
||||
<EuiPanel hasBorder hasShadow={false}>
|
||||
<EuiAccordion
|
||||
id="obsAiAssistantInsight"
|
||||
id="obsAiAssistantInsightContainer"
|
||||
arrowProps={{ css: { alignSelf: 'flex-start' } }}
|
||||
buttonContent={
|
||||
<EuiFlexGroup wrap responsive={false} gutterSize="m" data-test-subj={dataTestSubj}>
|
||||
|
|
|
@ -98,7 +98,7 @@ export class LlmProxy {
|
|||
waitForIntercept: () => Promise<LlmResponseSimulator>;
|
||||
}
|
||||
: {
|
||||
complete: () => Promise<void>;
|
||||
waitAndComplete: () => Promise<void>;
|
||||
} {
|
||||
const waitForInterceptPromise = Promise.race([
|
||||
new Promise<LlmResponseSimulator>((outerResolve) => {
|
||||
|
@ -149,7 +149,7 @@ export class LlmProxy {
|
|||
});
|
||||
}),
|
||||
new Promise<LlmResponseSimulator>((_, reject) => {
|
||||
setTimeout(() => reject(new Error(`Interceptor "${name}" timed out after 5000ms`)), 5000);
|
||||
setTimeout(() => reject(new Error(`Interceptor "${name}" timed out after 20000ms`)), 20000);
|
||||
}),
|
||||
]);
|
||||
|
||||
|
@ -162,7 +162,7 @@ export class LlmProxy {
|
|||
: responseChunks.split(' ').map((token, i) => (i === 0 ? token : ` ${token}`));
|
||||
|
||||
return {
|
||||
complete: async () => {
|
||||
waitAndComplete: async () => {
|
||||
const simulator = await waitForInterceptPromise;
|
||||
for (const chunk of parsedChunks) {
|
||||
await simulator.next(chunk);
|
||||
|
|
|
@ -414,11 +414,11 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
},
|
||||
},
|
||||
])
|
||||
.complete();
|
||||
.waitAndComplete();
|
||||
|
||||
proxy
|
||||
.intercept('conversation', (body) => !isFunctionTitleRequest(body), 'Good morning, sir!')
|
||||
.complete();
|
||||
.waitAndComplete();
|
||||
|
||||
const createResponse = await observabilityAIAssistantAPIClient
|
||||
.editorUser({
|
||||
|
@ -450,7 +450,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {
|
|||
|
||||
proxy
|
||||
.intercept('conversation', (body) => !isFunctionTitleRequest(body), 'Good night, sir!')
|
||||
.complete();
|
||||
.waitAndComplete();
|
||||
|
||||
const updatedResponse = await observabilityAIAssistantAPIClient
|
||||
.editorUser({
|
||||
|
|
|
@ -44,6 +44,7 @@ const pages = {
|
|||
saveButton: 'create-connector-flyout-save-btn',
|
||||
},
|
||||
contextualInsights: {
|
||||
container: 'obsAiAssistantInsightContainer',
|
||||
button: 'obsAiAssistantInsightButton',
|
||||
text: 'obsAiAssistantInsightResponse',
|
||||
},
|
||||
|
|
|
@ -17,14 +17,13 @@ import { FtrProviderContext } from '../../ftr_provider_context';
|
|||
|
||||
export default function ApiTest({ getService, getPageObjects }: FtrProviderContext) {
|
||||
const ui = getService('observabilityAIAssistantUI');
|
||||
const find = getService('find');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const supertest = getService('supertest');
|
||||
const retry = getService('retry');
|
||||
const log = getService('log');
|
||||
const browser = getService('browser');
|
||||
const deployment = getService('deployment');
|
||||
const apmSynthtraceEsClient = getService('apmSynthtraceEsClient');
|
||||
const { common } = getPageObjects(['header', 'common']);
|
||||
const { header, common } = getPageObjects(['header', 'common']);
|
||||
|
||||
async function createSynthtraceErrors() {
|
||||
const start = moment().subtract(5, 'minutes').valueOf();
|
||||
|
@ -45,7 +44,11 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte
|
|||
.transaction({ transactionName: 'GET /banana' })
|
||||
.errors(
|
||||
serviceInstance
|
||||
.error({ message: 'Some exception', type: 'exception' })
|
||||
.error({
|
||||
message: 'Some exception',
|
||||
type: 'exception',
|
||||
groupingKey: 'some-expection-key',
|
||||
})
|
||||
.timestamp(timestamp)
|
||||
)
|
||||
.duration(10)
|
||||
|
@ -87,9 +90,22 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte
|
|||
}
|
||||
|
||||
async function navigateToError() {
|
||||
await common.navigateToApp('apm');
|
||||
await browser.get(`${deployment.getHostPort()}/app/apm/services/opbeans-go/errors/`);
|
||||
await testSubjects.click('errorGroupId');
|
||||
await common.navigateToUrl('apm', 'services/opbeans-go/errors/some-expection-key', {
|
||||
shouldUseHashForSubUrl: false,
|
||||
});
|
||||
await header.waitUntilLoadingHasFinished();
|
||||
}
|
||||
|
||||
// open contextual insights component and ensure it was opened
|
||||
async function openContextualInsights() {
|
||||
await retry.tryForTime(5 * 1000, async () => {
|
||||
await testSubjects.click(ui.pages.contextualInsights.button);
|
||||
const isOpen =
|
||||
(await (
|
||||
await find.byCssSelector(`[aria-controls="${ui.pages.contextualInsights.container}"]`)
|
||||
).getAttribute('aria-expanded')) === 'true';
|
||||
expect(isOpen).to.be(true);
|
||||
});
|
||||
}
|
||||
|
||||
describe('Contextual insights for APM errors', () => {
|
||||
|
@ -113,16 +129,14 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte
|
|||
]);
|
||||
});
|
||||
|
||||
// FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/184029
|
||||
describe.skip('when there are no connectors', () => {
|
||||
describe('when there are no connectors', () => {
|
||||
it('should not show the contextual insight component', async () => {
|
||||
await navigateToError();
|
||||
await testSubjects.missingOrFail(ui.pages.contextualInsights.button);
|
||||
});
|
||||
});
|
||||
|
||||
// FAILING ES PROMOTION: https://github.com/elastic/kibana/issues/184071
|
||||
describe.skip('when there are connectors', () => {
|
||||
describe('when there are connectors', () => {
|
||||
let proxy: LlmProxy;
|
||||
|
||||
before(async () => {
|
||||
|
@ -137,17 +151,17 @@ export default function ApiTest({ getService, getPageObjects }: FtrProviderConte
|
|||
it('should show the contextual insight component on the APM error details page', async () => {
|
||||
await navigateToError();
|
||||
|
||||
proxy
|
||||
.intercept(
|
||||
'conversation',
|
||||
(body) => !isFunctionTitleRequest(body),
|
||||
'This error is nothing to worry about. Have a nice day!'
|
||||
)
|
||||
.complete();
|
||||
const interceptor = proxy.intercept(
|
||||
'conversation',
|
||||
(body) => !isFunctionTitleRequest(body),
|
||||
'This error is nothing to worry about. Have a nice day!'
|
||||
);
|
||||
|
||||
await testSubjects.click(ui.pages.contextualInsights.button);
|
||||
await openContextualInsights();
|
||||
|
||||
await retry.try(async () => {
|
||||
await interceptor.waitAndComplete();
|
||||
|
||||
await retry.tryForTime(5 * 1000, async () => {
|
||||
const llmResponse = await testSubjects.getVisibleText(ui.pages.contextualInsights.text);
|
||||
expect(llmResponse).to.contain('This error is nothing to worry about. Have a nice day!');
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue