Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into markdown-eslint-f…
Browse files Browse the repository at this point in the history
…ixes
  • Loading branch information
flash1293 committed Jan 10, 2020
2 parents b2a4a38 + d8f94b1 commit cc0a974
Show file tree
Hide file tree
Showing 10 changed files with 169 additions and 10 deletions.
55 changes: 55 additions & 0 deletions src/core/server/http/integration_tests/router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,61 @@ describe('Handler', () => {
statusCode: 400,
});
});

it('accept to receive an array payload', async () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');

let body: any = null;
router.post(
{
path: '/',
validate: {
body: schema.arrayOf(schema.object({ foo: schema.string() })),
},
},
(context, req, res) => {
body = req.body;
return res.ok({ body: 'ok' });
}
);
await server.start();

await supertest(innerServer.listener)
.post('/')
.send([{ foo: 'bar' }, { foo: 'dolly' }])
.expect(200);

expect(body).toEqual([{ foo: 'bar' }, { foo: 'dolly' }]);
});

it('accept to receive a json primitive payload', async () => {
const { server: innerServer, createRouter } = await server.setup(setupDeps);
const router = createRouter('/');

let body: any = null;
router.post(
{
path: '/',
validate: {
body: schema.number(),
},
},
(context, req, res) => {
body = req.body;
return res.ok({ body: 'ok' });
}
);
await server.start();

await supertest(innerServer.listener)
.post('/')
.type('json')
.send('12')
.expect(200);

expect(body).toEqual(12);
});
});

