-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation of context aware alert analysis (#215)
* support context aware alert analysis Signed-off-by: Hailong Cui <[email protected]> * Render GeneratePopover IncontextInsight component as a button to generate summary Signed-off-by: Songkan Tang <[email protected]> * Remove hardcoded assistant role from the parameter payload Signed-off-by: Songkan Tang <[email protected]> * Make GeneratePopoverBody as independent component Signed-off-by: Songkan Tang <[email protected]> * Update change log Signed-off-by: Songkan Tang <[email protected]> * Add independent GeneratePopoverBody ut and reorgnize constants Signed-off-by: Songkan Tang <[email protected]> * Simplify states of loading to get summary process Signed-off-by: Songkan Tang <[email protected]> * Make IncontextInsight not shareable and each component has its own IncontextInsight Signed-off-by: Songkan Tang <[email protected]> * Enable context aware alert only if feature flag is enabled Signed-off-by: Songkan Tang <[email protected]> --------- Signed-off-by: Hailong Cui <[email protected]> Signed-off-by: Songkan Tang <[email protected]> Co-authored-by: Hailong Cui <[email protected]>
- Loading branch information
1 parent
d94b896
commit 32888dd
Showing
15 changed files
with
529 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
public/components/incontext_insight/generate_popover_body.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
import React from 'react'; | ||
import { render, cleanup, fireEvent, waitFor } from '@testing-library/react'; | ||
import { getConfigSchema, getNotifications } from '../../services'; | ||
import { GeneratePopoverBody } from './generate_popover_body'; | ||
import { HttpSetup } from '../../../../../src/core/public'; | ||
import { ASSISTANT_API } from '../../../common/constants/llm'; | ||
|
||
jest.mock('../../services'); | ||
|
||
const mockToasts = { | ||
addDanger: jest.fn(), | ||
}; | ||
|
||
beforeEach(() => { | ||
(getNotifications as jest.Mock).mockImplementation(() => ({ | ||
toasts: mockToasts, | ||
})); | ||
(getConfigSchema as jest.Mock).mockReturnValue({ | ||
chat: { enabled: true }, | ||
}); | ||
}); | ||
|
||
afterEach(cleanup); | ||
|
||
const mockPost = jest.fn(); | ||
const mockHttpSetup: HttpSetup = ({ | ||
post: mockPost, | ||
} as unknown) as HttpSetup; // Mocking HttpSetup | ||
|
||
describe('GeneratePopoverBody', () => { | ||
const incontextInsightMock = { | ||
contextProvider: jest.fn(), | ||
suggestions: ['Test summarization question'], | ||
datasourceId: 'test-datasource', | ||
key: 'test-key', | ||
}; | ||
|
||
const closePopoverMock = jest.fn(); | ||
|
||
it('renders the generate summary button', () => { | ||
const { getByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
expect(getByText('Generate summary')).toBeInTheDocument(); | ||
}); | ||
|
||
it('calls onGenerateSummary when button is clicked', async () => { | ||
mockPost.mockResolvedValue({ | ||
interactions: [{ conversation_id: 'test-conversation' }], | ||
messages: [{ type: 'output', content: 'Generated summary content' }], | ||
}); | ||
|
||
const { getByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
const button = getByText('Generate summary'); | ||
fireEvent.click(button); | ||
|
||
// Wait for loading to complete and summary to render | ||
await waitFor(() => { | ||
expect(getByText('Generated summary content')).toBeInTheDocument(); | ||
}); | ||
|
||
expect(mockPost).toHaveBeenCalledWith(ASSISTANT_API.SEND_MESSAGE, expect.any(Object)); | ||
expect(mockToasts.addDanger).not.toHaveBeenCalled(); | ||
}); | ||
|
||
it('shows loading state while generating summary', async () => { | ||
const { getByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
const button = getByText('Generate summary'); | ||
fireEvent.click(button); | ||
|
||
// Wait for loading state to appear | ||
expect(getByText('Generating summary...')).toBeInTheDocument(); | ||
}); | ||
|
||
it('handles error during summary generation', async () => { | ||
mockPost.mockRejectedValue(new Error('Network Error')); | ||
|
||
const { getByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
const button = getByText('Generate summary'); | ||
fireEvent.click(button); | ||
|
||
await waitFor(() => { | ||
expect(mockToasts.addDanger).toHaveBeenCalledWith('Generate summary error'); | ||
}); | ||
}); | ||
|
||
it('renders the continue in chat button after summary is generated', async () => { | ||
mockPost.mockResolvedValue({ | ||
interactions: [{ conversation_id: 'test-conversation' }], | ||
messages: [{ type: 'output', content: 'Generated summary content' }], | ||
}); | ||
|
||
const { getByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
const button = getByText('Generate summary'); | ||
fireEvent.click(button); | ||
|
||
// Wait for the summary to be displayed | ||
await waitFor(() => { | ||
expect(getByText('Generated summary content')).toBeInTheDocument(); | ||
}); | ||
|
||
// Check for continue in chat button | ||
expect(getByText('Continue in chat')).toBeInTheDocument(); | ||
}); | ||
|
||
it('calls onChatContinuation when continue in chat button is clicked', async () => { | ||
mockPost.mockResolvedValue({ | ||
interactions: [{ conversation_id: 'test-conversation' }], | ||
messages: [{ type: 'output', content: 'Generated summary content' }], | ||
}); | ||
|
||
const { getByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
const button = getByText('Generate summary'); | ||
fireEvent.click(button); | ||
|
||
await waitFor(() => { | ||
expect(getByText('Generated summary content')).toBeInTheDocument(); | ||
}); | ||
|
||
const continueButton = getByText('Continue in chat'); | ||
fireEvent.click(continueButton); | ||
|
||
expect(mockPost).toHaveBeenCalledTimes(1); | ||
expect(closePopoverMock).toHaveBeenCalled(); | ||
}); | ||
|
||
it("continue in chat button doesn't appear when chat is disabled", async () => { | ||
mockPost.mockResolvedValue({ | ||
interactions: [{ conversation_id: 'test-conversation' }], | ||
messages: [{ type: 'output', content: 'Generated summary content' }], | ||
}); | ||
(getConfigSchema as jest.Mock).mockReturnValue({ | ||
chat: { enabled: false }, | ||
}); | ||
|
||
const { getByText, queryByText } = render( | ||
<GeneratePopoverBody | ||
incontextInsight={incontextInsightMock} | ||
httpSetup={mockHttpSetup} | ||
closePopover={closePopoverMock} | ||
/> | ||
); | ||
|
||
const button = getByText('Generate summary'); | ||
fireEvent.click(button); | ||
|
||
await waitFor(() => { | ||
expect(getByText('Generated summary content')).toBeInTheDocument(); | ||
}); | ||
|
||
expect(queryByText('Continue in chat')).toBeNull(); | ||
expect(mockPost).toHaveBeenCalledTimes(1); | ||
}); | ||
}); |
Oops, something went wrong.