[packages] add kbn-scalability-simulation-generator package (#132631)

* add kbn-scalability-simulation-generator package

* update codeowners

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Dzmitry Lemechko 2022-06-14 10:08:26 +02:00 committed by GitHub
parent 40acfe365c
commit 6f5b23b221
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 757 additions and 0 deletions

4
.github/CODEOWNERS vendored
View file

@ -255,6 +255,10 @@
#CC# /packages/kbn-expect/ @elastic/kibana-operations
/.buildkite/ @elastic/kibana-operations
# Scalability testing
/packages/kbn-performance-testing-dataset-extractor/ @elastic/kibana-scalability-testing
/packages/kbn-scalability-simulation-generator/ @elastic/kibana-scalability-testing
# Quality Assurance
/src/dev/code_coverage @elastic/kibana-qa
/vars/*Coverage.groovy @elastic/kibana-qa

View file

@ -536,6 +536,7 @@
"@kbn/plugin-generator": "link:bazel-bin/packages/kbn-plugin-generator",
"@kbn/plugin-helpers": "link:bazel-bin/packages/kbn-plugin-helpers",
"@kbn/pm": "link:packages/kbn-pm",
"@kbn/scalability-simulation-generator": "link:bazel-bin/packages/kbn-scalability-simulation-generator",
"@kbn/sort-package-json": "link:bazel-bin/packages/kbn-sort-package-json",
"@kbn/spec-to-console": "link:bazel-bin/packages/kbn-spec-to-console",
"@kbn/stdio-dev-helpers": "link:bazel-bin/packages/kbn-stdio-dev-helpers",
@ -715,6 +716,7 @@
"@types/kbn__plugin-helpers": "link:bazel-bin/packages/kbn-plugin-helpers/npm_module_types",
"@types/kbn__react-field": "link:bazel-bin/packages/kbn-react-field/npm_module_types",
"@types/kbn__rule-data-utils": "link:bazel-bin/packages/kbn-rule-data-utils/npm_module_types",
"@types/kbn__scalability-simulation-generator": "link:bazel-bin/packages/kbn-scalability-simulation-generator/npm_module_types",
"@types/kbn__securitysolution-autocomplete": "link:bazel-bin/packages/kbn-securitysolution-autocomplete/npm_module_types",
"@types/kbn__securitysolution-es-utils": "link:bazel-bin/packages/kbn-securitysolution-es-utils/npm_module_types",
"@types/kbn__securitysolution-hook-utils": "link:bazel-bin/packages/kbn-securitysolution-hook-utils/npm_module_types",

View file

@ -93,6 +93,7 @@ filegroup(
"//packages/kbn-plugin-helpers:build",
"//packages/kbn-react-field:build",
"//packages/kbn-rule-data-utils:build",
"//packages/kbn-scalability-simulation-generator:build",
"//packages/kbn-securitysolution-autocomplete:build",
"//packages/kbn-securitysolution-es-utils:build",
"//packages/kbn-securitysolution-hook-utils:build",
@ -223,6 +224,7 @@ filegroup(
"//packages/kbn-plugin-helpers:build_types",
"//packages/kbn-react-field:build_types",
"//packages/kbn-rule-data-utils:build_types",
"//packages/kbn-scalability-simulation-generator:build_types",
"//packages/kbn-securitysolution-autocomplete:build_types",
"//packages/kbn-securitysolution-es-utils:build_types",
"//packages/kbn-securitysolution-hook-utils:build_types",

View file

@ -0,0 +1,120 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
PKG_DIRNAME = "kbn-scalability-simulation-generator"
PKG_REQUIRE_NAME = "@kbn/scalability-simulation-generator"
SOURCE_FILES = glob(
[
"src/**/*.ts",
],
exclude = [
"**/*.test.*",
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
]
# In this array place runtime dependencies, including other packages and NPM packages
# which must be available for this code to run.
#
# To reference other packages use:
# "//repo/relative/path/to/package"
# eg. "//packages/kbn-utils"
#
# To reference a NPM package use:
# "@npm//name-of-package"
# eg. "@npm//lodash"
RUNTIME_DEPS = [
"//packages/kbn-dev-cli-errors",
"//packages/kbn-dev-cli-runner",
"//packages/kbn-tooling-log",
]
# In this array place dependencies necessary to build the types, which will include the
# :npm_module_types target of other packages and packages from NPM, including @types/*
# packages.
#
# To reference the types for another package use:
# "//repo/relative/path/to/package:npm_module_types"
# eg. "//packages/kbn-utils:npm_module_types"
#
# References to NPM packages work the same as RUNTIME_DEPS
TYPES_DEPS = [
"//packages/kbn-dev-cli-errors:npm_module_types",
"//packages/kbn-dev-cli-runner:npm_module_types",
"//packages/kbn-tooling-log:npm_module_types",
"@npm//@types/node",
"@npm//@types/jest",
]
jsts_transpiler(
name = "target_node",
srcs = SRCS,
build_pkg_name = package_name(),
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
"//:tsconfig.bazel.json",
],
)
ts_project(
name = "tsc_types",
args = ['--pretty'],
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
emit_declaration_only = True,
out_dir = "target_types",
root_dir = "src",
tsconfig = ":tsconfig",
)
js_library(
name = PKG_DIRNAME,
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + [":target_node"],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [":" + PKG_DIRNAME],
)
filegroup(
name = "build",
srcs = [":npm_module"],
visibility = ["//visibility:public"],
)
pkg_npm_types(
name = "npm_module_types",
srcs = SRCS,
deps = [":tsc_types"],
package_name = PKG_REQUIRE_NAME,
tsconfig = ":tsconfig",
visibility = ["//visibility:public"],
)
filegroup(
name = "build_types",
srcs = [":npm_module_types"],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,31 @@
# @kbn/scalability-simulation-generator
A library to generate scalability benchmarking simulation file, that can be run by Gatling performance testing tool.
## Usage
There are 2 ways to run auto-generated simulation files, using:
- Gatling bundle
- kibana-load-testing project
If you plan to use Gatling-bundle, generate simulation using this command:
```
node scripts/generate_scalability_simulations.js \
--dir "<path to @kbn/performance-testing-dataset-extractor output>" \
--baseUrl "<Kibana server baseURL>"
```
If you plan to use [kibana-load-testing](https://github.com/elastic/kibana-load-testing), use the following command:
```
node scripts/generate_scalability_simulations.js \
--dir "<path to @kbn/performance-testing-dataset-extractor output>" \
--baseUrl "<Kibana server baseURL>" \
--packageName "org.kibanaLoadTest"
```
To run the generated simulation:
- Move file to `src/test/scala/org/kibanaLoadTest`
- Compile source code `mvn clean compile`
- Run simulation `mvn gatling:test -Dgatling.simulationClass=org.kibanaLoadTest.<simulationFileName>`

View file

@ -0,0 +1,13 @@
/*
* 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.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-scalability-simulation-generator'],
};

View file

@ -0,0 +1,11 @@
{
"name": "@kbn/scalability-simulation-generator",
"description": "A library to generate scalability benchmarking simulation files from APM traces.",
"private": true,
"version": "1.0.0",
"main": "./target_node/index.js",
"license": "SSPL-1.0 OR Elastic License 2.0",
"kibana": {
"devOnly": true
}
}

View file

@ -0,0 +1,231 @@
/*
* 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 { Stage } from './types/journey';
import { Header, Request, Simulation } from './types/simulation';
const AUTH_PATH = '/internal/security/login';
const B_SEARCH_PATH = '/internal/bsearch';
const getHeaders = (headers: readonly Header[]) =>
headers
.map(
(header) =>
`"${header.name}" -> ${JSON.stringify(
header.name !== 'Cookie' ? header.value : '${Cookie}'
)}`
)
.join(',')
.replace(/^/, 'Map(') + ')';
const getPayload = (body: string) => JSON.stringify(body).replace(/"/g, '\\"');
const getDuration = (duration: string) => {
const value = duration.replace(/\D+/, '');
return duration.endsWith('m') ? `${value} * 60` : value;
};
/**
* Builds Gatling simulation content from common template
* @param packageName scala package name, where simulation file will be placed
* @param simulationName scala class name
* @param protocol Gatling protocol string
* @param scenario Gatling scenario string
* @param setup Gatling simulation injection setup string
* @returns Gatling simulation content as string
*/
const buildSimulation = (
packageName: string,
simulationName: string,
protocol: string,
scenario: string,
setup: string
) =>
`package ${packageName}
import scala.concurrent.duration._
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
class ${simulationName} extends Simulation {
${protocol}
${scenario}
${setup}
}`;
const buildAuthenticationExec = (path: string, headers: string, payload: string) =>
` .exec(
http("${path}")
.post("${path}")
.body(StringBody("${payload}"))
.asJson
.headers(${headers})
.check(headerRegex("set-cookie", ".+?(?=;)").saveAs("Cookie"))
)`;
const buildBSearchExec = (path: string, headers: string, payload: string) =>
` .exec(
http("${path}")
.post("${path}")
.headers(${headers})
.body(StringBody(${payload}))
.asJson
.check(status.is(200).saveAs("status"))
.check(jsonPath("$.result.id").find.saveAs("requestId"))
.check(jsonPath("$.result.isPartial").find.saveAs("isPartial"))
)
.exitHereIfFailed
// First response might be “partial”. Then we continue to fetch for the results
// using the request id returned from the first response
.asLongAs(session =>
session("status").as[Int] == 200
&& session("isPartial").as[Boolean]
) {
exec(
http("${path}")
.post("${path}")
.headers(${headers})
.body(StringBody(${payload}))
.asJson
.check(status.is(200).saveAs("status"))
.check(jsonPath("$.result.isPartial").saveAs("isPartial"))
)
.exitHereIfFailed
.pause(1)
}`;
const buildCommonHttpExec = (path: string, method: string, headers: string) =>
` .exec(
http("${path}")
.${method}("${path}")
.headers(${headers})
)`;
const buildCommonHttpBodyExec = (path: string, method: string, headers: string, payload: string) =>
` .exec(
http("${path}")
.${method}("${path}")
.body(StringBody("${payload}"))
.asJson
.headers(${headers})
)`;
const addPause = (delay: number) => ` .pause(${delay}.milliseconds)`;
const buildProtocol = (baseUrl: string) =>
` val httpProtocol = http
.baseUrl("${baseUrl}")
.inferHtmlResources()
.acceptHeader("*/*")
.acceptEncodingHeader("gzip, deflate")
.acceptLanguageHeader("en-US,en;q=0.9,ru;q=0.8,de;q=0.7")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36")`;
const buildScenarioDefinition = (phase: string, scenarioName: string) =>
` val ${phase} = scenario("${scenarioName} ${phase}")
.exec(steps)`;
/**
* Builds Gatling simulation setUp section, that defines injection for warmup and test scenarios
* @param warmupStages
* @param testStages
* @param maxDuration
* @returns Gatling simulation setUp as a string
*/
const buildSetup = (warmupStages: string, testStages: string, maxDuration: string) =>
` setUp(
warmup
.inject(${warmupStages})
.protocols(httpProtocol)
.andThen(
test
.inject(${testStages})
.protocols(httpProtocol)
)
).maxDuration(${maxDuration})`;
const buildExecStep = (request: Request) => {
const headers = getHeaders(request.headers);
const method = request.method.toLowerCase();
if (!request.body) {
return buildCommonHttpExec(request.path, method, headers);
} else if (request.path.includes(AUTH_PATH)) {
return buildAuthenticationExec(request.path, headers, getPayload(request.body));
} else if (request.path.includes(B_SEARCH_PATH)) {
return buildBSearchExec(request.path, headers, getPayload(request.body));
} else {
return buildCommonHttpBodyExec(request.path, method, headers, getPayload(request.body));
}
};
/**
* Builds Gatling scenario body
* @param scenarioName scenario name
* @param requests Kibana API requests
* @returns Gatling scenario as a string
*/
const buildScenario = (scenarioName: string, requests: readonly Request[]): string => {
const warmupScn = buildScenarioDefinition('warmup', scenarioName);
const testScn = buildScenarioDefinition('test', scenarioName);
// convert requests into array of Gatling exec http calls
const execs = requests.map((request, index, reqArray) => {
// construct Gatling exec http calls
const exec = buildExecStep(request);
// add delay between requests
if (index < reqArray.length - 1) {
const delay = reqArray[index + 1].timestamp - request.timestamp;
if (delay > 0) {
return exec + '\n' + addPause(delay);
}
}
return exec;
});
const steps = execs.join('\n');
const finalSteps = steps.slice(0, steps.indexOf('.')) + steps.slice(steps.indexOf('.') + 1);
return ' val steps =\n' + finalSteps + '\n\n' + warmupScn + '\n' + testScn + '\n';
};
/**
* Builds injection setup for scenario
* @param stages Array of actions to be executed with users count and duration
* @returns scenario injection as a string
*/
const buildBenchmarkingModel = (stages: readonly Stage[]) => {
return stages
.map((stage) => {
return stage.action === 'constantConcurrentUsers'
? `${stage.action}(${stage.maxUsersCount}) during (${getDuration(stage.duration)})`
: `${stage.action}(${stage.minUsersCount}) to ${stage.maxUsersCount} during (${getDuration(
stage.duration
)})`;
})
.join(', ');
};
/**
* Generates Gatling-compatible simulation content
* @param params Simulation parameters
* @returns Gatling simulation content as string
*/
export const generateSimulationContent = (params: Simulation) => {
const { simulationName, packageName, scenarioName, baseUrl, requests, scalabilitySetup } = params;
const protocol = buildProtocol(baseUrl);
const scenario = buildScenario(scenarioName, requests);
const setup = buildSetup(
buildBenchmarkingModel(scalabilitySetup.warmup.stages),
buildBenchmarkingModel(scalabilitySetup.test.stages),
getDuration(scalabilitySetup.maxDuration)
);
return buildSimulation(packageName, simulationName, protocol, scenario, setup);
};

View file

@ -0,0 +1,73 @@
/*
* 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.
*/
/** ***********************************************************
*
* Run `node scripts/generate_scalability_simulations --help` for usage information
*
*************************************************************/
import { run } from '@kbn/dev-cli-runner';
import { createFlagError } from '@kbn/dev-cli-errors';
import path from 'path';
import fs from 'fs';
import { generator } from './generate_files';
const gatlingBundlePackageName = 'computerdatabase';
export async function generateScalabilitySimulations() {
run(
async ({ log, flags }) => {
const baseUrl = flags.baseUrl;
if (baseUrl && typeof baseUrl !== 'string') {
throw createFlagError('--baseUrl must be a string');
}
if (!baseUrl) {
throw createFlagError('--baseUrl must be defined');
}
if (typeof flags.dir !== 'string') {
throw createFlagError('--dir must be a string');
}
const dir = path.resolve(flags.dir);
if (!dir) {
throw createFlagError('--dir must be defined');
}
if (!fs.existsSync(path.resolve(dir))) {
throw createFlagError('--dir must be an existing folder path');
}
if (typeof flags.packageName !== 'undefined' && typeof flags.packageName !== 'string') {
throw createFlagError('--packageName is optional, but must be a string');
}
const packageName = !flags.packageName ? gatlingBundlePackageName : flags.packageName;
return generator({
dir,
baseUrl,
packageName,
log,
});
},
{
description: `CLI to get scalability simulation file out of single user performance journey APM traces`,
flags: {
string: ['dir', 'baseUrl', 'packageName'],
help: `
--dir Path to json files with APM traces, generated using kbn-performance-testing-dataset-extractor
--baseUrl Kibana server base url to use for scalability testing
--packageName Simulation file package reference: ${gatlingBundlePackageName} is used by default and assumes
a run with Gatling bundle. Use 'org.kibanaLoadTest' to run with 'kibana-load-testing' project.
`,
},
usage: '--dir target/scalability_traces --baseUrl http://localhost:5620',
}
);
}

View file

@ -0,0 +1,74 @@
/*
* 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 { ToolingLog } from '@kbn/tooling-log';
import fsp from 'fs/promises';
import fs from 'fs';
import path from 'path';
import { generateSimulationContent } from './build_simulation';
import { getHttpRequests } from './parse_traces';
import { Journey } from './types/journey';
export interface CLIParams {
dir: string;
baseUrl: string;
packageName: string;
log: ToolingLog;
}
export const generator = async ({ dir, baseUrl, packageName, log }: CLIParams) => {
const jsonInDir = fs.readdirSync(dir).filter((file) => path.extname(file) === '.json');
log.info(`Found ${jsonInDir.length} json files in path: ${jsonInDir}`);
for (const file of jsonInDir) {
const jsonPath = path.resolve(dir, file);
const journey: Journey = JSON.parse(fs.readFileSync(jsonPath).toString());
if (!journey.traceItems || journey.traceItems.length === 0) {
log.error(`No 'traceItems' found in ${jsonPath}, skipping file`);
return;
}
if (!journey.scalabilitySetup) {
log.error(`No 'scalabilitySetup' found in ${jsonPath}, skipping file`);
return;
}
const requests = getHttpRequests(journey.traceItems);
requests.forEach((req) =>
log.debug(`${req.date} ${req.transactionId} ${req.method} ${req.path}`)
);
const simulationName = journey.journeyName
.replace(/[^a-zA-Z ]/g, ' ')
.replace(/\b(\w)/g, (match, capture) => capture.toUpperCase())
.replace(/\s+/g, '');
const fileName = `${simulationName}.scala`;
const outputDir = path.resolve('target/scalability_simulations');
const filePath = path.resolve(outputDir, fileName);
const fileContent = generateSimulationContent({
simulationName,
packageName,
scenarioName: `${journey.journeyName} ${journey.kibanaVersion}`,
baseUrl,
scalabilitySetup: journey.scalabilitySetup,
requests,
});
if (!fs.existsSync(outputDir)) {
await fsp.mkdir(outputDir, { recursive: true });
}
const stream = fs.createWriteStream(filePath);
stream.write(fileContent);
stream.end(() => log.info(`Gatling simulation '${simulationName}' was saved in '${filePath}'`));
}
};

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
export { generator } from './generate_files';
export * from './cli';

View file

@ -0,0 +1,29 @@
/*
* 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 { TraceItem } from './types/journey';
import { Request } from './types/simulation';
export const getHttpRequests = (traces: readonly TraceItem[]): Request[] => {
return traces
.map((trace) => {
const timestamp = new Date(trace.timestamp).getTime();
const date = trace.timestamp;
const transactionId = trace.transaction.id;
const method = trace.request.method;
const path = trace.request.url.path;
const rawHeaders = trace.request.headers;
const headers = Object.keys(rawHeaders).map((key) => ({
name: key,
value: String(rawHeaders[key].join('')),
}));
const body = trace.request.body;
return { timestamp, date, transactionId, method, path, headers, body };
})
.sort((a, b) => (a.timestamp > b.timestamp ? 1 : -1));
};

View file

@ -0,0 +1,89 @@
/*
* 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.
*/
export interface Headers {
readonly [key: string]: string[];
}
export interface HttpRequest {
readonly headers?: Headers[];
readonly method?: string;
readonly body?: string;
}
export interface HttpResponse {
readonly headers?: Headers[];
readonly status_code?: number;
}
export interface Http {
readonly request?: HttpRequest;
readonly response?: HttpResponse;
}
export interface Trace {
readonly '@timestamp': string;
readonly transaction_id: string;
readonly url_path: string;
readonly url_base: string;
readonly span_id?: string;
readonly http?: Http;
readonly children?: readonly Trace[];
}
export interface Transaction {
readonly transactionName: string;
readonly transactionType: string;
readonly service: string;
readonly traces: readonly Trace[];
}
export interface Request {
readonly url: {
readonly path: string;
};
readonly headers: Headers;
readonly method: string;
readonly body?: string;
}
export interface TransactionItem {
readonly id: string;
readonly name: string;
readonly type: string;
}
export interface TraceItem {
readonly traceId: string;
readonly timestamp: string;
readonly request: Request;
readonly response: {
readonly status: string;
};
readonly transaction: TransactionItem;
}
export interface Stage {
readonly action: string;
readonly minUsersCount?: number;
readonly maxUsersCount: number;
readonly duration: string;
}
export interface Setup {
readonly warmup: { readonly stages: readonly Stage[] };
readonly test: { readonly stages: readonly Stage[] };
readonly maxDuration: string;
}
export interface Journey {
readonly journeyName: string;
readonly kibanaVersion: string;
readonly scalabilitySetup: Setup;
readonly traceItems: readonly TraceItem[];
}

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 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 { Setup } from './journey';
export interface Header {
readonly name: string;
readonly value: string;
}
export interface Request {
readonly timestamp: number;
readonly date: string;
readonly transactionId: string;
readonly method: string;
readonly path: string;
readonly headers: readonly Header[];
readonly body?: string;
}
export interface Simulation {
readonly simulationName: string;
readonly packageName: string;
readonly scenarioName: string;
readonly baseUrl: string;
readonly scalabilitySetup: Setup;
readonly requests: readonly Request[];
}

View file

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.bazel.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "target_types",
"rootDir": "src",
"stripInternal": false,
"types": [
"jest",
"node"
]
},
"include": [
"src/**/*"
]
}

View file

@ -0,0 +1,10 @@
/*
* 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.
*/
require('../src/setup_node_env');
require('@kbn/scalability-simulation-generator').generateScalabilitySimulations();

View file

@ -3247,6 +3247,10 @@
version "0.0.0"
uid ""
"@kbn/scalability-simulation-generator@link:bazel-bin/packages/kbn-scalability-simulation-generator":
version "0.0.0"
uid ""
"@kbn/securitysolution-autocomplete@link:bazel-bin/packages/kbn-securitysolution-autocomplete":
version "0.0.0"
uid ""
@ -6582,6 +6586,10 @@
version "0.0.0"
uid ""
"@types/kbn__scalability-simulation-generator@link:bazel-bin/packages/kbn-scalability-simulation-generator/npm_module_types":
version "0.0.0"
uid ""
"@types/kbn__securitysolution-autocomplete@link:bazel-bin/packages/kbn-securitysolution-autocomplete/npm_module_types":
version "0.0.0"
uid ""