describe('handleLegacyErrors', () => {
Expand Down
58 changes: 58 additions & 0 deletions src/core/server/http/router/validator/validator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,62 @@ describe('Router validator', () => {
'The validation rule provided in the handler is not valid'
);
});

it('should validate and infer type when data is an array', () => {
expect(
RouteValidator.from({
body: schema.arrayOf(schema.string()),
}).getBody(['foo', 'bar'])
).toStrictEqual(['foo', 'bar']);
expect(
RouteValidator.from({
body: schema.arrayOf(schema.number()),
}).getBody([1, 2, 3])
).toStrictEqual([1, 2, 3]);
expect(
RouteValidator.from({
body: schema.arrayOf(schema.object({ foo: schema.string() })),
}).getBody([{ foo: 'bar' }, { foo: 'dolly' }])
).toStrictEqual([{ foo: 'bar' }, { foo: 'dolly' }]);

expect(() =>
RouteValidator.from({
body: schema.arrayOf(schema.number()),
}).getBody(['foo', 'bar', 'dolly'])
).toThrowError('[0]: expected value of type [number] but got [string]');
expect(() =>
RouteValidator.from({
body: schema.arrayOf(schema.number()),
}).getBody({ foo: 'bar' })
).toThrowError('expected value of type [array] but got [Object]');
});

it('should validate and infer type when data is a primitive', () => {
expect(
RouteValidator.from({
body: schema.string(),
}).getBody('foobar')
).toStrictEqual('foobar');
expect(
RouteValidator.from({
body: schema.number(),
}).getBody(42)
).toStrictEqual(42);
expect(
RouteValidator.from({
body: schema.boolean(),
}).getBody(true)
).toStrictEqual(true);

expect(() =>
RouteValidator.from({
body: schema.string(),
}).getBody({ foo: 'bar' })
).toThrowError('expected value of type [string] but got [Object]');
expect(() =>
RouteValidator.from({
body: schema.number(),
}).getBody('foobar')
).toThrowError('expected value of type [number] but got [string]');
});
});
2 changes: 1 addition & 1 deletion src/core/server/http/router/validator/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ export class RouteValidator<P = {}, Q = {}, B = {}> {
// if options.body.output === 'stream'
return schema.stream();
} else {
return schema.maybe(schema.nullable(schema.object({}, { allowUnknowns: true })));
return schema.maybe(schema.nullable(schema.any({})));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ export function KbnAggTable(config, RecursionHelper) {
// escape each cell in each row
const csvRows = rows.map(function(row) {
return Object.entries(row).map(([k, v]) => {
return escape(formatted ? columns.find(c => c.id === k).formatter.convert(v) : v);
const column = columns.find(c => c.id === k);
if (formatted && column) {
return escape(column.formatter.convert(v));
}
return escape(v);
});
});

Expand Down Expand Up @@ -110,12 +114,16 @@ export function KbnAggTable(config, RecursionHelper) {

if (typeof $scope.dimensions === 'undefined') return;

const { buckets, metrics } = $scope.dimensions;
const { buckets, metrics, splitColumn } = $scope.dimensions;

$scope.formattedColumns = table.columns
.map(function(col, i) {
const isBucket = buckets.find(bucket => bucket.accessor === i);
const dimension = isBucket || metrics.find(metric => metric.accessor === i);
const isSplitColumn = splitColumn
? splitColumn.find(splitColumn => splitColumn.accessor === i)
: undefined;
const dimension =
isBucket || isSplitColumn || metrics.find(metric => metric.accessor === i);

if (!dimension) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,5 @@ export type TestSubjects =
| 'webhookPathInput'
| 'webhookPortInput'
| 'webhookMethodSelect'
| 'webhookSchemeSelect'
| 'webhookUsernameInput';
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
const METHOD = 'put';
const HOST = 'localhost';
const PORT = '9200';
const SCHEME = 'http';
const PATH = '/test';
const USERNAME = 'test_user';
const PASSWORD = 'test_password';
Expand All @@ -510,6 +511,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
form.setInputValue('webhookMethodSelect', METHOD);
form.setInputValue('webhookHostInput', HOST);
form.setInputValue('webhookPortInput', PORT);
form.setInputValue('webhookSchemeSelect', SCHEME);
form.setInputValue('webhookPathInput', PATH);
form.setInputValue('webhookUsernameInput', USERNAME);
form.setInputValue('webhookPasswordInput', PASSWORD);
Expand All @@ -534,6 +536,7 @@ describe('<ThresholdWatchEdit /> create route', () => {
method: METHOD,
host: HOST,
port: Number(PORT),
scheme: SCHEME,
path: PATH,
body:
'{\n "message": "Watch [{{ctx.metadata.name}}] has exceeded the threshold"\n}', // Default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class WebhookAction extends BaseAction {
this.method = props.method;
this.host = props.host;
this.port = props.port;
this.scheme = props.scheme;
this.path = props.path;
this.body = props.body;
this.contentType = props.contentType;
Expand All @@ -30,6 +31,7 @@ export class WebhookAction extends BaseAction {
method: this.method,
host: this.host,
port: this.port,
scheme: this.scheme,
path: this.path,
body: this.body,
contentType: this.contentType,
Expand All @@ -47,6 +49,7 @@ export class WebhookAction extends BaseAction {
method: json.method,
host: json.host,
port: json.port,
scheme: json.scheme,
path: json.path,
body: json.body,
contentType: json.contentType,
Expand All @@ -72,6 +75,10 @@ export class WebhookAction extends BaseAction {
optionalFields.method = this.method;
}

if (this.scheme) {
optionalFields.scheme = this.scheme;
}

if (this.body) {
optionalFields.body = this.body;
}
Expand Down Expand Up @@ -108,7 +115,7 @@ export class WebhookAction extends BaseAction {
const webhookJson = json && json.actionJson && json.actionJson.webhook;
const { errors } = this.validateJson(json.actionJson);

const { path, method, body, auth, headers } = webhookJson;
const { path, method, scheme, body, auth, headers } = webhookJson;

const optionalFields = {};

Expand All @@ -120,6 +127,10 @@ export class WebhookAction extends BaseAction {
optionalFields.method = method;
}

if (scheme) {
optionalFields.scheme = scheme;
}

if (body) {
optionalFields.body = body;
}
Expand Down
1 change: 1 addition & 0 deletions x-pack/legacy/plugins/watcher/common/types/action_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export interface WebhookAction extends BaseAction {
method?: 'head' | 'get' | 'post' | 'put' | 'delete';
host: string;
port: number;
scheme?: 'http' | 'https';
path?: string;
body?: string;
username?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,21 @@ import { i18n } from '@kbn/i18n';
export class WebhookAction extends BaseAction {
constructor(props = {}) {
super(props);

const defaultJson = JSON.stringify(
{ message: 'Watch [{{ctx.metadata.name}}] has exceeded the threshold' },
null,
2
);
this.body = get(props, 'body', props.ignoreDefaults ? null : defaultJson);

this.method = get(props, 'method');
this.host = get(props, 'host');
this.port = get(props, 'port');
this.scheme = get(props, 'scheme', 'http');
this.path = get(props, 'path');
this.username = get(props, 'username');
this.password = get(props, 'password');
this.contentType = get(props, 'contentType');

this.fullPath = `${this.host}:${this.port}${this.path}`;
this.fullPath = `${this.host}:${this.port}${this.path ? '/' + this.path : ''}`;
}

validate() {
Expand Down Expand Up @@ -112,6 +110,7 @@ export class WebhookAction extends BaseAction {
method: this.method,
host: this.host,
port: this.port,
scheme: this.scheme,
path: this.path,
body: this.body,
username: this.username,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ interface Props {

const HTTP_VERBS = ['head', 'get', 'post', 'put', 'delete'];

const SCHEME = ['http', 'https'];

export const WebhookActionFields: React.FunctionComponent<Props> = ({
action,
editAction,
errors,
hasErrors,
}) => {
const { method, host, port, path, body, username, password } = action;
const { method, host, port, scheme, path, body, username, password } = action;

useEffect(() => {
editAction({ key: 'contentType', value: 'application/json' }); // set content-type for threshold watch to json by default
Expand Down Expand Up @@ -65,6 +67,27 @@ export const WebhookActionFields: React.FunctionComponent<Props> = ({
</EuiFormRow>
</EuiFlexItem>

<EuiFlexItem>
<EuiFormRow
label={i18n.translate(
'xpack.watcher.sections.watchEdit.threshold.webhookAction.schemeFieldLabel',
{
defaultMessage: 'Scheme',
}
)}
>
<EuiSelect
name="scheme"
value={scheme}
data-test-subj="webhookSchemeSelect"
options={SCHEME.map(verb => ({ text: verb, value: verb }))}
onChange={e => {
editAction({ key: 'scheme', value: e.target.value });
}}
/>
</EuiFormRow>
</EuiFlexItem>

<EuiFlexItem>
<ErrableFormRow
id="webhookHost"
Expand Down

0 comments on commit cc0a974

Please sign in to comment.