[FTR] move supertestWithoutAuth service to kbn-ftr-common-functional-services (#189613)

## Summary

While working on #188737 I had to move `supertestWithoutAuth` into
`kbn-ftr-common-functional-services` package. This change seems to be
bigger than initially planned.

Moving it to the separate PR with following changes:
- move FTR `SupertestWithoutAuthProvider` service to package
- remove "duplicates" in favour of service from package
- update service type where needed
This commit is contained in:
Dzmitry Lemechko 2024-08-05 11:20:38 +02:00 committed by GitHub
parent 32b7873515
commit 477d07f7fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
44 changed files with 315 additions and 352 deletions

View file

@ -20,4 +20,7 @@ export type EsArchiver = ProvidedType<typeof EsArchiverProvider>;
import { EsProvider } from './services/es';
export type Es = ProvidedType<typeof EsProvider>;
import { SupertestWithoutAuthProvider } from './services/supertest_without_auth';
export type SupertestWithoutAuthProviderType = ProvidedType<typeof SupertestWithoutAuthProvider>;
export type { FtrProviderContext } from './services/ftr_provider_context';

View file

@ -10,10 +10,12 @@ import { EsArchiverProvider } from './es_archiver';
import { EsProvider } from './es';
import { KibanaServerProvider } from './kibana_server';
import { RetryService } from './retry';
import { SupertestWithoutAuthProvider } from './supertest_without_auth';
export const services = {
es: EsProvider,
kibanaServer: KibanaServerProvider,
esArchiver: EsArchiverProvider,
retry: RetryService,
supertestWithoutAuth: SupertestWithoutAuthProvider,
};

View file

@ -0,0 +1,28 @@
/*
* 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 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { format as formatUrl } from 'url';
import supertest from 'supertest';
import { FtrProviderContext } from './ftr_provider_context';
/**
* Returns supertest.SuperTest<supertest.Test> instance that will not persist cookie between API requests.
* If you need to pass certificate, do the following:
* await supertestWithoutAuth
* .get('/abc')
* .ca(CA_CERT)
*/
export function SupertestWithoutAuthProvider({ getService }: FtrProviderContext) {
const config = getService('config');
const kbnUrl = formatUrl({
...config.get('servers.kibana'),
auth: false,
});
return supertest(kbnUrl);
}

View file

@ -7,6 +7,7 @@
import { ES_TEST_INDEX_NAME } from '@kbn/alerting-api-integration-helpers';
import { AlertsFilter } from '@kbn/alerting-plugin/common/rule';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { Space, User } from '../types';
import { ObjectRemover } from './object_remover';
import { getUrlPrefix } from './space_test_utils';
@ -15,7 +16,7 @@ import { getTestRuleData } from './get_test_rule_data';
export interface AlertUtilsOpts {
user?: User;
space: Space;
supertestWithoutAuth: any;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
indexRecordActionId?: string;
objectRemover?: ObjectRemover;
}
@ -57,7 +58,7 @@ export class AlertUtils {
private referenceCounter = 1;
private readonly user?: User;
private readonly space: Space;
private readonly supertestWithoutAuth: any;
private readonly supertestWithoutAuth: SupertestWithoutAuthProviderType;
private readonly indexRecordActionId?: string;
private readonly objectRemover?: ObjectRemover;

View file

@ -9,6 +9,7 @@ import expect from '@kbn/expect';
import { Agent as SuperTestAgent } from 'supertest';
import { chunk, omit } from 'lodash';
import { v4 as uuidv4 } from 'uuid';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { SuperuserAtSpace1, UserAtSpaceScenarios } from '../../../scenarios';
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib';
import { FtrProviderContext } from '../../../../common/ftr_provider_context';
@ -17,7 +18,7 @@ const findTestUtils = (
describeType: 'internal' | 'public',
objectRemover: ObjectRemover,
supertest: SuperTestAgent,
supertestWithoutAuth: any
supertestWithoutAuth: SupertestWithoutAuthProviderType
) => {
describe(describeType, () => {
afterEach(async () => {

View file

@ -9,6 +9,7 @@ import expect from '@kbn/expect';
import { Agent as SuperTestAgent } from 'supertest';
import { chunk, omit } from 'lodash';
import { v4 as uuidv4 } from 'uuid';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { UserAtSpaceScenarios } from '../../../scenarios';
import { getUrlPrefix, getTestRuleData, ObjectRemover } from '../../../../common/lib';
import { FtrProviderContext } from '../../../../common/ftr_provider_context';
@ -17,7 +18,7 @@ const findTestUtils = (
describeType: 'internal' | 'public',
objectRemover: ObjectRemover,
supertest: SuperTestAgent,
supertestWithoutAuth: any
supertestWithoutAuth: SupertestWithoutAuthProviderType
) => {
describe(describeType, () => {
afterEach(async () => {

View file

@ -7,6 +7,7 @@
import expect from '@kbn/expect';
import { Agent as SuperTestAgent } from 'supertest';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { SuperuserAtSpace1, UserAtSpaceScenarios } from '../../../scenarios';
import {
getUrlPrefix,
@ -20,7 +21,7 @@ const getTestUtils = (
describeType: 'internal' | 'public',
objectRemover: ObjectRemover,
supertest: SuperTestAgent,
supertestWithoutAuth: any
supertestWithoutAuth: SupertestWithoutAuthProviderType
) => {
describe(describeType, () => {
afterEach(() => objectRemover.removeAll());

View file

@ -6,7 +6,6 @@
*/
import expect from '@kbn/expect';
import { SuperTest } from 'supertest';
import { CSV_QUOTE_VALUES_SETTING } from '@kbn/share-plugin/common/constants';
import {
ELASTIC_HTTP_VERSION_HEADER,
@ -15,7 +14,7 @@ import {
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function featureControlsTests({ getService }: FtrProviderContext) {
const supertest: SuperTest<any> = getService('supertestWithoutAuth');
const supertestWithoutAuth = getService('supertestWithoutAuth');
const security = getService('security');
const spaces = getService('spaces');
const deployment = getService('deployment');
@ -55,7 +54,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
async function saveAdvancedSetting(username: string, password: string, spaceId?: string) {
const basePath = spaceId ? `/s/${spaceId}` : '';
return await supertest
return await supertestWithoutAuth
.post(`${basePath}/internal/kibana/settings`)
.auth(username, password)
.set('kbn-xsrf', 'foo')
@ -67,7 +66,7 @@ export default function featureControlsTests({ getService }: FtrProviderContext)
async function saveTelemetrySetting(username: string, password: string, spaceId?: string) {
const basePath = spaceId ? `/s/${spaceId}` : '';
return await supertest
return await supertestWithoutAuth
.post(`${basePath}/internal/telemetry/optIn`)
.auth(username, password)
.set('kbn-xsrf', 'foo')

View file

@ -10,8 +10,6 @@ import { services as commonServices } from '../../common/services';
// @ts-ignore not ts yet
import { EsSupertestWithoutAuthProvider } from './es_supertest_without_auth';
// @ts-ignore not ts yet
import { SupertestWithoutAuthProvider } from './supertest_without_auth';
import { UsageAPIProvider } from './usage_api';
@ -36,7 +34,6 @@ export const services = {
dataViewApi: DataViewApiProvider,
esSupertestWithoutAuth: EsSupertestWithoutAuthProvider,
infraOpsSourceConfiguration: InfraOpsSourceConfigurationProvider,
supertestWithoutAuth: SupertestWithoutAuthProvider,
usageAPI: UsageAPIProvider,
ml: MachineLearningProvider,
ingestManager: IngestManagerProvider,

View file

@ -1,26 +0,0 @@
/*
* 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 { format as formatUrl } from 'url';
import supertest from 'supertest';
/**
* supertest provider that doesn't include user credentials into base URL that is passed
* to the supertest. It's used to test API behaviour for not yet authenticated user.
*/
export function SupertestWithoutAuthProvider({ getService }) {
const config = getService('config');
const kibanaServerConfig = config.get('servers.kibana');
return supertest(
formatUrl({
...kibanaServerConfig,
auth: false,
})
);
}

View file

@ -10,10 +10,10 @@
import expect from '@kbn/expect';
import request from 'superagent';
import type SuperTest from 'supertest';
import type { IEsSearchResponse } from '@kbn/search-types';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { FtrService } from '../ftr_provider_context';
const parseBfetchResponse = (resp: request.Response): Array<Record<string, any>> => {
@ -28,7 +28,7 @@ const getSpaceUrlPrefix = (spaceId?: string): string => {
};
interface SendOptions {
supertestWithoutAuth: SuperTest.Agent;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
auth: { username: string; password: string };
referer?: string;
kibanaVersion?: string;

View file

@ -6,9 +6,7 @@
*/
import { services as commonServices } from '../common/services';
import { services as apiIntegrationServices } from '../api_integration/services';
export const services = {
...commonServices,
supertestWithoutAuth: apiIntegrationServices.supertestWithoutAuth,
};

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import supertest, { type SuperTest } from 'supertest';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import supertest from 'supertest';
interface PrivilegeTestScenario {
user: {
@ -26,7 +27,7 @@ interface PrivilegeTestRoute {
export function runPrivilegeTests(
routes: PrivilegeTestRoute[],
supertestWithoutAuth: SuperTest<supertest.Test>
supertestWithoutAuth: SupertestWithoutAuthProviderType
) {
for (const route of routes) {
describe(`${route.method} ${route.path}`, () => {

View file

@ -5,17 +5,10 @@
* 2.0.
*/
import { services as kibanaApiIntegrationServices } from '@kbn/test-suites-src/api_integration/services';
import { services as kibanaFunctionalServices } from '@kbn/test-suites-src/functional/services';
import { services as commonServices } from '../../../common/services';
import { services as apiIntegrationServices } from '../../../api_integration/services';
export const services = {
...commonServices,
esSupertestWithoutAuth: apiIntegrationServices.esSupertestWithoutAuth,
supertest: kibanaApiIntegrationServices.supertest,
supertestWithoutAuth: apiIntegrationServices.supertestWithoutAuth,
retry: kibanaApiIntegrationServices.retry,
esArchiver: kibanaFunctionalServices.esArchiver,
kibanaServer: kibanaFunctionalServices.kibanaServer,
};

View file

@ -29,6 +29,7 @@ import type { Client } from '@elastic/elasticsearch';
import type { ToolingLog } from '@kbn/tooling-log';
import querystring from 'querystring';
import { KbnClient } from '@kbn/test';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { routeWithNamespace, waitFor } from '../../../../common/utils/security_solution';
export const getAssetCriticalityIndex = (namespace?: string) =>
@ -202,7 +203,7 @@ export const assetCriticalityRouteHelpersFactory = (
});
export const assetCriticalityRouteHelpersFactoryNoAuth = (
supertestWithoutAuth: SuperTest.Agent,
supertestWithoutAuth: SupertestWithoutAuthProviderType,
namespace?: string
) => ({
privilegesForUser: async ({ username, password }: { username: string; password: string }) =>

View file

@ -26,6 +26,7 @@ import {
import { MappingTypeMapping } from '@elastic/elasticsearch/lib/api/types';
import { removeLegacyTransforms } from '@kbn/security-solution-plugin/server/lib/entity_analytics/utils/transforms';
import { EntityRiskScoreRecord } from '@kbn/security-solution-plugin/common/api/entity_analytics/common';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import {
createRule,
waitForAlertsToBePresent,
@ -579,7 +580,7 @@ interface Credentials {
}
export const riskEngineRouteHelpersFactoryNoAuth = (
supertestWithoutAuth: SuperTest.Agent,
supertestWithoutAuth: SupertestWithoutAuthProviderType,
namespace?: string
) => ({
privilegesForUser: async ({ username, password }: Credentials) =>

View file

@ -11,5 +11,4 @@ import { services as apiIntegrationServices } from '../../api_integration/servic
export const services = {
...commonServices,
usageAPI: apiIntegrationServices.usageAPI,
supertestWithoutAuth: apiIntegrationServices.supertestWithoutAuth,
};

View file

@ -12,6 +12,7 @@ import {
SavedObjectsImportFailure,
SavedObjectsImportAmbiguousConflictError,
} from '@kbn/core/server';
import { SuperTest } from 'supertest';
import { getAggregatedSpaceData, getUrlPrefix } from '../lib/space_test_utils';
import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
import { getTestDataLoader, SPACE_1, SPACE_2 } from '../../../common/lib/test_data_loader';
@ -98,7 +99,9 @@ interface Aggs extends estypes.AggregationsMultiBucketAggregateBase {
}
export function copyToSpaceTestSuiteFactory(context: FtrProviderContext) {
const testDataLoader = getTestDataLoader(context);
const supertestWithoutAuth = context.getService('supertestWithoutAuth');
const supertestWithoutAuth = context.getService(
'supertestWithoutAuth'
) as unknown as SuperTest<any>;
const es = context.getService('es');
const collectSpaceContents = async () => {

View file

@ -9,6 +9,7 @@ import expect from '@kbn/expect';
import { SavedObject } from '@kbn/core/server';
import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common/constants';
import { CopyResponse } from '@kbn/spaces-plugin/server/lib/copy_to_spaces';
import { SuperTest } from 'supertest';
import { getUrlPrefix } from '../lib/space_test_utils';
import { DescribeFn, TestDefinitionAuthentication } from '../lib/types';
import type { FtrProviderContext } from '../ftr_provider_context';
@ -69,7 +70,9 @@ const getDestinationSpace = (originSpaceId?: string) => {
export function resolveCopyToSpaceConflictsSuite(context: FtrProviderContext) {
const testDataLoader = getTestDataLoader(context);
const supertestWithAuth = context.getService('supertest');
const supertestWithoutAuth = context.getService('supertestWithoutAuth');
const supertestWithoutAuth = context.getService(
'supertestWithoutAuth'
) as unknown as SuperTest<any>;
const getVisualizationAtSpace = async (spaceId: string): Promise<SavedObject<any>> => {
return supertestWithAuth

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { AUTHENTICATION } from '../../common/lib/authentication';
import { SPACES } from '../../common/lib/spaces';
import { createTestSuiteFactory } from '../../common/suites/create';
@ -22,7 +23,7 @@ export default function createSpacesOnlySuite({ getService }: FtrProviderContext
expectConflictResponse,
expectRbacForbiddenResponse,
expectSolutionSpecifiedResult,
} = createTestSuiteFactory(esArchiver, supertestWithoutAuth);
} = createTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('create', () => {
[

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { AUTHENTICATION } from '../../common/lib/authentication';
import { SPACES } from '../../common/lib/spaces';
import { deleteTestSuiteFactory } from '../../common/suites/delete';
@ -22,7 +23,7 @@ export default function deleteSpaceTestSuite({ getService }: FtrProviderContext)
expectEmptyResult,
expectNotFound,
expectReservedSpaceResult,
} = deleteTestSuiteFactory(es, esArchiver, supertestWithoutAuth);
} = deleteTestSuiteFactory(es, esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('delete', () => {
[

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { AUTHENTICATION } from '../../common/lib/authentication';
import { SPACES } from '../../common/lib/spaces';
import { getTestSuiteFactory } from '../../common/suites/get';
@ -21,7 +22,7 @@ export default function getSpaceTestSuite({ getService }: FtrProviderContext) {
createExpectNotFoundResult,
createExpectRbacForbidden,
nonExistantSpaceId,
} = getTestSuiteFactory(esArchiver, supertestWithoutAuth);
} = getTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('get', () => {
[

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { AUTHENTICATION } from '../../common/lib/authentication';
import { SPACES } from '../../common/lib/spaces';
import { getAllTestSuiteFactory } from '../../common/suites/get_all';
@ -16,7 +17,7 @@ export default function getAllSpacesTestSuite({ getService }: FtrProviderContext
const esArchiver = getService('esArchiver');
const { getAllTest, createExpectResults, createExpectAllPurposesResults, expectRbacForbidden } =
getAllTestSuiteFactory(esArchiver, supertestWithoutAuth);
getAllTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
// these are used to determine expected results for tests where the `include_authorized_purposes` option is enabled
const authorizedAll = {

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { AUTHENTICATION } from '../../common/lib/authentication';
import { SPACES } from '../../common/lib/spaces';
import { updateTestSuiteFactory } from '../../common/suites/update';
@ -21,7 +22,7 @@ export default function updateSpaceTestSuite({ getService }: FtrProviderContext)
expectAlreadyExistsResult,
expectDefaultSpaceResult,
expectRbacForbidden,
} = updateTestSuiteFactory(esArchiver, supertestWithoutAuth);
} = updateTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('update', () => {
[

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { SPACES } from '../../common/lib/spaces';
import { createTestSuiteFactory } from '../../common/suites/create';
import { FtrProviderContext } from '../../common/ftr_provider_context';
@ -20,7 +21,7 @@ export default function createSpacesOnlySuite({ getService }: FtrProviderContext
expectConflictResponse,
expectReservedSpecifiedResult,
expectSolutionSpecifiedResult,
} = createTestSuiteFactory(esArchiver, supertestWithoutAuth);
} = createTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('create', () => {
[

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { SPACES } from '../../common/lib/spaces';
import { deleteTestSuiteFactory } from '../../common/suites/delete';
import { FtrProviderContext } from '../../common/ftr_provider_context';
@ -16,7 +17,7 @@ export default function deleteSpaceTestSuite({ getService }: FtrProviderContext)
const es = getService('es');
const { deleteTest, expectEmptyResult, expectReservedSpaceResult, expectNotFound } =
deleteTestSuiteFactory(es, esArchiver, supertestWithoutAuth);
deleteTestSuiteFactory(es, esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('delete', () => {
[

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { SPACES } from '../../common/lib/spaces';
import { getTestSuiteFactory } from '../../common/suites/get';
import { FtrProviderContext } from '../../common/ftr_provider_context';
@ -15,7 +16,7 @@ export default function getSpaceTestSuite({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const { getTest, createExpectResults, createExpectNotFoundResult, nonExistantSpaceId } =
getTestSuiteFactory(esArchiver, supertestWithoutAuth);
getTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('get', () => {
// valid spaces

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { SPACES } from '../../common/lib/spaces';
import { getAllTestSuiteFactory } from '../../common/suites/get_all';
import { FtrProviderContext } from '../../common/ftr_provider_context';
@ -16,7 +17,7 @@ export default function getAllSpacesTestSuite({ getService }: FtrProviderContext
const { getAllTest, createExpectResults } = getAllTestSuiteFactory(
esArchiver,
supertestWithoutAuth
supertestWithoutAuth as unknown as SuperTest<any>
);
describe('get all', () => {

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { SuperTest } from 'supertest';
import { SPACES } from '../../common/lib/spaces';
import { updateTestSuiteFactory } from '../../common/suites/update';
import { FtrProviderContext } from '../../common/ftr_provider_context';
@ -15,7 +16,7 @@ export default function updateSpaceTestSuite({ getService }: FtrProviderContext)
const esArchiver = getService('esArchiver');
const { updateTest, expectAlreadyExistsResult, expectDefaultSpaceResult, expectNotFound } =
updateTestSuiteFactory(esArchiver, supertestWithoutAuth);
updateTestSuiteFactory(esArchiver, supertestWithoutAuth as unknown as SuperTest<any>);
describe('update', () => {
[

View file

@ -11,7 +11,7 @@ import type { Agent as SuperTestAgent } from 'supertest';
import {
InternalRequestHeader,
RoleCredentials,
SupertestWithoutAuthType,
SupertestWithoutAuthProviderType,
} from '../../../../../shared/services';
interface CreateEsQueryRuleParams {
@ -40,7 +40,7 @@ export async function createIndexConnector({
name,
indexName,
}: {
supertestWithoutAuth: SupertestWithoutAuthType;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
roleAuthc: RoleCredentials;
internalReqHeader: InternalRequestHeader;
name: string;
@ -68,7 +68,7 @@ export async function createSlackConnector({
internalReqHeader,
name,
}: {
supertestWithoutAuth: SupertestWithoutAuthType;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
roleAuthc: RoleCredentials;
internalReqHeader: InternalRequestHeader;
name: string;
@ -103,7 +103,7 @@ export async function createEsQueryRule({
notifyWhen,
enabled = true,
}: {
supertestWithoutAuth: SupertestWithoutAuthType;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
roleAuthc: RoleCredentials;
internalReqHeader: InternalRequestHeader;
ruleTypeId: string;
@ -360,7 +360,7 @@ export async function runRule({
internalReqHeader,
ruleId,
}: {
supertestWithoutAuth: SupertestWithoutAuthType;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
roleAuthc: RoleCredentials;
internalReqHeader: InternalRequestHeader;
ruleId: string;

View file

@ -12,7 +12,7 @@ import type {
SearchResponse,
} from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import { runRule } from './alerting_api_helper';
import type { SupertestWithoutAuthType } from '../../../../../shared/services';
import type { SupertestWithoutAuthProviderType } from '../../../../../shared/services';
import { RoleCredentials } from '../../../../../shared/services';
import { InternalRequestHeader } from '../../../../../shared/services';
@ -376,7 +376,7 @@ export async function waitForNumRuleRuns({
esClient,
testStart,
}: {
supertestWithoutAuth: SupertestWithoutAuthType;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
roleAuthc: RoleCredentials;
internalReqHeader: InternalRequestHeader;
numOfRuns: number;

View file

@ -25,14 +25,12 @@ export default function ({ getService }: FtrProviderContext) {
describe('system indices behavior', () => {
it('does not forward x-elastic-product-origin', async () => {
// If we pass the header and we still get the warning back, we assume that the header was not forwarded.
return await supertestWithoutAuth
const response = await supertestWithoutAuth
.post('/api/console/proxy?method=GET&path=/.kibana/_settings')
.set('kbn-xsrf', 'true')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.then((response) => {
expect(response.header).to.have.property('warning');
});
.set(roleAuthc.apiKeyHeader);
expect(response.header).to.have.property('warning');
});
});
});

View file

@ -17,26 +17,22 @@ export default function ({ getService }: FtrProviderContext) {
const compressionSuite = (url: string) => {
it(`uses compression when there isn't a referer`, async () => {
await supertestWithoutAuth
const response = await supertestWithoutAuth
.get(url)
.set('accept-encoding', 'gzip')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.then((response) => {
expect(response.header).to.have.property('content-encoding', 'gzip');
});
.set(roleAuthc.apiKeyHeader);
expect(response.header).to.have.property('content-encoding', 'gzip');
});
it(`uses compression when there is a whitelisted referer`, async () => {
await supertestWithoutAuth
const response = await supertestWithoutAuth
.get(url)
.set('accept-encoding', 'gzip')
.set(svlCommonApi.getInternalRequestHeader())
.set('referer', 'https://some-host.com')
.set(roleAuthc.apiKeyHeader)
.then((response) => {
expect(response.header).to.have.property('content-encoding', 'gzip');
});
.set(roleAuthc.apiKeyHeader);
expect(response.header).to.have.property('content-encoding', 'gzip');
});
};

View file

@ -23,33 +23,26 @@ export default function ({ getService }: FtrProviderContext) {
await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc);
});
it(`returns the translations with the correct headers`, async () => {
await supertestWithoutAuth
const response = await supertestWithoutAuth
.get('/translations/en.json')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.then((response) => {
expect(response.body.locale).to.eql('en');
.set(roleAuthc.apiKeyHeader);
expect(response.body.locale).to.eql('en');
expect(response.header).to.have.property(
'content-type',
'application/json; charset=utf-8'
);
expect(response.header).to.have.property(
'cache-control',
'public, max-age=31536000, immutable'
);
expect(response.header).not.to.have.property('etag');
});
expect(response.header).to.have.property('content-type', 'application/json; charset=utf-8');
expect(response.header).to.have.property(
'cache-control',
'public, max-age=31536000, immutable'
);
expect(response.header).not.to.have.property('etag');
});
it(`returns a 404 when not using the correct locale`, async () => {
await supertestWithoutAuth
const response = await supertestWithoutAuth
.get('/translations/foo.json')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.then((response) => {
expect(response.status).to.eql(404);
});
.set(roleAuthc.apiKeyHeader);
expect(response.status).to.eql(404);
});
});
}

View file

@ -31,60 +31,59 @@ export default function ({ getService }: FtrProviderContext) {
await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc);
});
it('flags fields with mismatched types as conflicting', () =>
supertestWithoutAuth
it('flags fields with mismatched types as conflicting', async () => {
const resp = await supertestWithoutAuth
.get(FIELDS_FOR_WILDCARD_PATH)
.set(ELASTIC_HTTP_VERSION_HEADER, INITIAL_REST_VERSION_INTERNAL)
.set(internalReqHeader)
.set(roleAuthc.apiKeyHeader)
.query({ pattern: 'logs-2017.01.*' })
.expect(200)
.then((resp) => {
expect(resp.body).to.eql({
fields: [
{
name: '@timestamp',
type: 'date',
esTypes: ['date'],
aggregatable: true,
searchable: true,
readFromDocValues: true,
metadata_field: false,
},
{
name: 'number_conflict',
type: 'number',
esTypes: ['float', 'integer'],
aggregatable: true,
searchable: true,
readFromDocValues: true,
metadata_field: false,
},
{
name: 'string_conflict',
type: 'string',
esTypes: ['keyword', 'text'],
aggregatable: true,
searchable: true,
readFromDocValues: true,
metadata_field: false,
},
{
name: 'success',
type: 'conflict',
esTypes: ['keyword', 'boolean'],
aggregatable: true,
searchable: true,
readFromDocValues: false,
conflictDescriptions: {
boolean: ['logs-2017.01.02'],
keyword: ['logs-2017.01.01'],
},
metadata_field: false,
},
],
indices: ['logs-2017.01.01', 'logs-2017.01.02'],
});
}));
.expect(200);
expect(resp.body).to.eql({
fields: [
{
name: '@timestamp',
type: 'date',
esTypes: ['date'],
aggregatable: true,
searchable: true,
readFromDocValues: true,
metadata_field: false,
},
{
name: 'number_conflict',
type: 'number',
esTypes: ['float', 'integer'],
aggregatable: true,
searchable: true,
readFromDocValues: true,
metadata_field: false,
},
{
name: 'string_conflict',
type: 'string',
esTypes: ['keyword', 'text'],
aggregatable: true,
searchable: true,
readFromDocValues: true,
metadata_field: false,
},
{
name: 'success',
type: 'conflict',
esTypes: ['keyword', 'boolean'],
aggregatable: true,
searchable: true,
readFromDocValues: false,
conflictDescriptions: {
boolean: ['logs-2017.01.02'],
keyword: ['logs-2017.01.01'],
},
metadata_field: false,
},
],
indices: ['logs-2017.01.01', 'logs-2017.01.02'],
});
});
});
}

View file

@ -81,40 +81,32 @@ export default function ({ getService }: FtrProviderContext) {
});
});
it('should report success when opt *in* is incremented successfully', () => {
return (
supertestWithoutAuth
.post('/internal/kql_opt_in_stats')
.set('content-type', 'application/json')
.set(ELASTIC_HTTP_VERSION_HEADER, KQL_TELEMETRY_ROUTE_LATEST_VERSION)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.send({ opt_in: true })
.expect('Content-Type', /json/)
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then(({ body }) => {
expect(body.success).to.be(true);
})
);
it('should report success when opt *in* is incremented successfully', async () => {
const { body } = await supertestWithoutAuth
.post('/internal/kql_opt_in_stats')
.set('content-type', 'application/json')
.set(ELASTIC_HTTP_VERSION_HEADER, KQL_TELEMETRY_ROUTE_LATEST_VERSION)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.send({ opt_in: true })
.expect('Content-Type', /json/)
.set(roleAuthc.apiKeyHeader)
.expect(200);
expect(body.success).to.be(true);
});
it('should report success when opt *out* is incremented successfully', () => {
return (
supertestWithoutAuth
.post('/internal/kql_opt_in_stats')
.set('content-type', 'application/json')
.set(ELASTIC_HTTP_VERSION_HEADER, KQL_TELEMETRY_ROUTE_LATEST_VERSION)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.send({ opt_in: false })
.expect('Content-Type', /json/)
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then(({ body }) => {
expect(body.success).to.be(true);
})
);
it('should report success when opt *out* is incremented successfully', async () => {
const { body } = await supertestWithoutAuth
.post('/internal/kql_opt_in_stats')
.set('content-type', 'application/json')
.set(ELASTIC_HTTP_VERSION_HEADER, KQL_TELEMETRY_ROUTE_LATEST_VERSION)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.send({ opt_in: false })
.expect('Content-Type', /json/)
.set(roleAuthc.apiKeyHeader)
.expect(200);
expect(body.success).to.be(true);
});
it('should only accept literal boolean values for the opt_in POST body param', function () {

View file

@ -59,41 +59,38 @@ export default function ({ getService }: FtrProviderContext) {
});
}
it('should return 200 for an existing object', async () =>
await supertestWithoutAuth
it('should return 200 for an existing object', async () => {
const { body } = await supertestWithoutAuth
.post(endpoint)
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.send([validObject])
.expect(200)
.then(({ body }) => {
expect(body).to.have.length(1);
expectSuccess(0, body);
}));
.expect(200);
expect(body).to.have.length(1);
expectSuccess(0, body);
});
it('should return error for invalid object type', async () =>
await supertestWithoutAuth
it('should return error for invalid object type', async () => {
const { body } = await supertestWithoutAuth
.post(endpoint)
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.send([invalidObject])
.expect(200)
.then(({ body }) => {
expect(body).to.have.length(1);
expectBadRequest(0, body);
}));
.expect(200);
expect(body).to.have.length(1);
expectBadRequest(0, body);
});
it('should return mix of successes and errors', async () =>
await supertestWithoutAuth
it('should return mix of successes and errors', async () => {
const { body } = await supertestWithoutAuth
.post(endpoint)
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.send([validObject, invalidObject])
.expect(200)
.then(({ body }) => {
expect(body).to.have.length(2);
expectSuccess(0, body);
expectBadRequest(1, body);
}));
.expect(200);
expect(body).to.have.length(2);
expectSuccess(0, body);
expectBadRequest(1, body);
});
});
}

View file

@ -61,42 +61,39 @@ export default function ({ getService }: FtrProviderContext) {
});
}
it('should return 200 for object that exists and inject metadata', async () =>
await supertestWithoutAuth
it('should return 200 for object that exists and inject metadata', async () => {
const { body } = await supertestWithoutAuth
.post(URL)
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.send([validObject])
.expect(200)
.then(({ body }) => {
expect(body).to.have.length(1);
expectSuccess(0, body);
}));
.expect(200);
expect(body).to.have.length(1);
expectSuccess(0, body);
});
it('should return error for invalid object type', async () =>
await supertestWithoutAuth
it('should return error for invalid object type', async () => {
const { body } = await supertestWithoutAuth
.post(URL)
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.send([invalidObject])
.expect(200)
.then(({ body }) => {
expect(body).to.have.length(1);
expectBadRequest(0, body);
}));
.expect(200);
expect(body).to.have.length(1);
expectBadRequest(0, body);
});
it('should return mix of successes and errors', async () =>
await supertestWithoutAuth
it('should return mix of successes and errors', async () => {
const { body } = await supertestWithoutAuth
.post(URL)
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.send([validObject, invalidObject])
.expect(200)
.then(({ body }) => {
expect(body).to.have.length(2);
expectSuccess(0, body);
expectBadRequest(1, body);
}));
.expect(200);
expect(body).to.have.length(2);
expectSuccess(0, body);
expectBadRequest(1, body);
});
});
});
}

View file

@ -132,7 +132,7 @@ export default function ({ getService }: FtrProviderContext) {
});
it('search for multiple references with OR operator', async () => {
await supertestWithoutAuth
const response = await supertestWithoutAuth
.get('/api/kibana/management/saved_objects/_find')
.query({
type: 'visualization',
@ -143,14 +143,10 @@ export default function ({ getService }: FtrProviderContext) {
hasReferenceOperator: 'OR',
})
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.then((response) => {
expect(response.status).to.eql(200);
expect(response.body.saved_objects.length).not.to.be(null);
expect(response.body.saved_objects.map((obj: any) => obj.id).length).to.be.greaterThan(
0
);
});
.set(roleAuthc.apiKeyHeader);
expect(response.status).to.eql(200);
expect(response.body.saved_objects.length).not.to.be(null);
expect(response.body.saved_objects.map((obj: any) => obj.id).length).to.be.greaterThan(0);
});
it('search for multiple references with AND operator', async () => {
@ -221,88 +217,84 @@ export default function ({ getService }: FtrProviderContext) {
await kibanaServer.savedObjects.cleanStandardList();
});
it('should inject meta attributes for searches', async () =>
await supertestWithoutAuth
it('should inject meta attributes for searches', async () => {
const response = await supertestWithoutAuth
.get('/api/kibana/management/saved_objects/_find?type=search')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then((response) => {
expect(response.body.saved_objects).to.have.length(1);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'discoverApp',
title: 'OneRecord',
hiddenType: false,
inAppUrl: {
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
namespaceType: 'multiple-isolated',
});
}));
.expect(200);
expect(response.body.saved_objects).to.have.length(1);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'discoverApp',
title: 'OneRecord',
hiddenType: false,
inAppUrl: {
path: '/app/discover#/view/960372e0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'discover.show',
},
namespaceType: 'multiple-isolated',
});
});
it('should inject meta attributes for dashboards', async () =>
await supertestWithoutAuth
it('should inject meta attributes for dashboards', async () => {
const response = await supertestWithoutAuth
.get('/api/kibana/management/saved_objects/_find?type=dashboard')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then((response) => {
expect(response.body.saved_objects).to.have.length(1);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'dashboardApp',
title: 'Dashboard',
hiddenType: false,
inAppUrl: {
path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'dashboard.show',
},
namespaceType: 'multiple-isolated',
});
}));
.expect(200);
expect(response.body.saved_objects).to.have.length(1);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'dashboardApp',
title: 'Dashboard',
hiddenType: false,
inAppUrl: {
path: '/app/dashboards#/view/b70c7ae0-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'dashboard.show',
},
namespaceType: 'multiple-isolated',
});
});
it('should inject meta attributes for visualizations', async () =>
await supertestWithoutAuth
it('should inject meta attributes for visualizations', async () => {
const response = await supertestWithoutAuth
.get('/api/kibana/management/saved_objects/_find?type=visualization')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then((response) => {
expect(response.body.saved_objects).to.have.length(2);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'visualizeApp',
title: 'VisualizationFromSavedSearch',
namespaceType: 'multiple-isolated',
hiddenType: false,
});
expect(response.body.saved_objects[1].meta).to.eql({
icon: 'visualizeApp',
title: 'Visualization',
namespaceType: 'multiple-isolated',
hiddenType: false,
});
}));
.expect(200);
expect(response.body.saved_objects).to.have.length(2);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'visualizeApp',
title: 'VisualizationFromSavedSearch',
namespaceType: 'multiple-isolated',
hiddenType: false,
});
expect(response.body.saved_objects[1].meta).to.eql({
icon: 'visualizeApp',
title: 'Visualization',
namespaceType: 'multiple-isolated',
hiddenType: false,
});
});
it('should inject meta attributes for index patterns', async () =>
await supertestWithoutAuth
it('should inject meta attributes for index patterns', async () => {
const response = await supertestWithoutAuth
.get('/api/kibana/management/saved_objects/_find?type=index-pattern')
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then((response) => {
expect(response.body.saved_objects).to.have.length(1);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'indexPatternApp',
title: 'saved_objects*',
hiddenType: false,
editUrl: '/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'management.kibana.indexPatterns',
},
namespaceType: 'multiple',
});
}));
.expect(200);
expect(response.body.saved_objects).to.have.length(1);
expect(response.body.saved_objects[0].meta).to.eql({
icon: 'indexPatternApp',
title: 'saved_objects*',
hiddenType: false,
editUrl: '/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357',
inAppUrl: {
path: '/app/management/kibana/dataViews/dataView/8963ca30-3224-11e8-a572-ffca06da1357',
uiCapabilitiesPath: 'management.kibana.indexPatterns',
},
namespaceType: 'multiple',
});
});
});
});
}

View file

@ -5,7 +5,9 @@
* 2.0.
*/
export default function ({ loadTestFile }) {
import { FtrProviderContext } from '../../../ftr_provider_context';
export default function ({ loadTestFile }: FtrProviderContext) {
// TODO: The `scripts` folder was renamed to `scripts_tests` because the folder
// name `scripts` triggers the `eslint@kbn/imports/no_boundary_crossing` rule
describe('scripts', function () {

View file

@ -9,11 +9,13 @@ import expect from '@kbn/expect';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { SCRIPT_LANGUAGES_ROUTE_LATEST_VERSION } from '@kbn/data-plugin/common/constants';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { RoleCredentials } from '../../../../shared/services';
export default function ({ getService }) {
export default function ({ getService }: FtrProviderContext) {
const svlCommonApi = getService('svlCommonApi');
const svlUserManager = getService('svlUserManager');
let roleAuthc;
let roleAuthc: RoleCredentials;
const supertestWithoutAuth = getService('supertestWithoutAuth');
describe('Script Languages API', function getLanguages() {
@ -23,31 +25,26 @@ export default function ({ getService }) {
after(async () => {
await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc);
});
it('should return 200 with an array of languages', () =>
supertestWithoutAuth
it('should return 200 with an array of languages', async () => {
const response = await supertestWithoutAuth
.get('/internal/scripts/languages')
.set(ELASTIC_HTTP_VERSION_HEADER, SCRIPT_LANGUAGES_ROUTE_LATEST_VERSION)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then((response) => {
expect(response.body).to.be.an('array');
}));
.expect(200);
expect(response.body).to.be.an('array');
});
// eslint-disable-next-line jest/no-disabled-tests
it.skip('should only return langs enabled for inline scripting', () =>
supertestWithoutAuth
it.skip('should only return langs enabled for inline scripting', async () => {
const response = await supertestWithoutAuth
.get('/internal/scripts/languages')
.set(ELASTIC_HTTP_VERSION_HEADER, SCRIPT_LANGUAGES_ROUTE_LATEST_VERSION)
// TODO: API requests in Serverless require internal request headers
.set(svlCommonApi.getInternalRequestHeader())
.set(roleAuthc.apiKeyHeader)
.expect(200)
.then((response) => {
expect(response.body).to.contain('expression');
expect(response.body).to.contain('painless');
expect(response.body).to.not.contain('groovy');
}));
.expect(200);
expect(response.body).to.contain('expression');
expect(response.body).to.contain('painless');
expect(response.body).to.not.contain('groovy');
});
});
}

View file

@ -11,10 +11,10 @@
import expect from '@kbn/expect';
import { GenericFtrService } from '@kbn/test';
import request from 'superagent';
import type SuperTest from 'supertest';
import type { IEsSearchResponse } from '@kbn/search-types';
import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common';
import { BFETCH_ROUTE_VERSION_LATEST } from '@kbn/bfetch-plugin/common';
import { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
import { FtrProviderContext } from '../../functional/ftr_provider_context';
const parseBfetchResponse = (resp: request.Response): Array<Record<string, any>> => {
@ -25,7 +25,7 @@ const parseBfetchResponse = (resp: request.Response): Array<Record<string, any>>
};
interface SendOptions {
supertestWithoutAuth: SuperTest.Agent;
supertestWithoutAuth: SupertestWithoutAuthProviderType;
apiKeyHeader: { Authorization: string };
referer?: string;
kibanaVersion?: string;

View file

@ -5,7 +5,8 @@
* 2.0.
*/
import { SupertestProvider, SupertestWithoutAuthProvider } from './supertest';
import { commonFunctionalServices } from '@kbn/ftr-common-functional-services';
import { SupertestProvider } from './supertest';
import { SvlCommonApiServiceProvider } from './svl_common_api';
import { SvlReportingServiceProvider } from './svl_reporting';
import { SvlUserManagerProvider } from './svl_user_manager';
@ -13,7 +14,9 @@ import { DataViewApiProvider } from './data_view_api';
export type { RoleCredentials } from './svl_user_manager';
export type { InternalRequestHeader } from './svl_common_api';
export type { SupertestWithoutAuthType } from './supertest';
export type { SupertestWithoutAuthProviderType } from '@kbn/ftr-common-functional-services';
const SupertestWithoutAuthProvider = commonFunctionalServices.supertestWithoutAuth;
export const services = {
supertest: SupertestProvider,

View file

@ -7,9 +7,7 @@
import { format as formatUrl } from 'url';
import supertest from 'supertest';
import { ProvidedType } from '@kbn/test';
import { FtrProviderContext } from '../../functional/ftr_provider_context';
export type SupertestWithoutAuthType = ProvidedType<typeof SupertestWithoutAuthProvider>;
/**
* Returns supertest.SuperTest<supertest.Test> instance that will not persist cookie between API requests.
*/
@ -19,20 +17,3 @@ export function SupertestProvider({ getService }: FtrProviderContext) {
return supertest(kbnUrl);
}
/**
* Returns supertest.SuperTest<supertest.Test> instance that will not persist cookie between API requests.
* If you need to pass certificate, do the following:
* await supertestWithoutAuth
* .get('/abc')
* .ca(CA_CERT)
*/
export function SupertestWithoutAuthProvider({ getService }: FtrProviderContext) {
const config = getService('config');
const kbnUrl = formatUrl({
...config.get('servers.kibana'),
auth: false,
});
return supertest(kbnUrl);
}