Skip to content

Commit

Permalink
[Obs AI Assistant] unskip kb user instructions test in serverless (el…
Browse files Browse the repository at this point in the history
…astic#205519)

## Summary
Resolves elastic#192886

- Unskips `knowledge_base_user_instructions.spec.ts` in serverless
  - stays skipped in mki due to proxy usage issue
  - Duplicates new changes from non serverless
- Removes `skipInMKI` tags for:
`knowledge_base_setup.spec.ts`
`knowledge_base.spec.ts `
`knowledge_base_status.spec.ts`


If elastic#192718 is merged before
this, I will move `knowledge_base_user_instructions.spec.ts` to
deployment agnostic. Otherwise It can be done in that PR or another.
  • Loading branch information
neptunian authored Jan 4, 2025
1 parent 6049493 commit b17b10e
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient');

describe('Knowledge base', function () {
// TODO: https://github.com/elastic/kibana/issues/192886 kb/setup error
this.tags(['skipMKI']);
before(async () => {
await createKnowledgeBaseModel(ml);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient');

describe('/internal/observability_ai_assistant/kb/setup', function () {
// TODO: https://github.com/elastic/kibana/issues/192886 kb/setup error
this.tags(['skipMKI']);

before(async () => {
await deleteKnowledgeBaseModel(ml).catch(() => {});
await deleteInferenceEndpoint({ es }).catch(() => {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ export default function ApiTest({ getService }: FtrProviderContext) {
const observabilityAIAssistantAPIClient = getService('observabilityAIAssistantAPIClient');

describe('/internal/observability_ai_assistant/kb/status', function () {
this.tags(['skipMKI']);

before(async () => {
await createKnowledgeBaseModel(ml);
await observabilityAIAssistantAPIClient
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import expect from '@kbn/expect';
import { sortBy } from 'lodash';
import { Message, MessageRole } from '@kbn/observability-ai-assistant-plugin/common';
import { CONTEXT_FUNCTION_NAME } from '@kbn/observability-ai-assistant-plugin/server/functions/context';
import { Instruction } from '@kbn/observability-ai-assistant-plugin/common/types';
import {
clearConversations,
clearKnowledgeBase,
createKnowledgeBaseModel,
deleteInferenceEndpoint,
deleteKnowledgeBaseModel,
TINY_ELSER,
} from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/knowledge_base/helpers';
import { getConversationCreatedEvent } from '@kbn/test-suites-xpack/observability_ai_assistant_api_integration/tests/conversations/helpers';
import {
Expand All @@ -33,8 +35,10 @@ export default function ApiTest({ getService }: FtrProviderContext) {
const log = getService('log');
const svlUserManager = getService('svlUserManager');
const svlCommonApi = getService('svlCommonApi');
const retry = getService('retry');

describe.skip('Knowledge base user instructions', function () {
describe('Knowledge base user instructions', function () {
// TODO: https://github.com/elastic/kibana/issues/192751
this.tags(['skipMKI']);
let editorRoleAuthc: RoleCredentials;
let internalReqHeader: InternalRequestHeader;
Expand All @@ -45,8 +49,13 @@ export default function ApiTest({ getService }: FtrProviderContext) {
await createKnowledgeBaseModel(ml);

await observabilityAIAssistantAPIClient
.slsEditor({
.slsAdmin({
endpoint: 'POST /internal/observability_ai_assistant/kb/setup',
params: {
query: {
model_id: TINY_ELSER.id,
},
},
})
.expect(200);
});
Expand All @@ -64,10 +73,22 @@ export default function ApiTest({ getService }: FtrProviderContext) {
await clearKnowledgeBase(es);

const promises = [
{ username: 'editor', isPublic: true },
{ username: 'editor', isPublic: false },
{ username: 'john', isPublic: true },
{ username: 'john', isPublic: false },
{
username: 'editor' as const,
isPublic: true,
},
{
username: 'editor' as const,
isPublic: false,
},
{
username: 'secondary_editor' as const,
isPublic: true,
},
{
username: 'secondary_editor' as const,
isPublic: false,
},
].map(async ({ username, isPublic }) => {
const visibility = isPublic ? 'Public' : 'Private';
const user = username === 'editor' ? 'slsEditor' : 'slsAdmin';
Expand All @@ -88,61 +109,69 @@ export default function ApiTest({ getService }: FtrProviderContext) {
});

it('"editor" can retrieve their own private instructions and the public instruction', async () => {
const res = await observabilityAIAssistantAPIClient.slsEditor({
endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions',
await retry.try(async () => {
const res = await observabilityAIAssistantAPIClient.slsEditor({
endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions',
});

const instructions = res.body.userInstructions;
// TODO: gets 4 in serverless, bufferFlush event?
expect(instructions).to.have.length(3);

const sortById = (data: Array<Instruction & { public?: boolean }>) => sortBy(data, 'id');
expect(sortById(instructions)).to.eql(
sortById([
{
id: 'private-doc-from-editor',
public: false,
text: 'Private user instruction from "editor"',
},
{
id: 'public-doc-from-editor',
public: true,
text: 'Public user instruction from "editor"',
},
{
id: 'public-doc-from-secondary_editor',
public: true,
text: 'Public user instruction from "secondary_editor"',
},
])
);
});

const instructions = res.body.userInstructions;

const sortByDocId = (data: any) => sortBy(data, 'doc_id');
expect(sortByDocId(instructions)).to.eql(
sortByDocId([
{
doc_id: 'private-doc-from-editor',
public: false,
text: 'Private user instruction from "editor"',
},
{
doc_id: 'public-doc-from-editor',
public: true,
text: 'Public user instruction from "editor"',
},
{
doc_id: 'public-doc-from-john',
public: true,
text: 'Public user instruction from "john"',
},
])
);
});

it('"john" can retrieve their own private instructions and the public instruction', async () => {
const res = await observabilityAIAssistantAPIClient.slsAdmin({
endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions',
});
it('"secondaryEditor" can retrieve their own private instructions and the public instruction', async () => {
await retry.try(async () => {
const res = await observabilityAIAssistantAPIClient.slsAdmin({
endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions',
});

const instructions = res.body.userInstructions;
const instructions = res.body.userInstructions;
expect(instructions).to.have.length(3);

const sortByDocId = (data: any) => sortBy(data, 'doc_id');
expect(sortByDocId(instructions)).to.eql(
sortByDocId([
{
doc_id: 'public-doc-from-editor',
public: true,
text: 'Public user instruction from "editor"',
},
{
doc_id: 'public-doc-from-john',
public: true,
text: 'Public user instruction from "john"',
},
{
doc_id: 'private-doc-from-john',
public: false,
text: 'Private user instruction from "john"',
},
])
);
const sortById = (data: Array<Instruction & { public?: boolean }>) => sortBy(data, 'id');

expect(sortById(instructions)).to.eql(
sortById([
{
id: 'public-doc-from-editor',
public: true,
text: 'Public user instruction from "editor"',
},
{
id: 'public-doc-from-secondary_editor',
public: true,
text: 'Public user instruction from "secondary_editor"',
},
{
id: 'private-doc-from-secondary_editor',
public: false,
text: 'Private user instruction from "secondary_editor"',
},
])
);
});
});
});

Expand Down Expand Up @@ -186,7 +215,7 @@ export default function ApiTest({ getService }: FtrProviderContext) {

expect(instructions).to.eql([
{
doc_id: 'doc-to-update',
id: 'doc-to-update',
text: 'Updated text',
public: false,
},
Expand Down Expand Up @@ -330,6 +359,37 @@ export default function ApiTest({ getService }: FtrProviderContext) {
});
});

describe('Instructions can be saved and cleared again', () => {
async function updateInstruction(text: string) {
await observabilityAIAssistantAPIClient
.slsEditor({
endpoint: 'PUT /internal/observability_ai_assistant/kb/user_instructions',
params: {
body: {
id: 'my-instruction-that-will-be-cleared',
text,
public: false,
},
},
})
.expect(200);

const res = await observabilityAIAssistantAPIClient
.slsEditor({ endpoint: 'GET /internal/observability_ai_assistant/kb/user_instructions' })
.expect(200);

return res.body.userInstructions[0].text;
}

it('can clear the instruction', async () => {
const res1 = await updateInstruction('This is a user instruction that will be cleared');
expect(res1).to.be('This is a user instruction that will be cleared');

const res2 = await updateInstruction('');
expect(res2).to.be('');
});
});

describe('security roles and access privileges', () => {
describe('should deny access for users without the ai_assistant privilege', () => {
it('PUT /internal/observability_ai_assistant/kb/user_instructions', async () => {
Expand Down

0 comments on commit b17b10e

Please sign in to comment.