[Cases] Total users returned by suggested users API (#161329)

Connected to https://github.com/elastic/kibana/issues/146945

## Summary

| Description  | Limit | Done? | Documented?
| ------------- | ---- | :---: | ---- |
| Total number of users returned by suggest users API | 10 |
 | No (internal) |

### Checklist

Delete any items that are not applicable to this PR.

- [x]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
This commit is contained in:
Antonio 2023-07-07 15:53:59 +02:00 committed by GitHub
parent 3eb387c7dd
commit ec6bcd69b8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 150 additions and 3 deletions

View file

@ -5,6 +5,8 @@
* 2.0.
*/
import { PathReporter } from 'io-ts/lib/PathReporter';
import { MAX_SUGGESTED_PROFILES } from '../../constants';
import { SuggestUserProfilesRequestRt, CaseUserProfileRt } from './user_profiles';
describe('userProfile', () => {
@ -44,6 +46,21 @@ describe('userProfile', () => {
});
});
it('missing size parameter works correctly', () => {
const query = SuggestUserProfilesRequestRt.decode({
name: 'di maria',
owners: ['benfica'],
});
expect(query).toStrictEqual({
_tag: 'Right',
right: {
name: 'di maria',
owners: ['benfica'],
},
});
});
it('removes foo:bar attributes from request', () => {
const query = SuggestUserProfilesRequestRt.decode({ ...defaultRequest, foo: 'bar' });
@ -56,6 +73,24 @@ describe('userProfile', () => {
},
});
});
it(`does not accept size param bigger than ${MAX_SUGGESTED_PROFILES}`, () => {
const query = SuggestUserProfilesRequestRt.decode({
...defaultRequest,
size: MAX_SUGGESTED_PROFILES + 1,
});
expect(PathReporter.report(query)).toContain('The size field cannot be more than 10.');
});
it('does not accept size param lower than 1', () => {
const query = SuggestUserProfilesRequestRt.decode({
...defaultRequest,
size: 0,
});
expect(PathReporter.report(query)).toContain('The size field cannot be less than 1.');
});
});
describe('CaseUserProfileRt', () => {

View file

@ -6,13 +6,19 @@
*/
import * as rt from 'io-ts';
import { MAX_SUGGESTED_PROFILES } from '../../constants';
import { limitedNumberSchema } from '../../schema';
export const SuggestUserProfilesRequestRt = rt.intersection([
rt.strict({
name: rt.string,
owners: rt.array(rt.string),
}),
rt.exact(rt.partial({ size: rt.number })),
rt.exact(
rt.partial({
size: limitedNumberSchema({ fieldName: 'size', min: 1, max: MAX_SUGGESTED_PROFILES }),
})
),
]);
export type SuggestUserProfilesRequest = rt.TypeOf<typeof SuggestUserProfilesRequestRt>;

View file

@ -124,6 +124,7 @@ export const MAX_COMMENT_LENGTH = 30000 as const;
export const MAX_LENGTH_PER_TAG = 256 as const;
export const MAX_TAGS_PER_CASE = 200 as const;
export const MAX_DELETE_IDS_LENGTH = 100 as const;
export const MAX_SUGGESTED_PROFILES = 10 as const;
export const MAX_CASES_TO_UPDATE = 100 as const;
/**

View file

@ -7,7 +7,13 @@
import { PathReporter } from 'io-ts/lib/PathReporter';
import { limitedArraySchema, limitedStringSchema, NonEmptyString, paginationSchema } from '.';
import {
limitedArraySchema,
limitedNumberSchema,
limitedStringSchema,
NonEmptyString,
paginationSchema,
} from '.';
import { MAX_DOCS_PER_PAGE } from '../constants';
describe('schema', () => {
@ -281,4 +287,36 @@ describe('schema', () => {
`);
});
});
describe('limitedNumberSchema', () => {
it('works correctly the number is between min and max', () => {
expect(
PathReporter.report(limitedNumberSchema({ fieldName: 'foo', min: 0, max: 2 }).decode(1))
).toMatchInlineSnapshot(`
Array [
"No errors!",
]
`);
});
it('fails when given a number that is lower than the minimum', () => {
expect(
PathReporter.report(limitedNumberSchema({ fieldName: 'foo', min: 1, max: 2 }).decode(0))
).toMatchInlineSnapshot(`
Array [
"The foo field cannot be less than 1.",
]
`);
});
it('fails when given number that is higher than the maximum', () => {
expect(
PathReporter.report(limitedNumberSchema({ fieldName: 'foo', min: 1, max: 2 }).decode(3))
).toMatchInlineSnapshot(`
Array [
"The foo field cannot be more than 2.",
]
`);
});
});
});

View file

@ -134,3 +134,22 @@ export const paginationSchema = ({ maxPerPage }: { maxPerPage: number }) =>
rt.identity,
undefined
);
export const limitedNumberSchema = ({ fieldName, min, max }: LimitedSchemaType) =>
new rt.Type<number, number, unknown>(
'LimitedNumber',
rt.number.is,
(input, context) =>
either.chain(rt.number.validate(input, context), (s) => {
if (s < min) {
return rt.failure(input, context, `The ${fieldName} field cannot be less than ${min}.`);
}
if (s > max) {
return rt.failure(input, context, `The ${fieldName} field cannot be more than ${max}.`);
}
return rt.success(s);
}),
rt.identity
);

View file

@ -0,0 +1,33 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { MAX_SUGGESTED_PROFILES } from '../../../common/constants';
import { loggingSystemMock } from '@kbn/core/server/mocks';
import { UserProfileService } from '.';
describe('suggest', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('throws with invalid size field', async () => {
const mockLogger = loggingSystemMock.createLogger();
const userProfileService = new UserProfileService(mockLogger);
await expect(
// @ts-ignore: irrelevant missing parameters
userProfileService.suggest({
body: {
name: 'antonio',
owners: [],
size: MAX_SUGGESTED_PROFILES + 1,
},
})
).rejects.toThrow(
`Failed to retrieve suggested user profiles in service: Error: The size field cannot be more than ${MAX_SUGGESTED_PROFILES}.`
);
});
});

View file

@ -6,7 +6,7 @@
*/
import expect from '@kbn/expect';
import { APP_ID as CASES_APP_ID } from '@kbn/cases-plugin/common/constants';
import { APP_ID as CASES_APP_ID, MAX_SUGGESTED_PROFILES } from '@kbn/cases-plugin/common/constants';
import { APP_ID as SECURITY_SOLUTION_APP_ID } from '@kbn/security-solution-plugin/common/constants';
import { observabilityFeatureId as OBSERVABILITY_APP_ID } from '@kbn/observability-plugin/common';
import { FtrProviderContext } from '../../ftr_provider_context';
@ -76,5 +76,20 @@ export default ({ getService }: FtrProviderContext): void => {
});
});
}
describe('errors', () => {
it('400s when size parameter is not valid', async () => {
await suggestUserProfiles({
supertest: supertestWithoutAuth,
req: {
name: casesAllUser.username,
owners: [CASES_APP_ID],
size: MAX_SUGGESTED_PROFILES + 1,
},
auth: { user: casesAllUser, space: null },
expectedHttpCode: 400,
});
});
});
});
};