Skip to content

Commit

Permalink
[Cases] Total users returned by suggested users API (#161329)
Browse files Browse the repository at this point in the history
Connected to #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
  • Loading branch information
adcoelho authored Jul 7, 2023
1 parent 3eb387c commit ec6bcd6
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 3 deletions.
35 changes: 35 additions & 0 deletions x-pack/plugins/cases/common/api/cases/user_profile.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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' });

Expand All @@ -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', () => {
Expand Down
8 changes: 7 additions & 1 deletion x-pack/plugins/cases/common/api/cases/user_profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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>;
Expand Down
1 change: 1 addition & 0 deletions x-pack/plugins/cases/common/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down
40 changes: 39 additions & 1 deletion x-pack/plugins/cases/common/schema/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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.",
]
`);
});
});
});
19 changes: 19 additions & 0 deletions x-pack/plugins/cases/common/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
33 changes: 33 additions & 0 deletions x-pack/plugins/cases/server/services/user_profiles/index.test.ts
Original file line number Diff line number Diff line change
@@ -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}.`
);
});
});
17 changes: 16 additions & 1 deletion x-pack/test/api_integration/apis/cases/suggest_user_profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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,
});
});
});
});
};

0 comments on commit ec6bcd6

Please sign in to comment.