diff --git a/packages/kbn-test/src/functional_test_runner/lib/mocha/load_tests.ts b/packages/kbn-test/src/functional_test_runner/lib/mocha/load_tests.ts index c84d78fe1d20a..2303704ea43fa 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/mocha/load_tests.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/mocha/load_tests.ts @@ -57,7 +57,11 @@ export const loadTests = ({ updateBaselines, }; - decorateSnapshotUi({ lifecycle, updateSnapshots, isCi: !!process.env.CI }); + decorateSnapshotUi({ + lifecycle, + updateSnapshots, + isCi: !!process.env.CI, + }); function loadTestFile(path: string) { if (typeof path !== 'string' || !isAbsolute(path)) { diff --git a/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts b/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts index 78e2b8d7e680c..3d00eae7f22ff 100644 --- a/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts +++ b/packages/kbn-test/src/functional_test_runner/lib/snapshots/decorate_snapshot_ui.ts @@ -33,11 +33,13 @@ const globalState: { registered: boolean; currentTest: Test | null; snapshotStates: Record; + deploymentAgnostic: boolean; } = { updateSnapshot: 'none', registered: false, currentTest: null, snapshotStates: {}, + deploymentAgnostic: false, }; const modifyStackTracePrepareOnce = once(() => { @@ -125,7 +127,7 @@ export function decorateSnapshotUi({ const snapshotState = globalState.snapshotStates[file]; if (snapshotState && !test.isPassed()) { - snapshotState.markSnapshotsAsCheckedForTest(test.fullTitle()); + snapshotState.markSnapshotsAsCheckedForTest(getTestTitle(test)); } }); @@ -194,7 +196,7 @@ export function expectSnapshot(received: any) { const context: SnapshotContext = { snapshotState, - currentTestName: test.fullTitle(), + currentTestName: getTestTitle(test), }; return { @@ -204,6 +206,18 @@ export function expectSnapshot(received: any) { }; } +function getTestTitle(test: Test) { + return ( + test + .fullTitle() + // remove deployment type from test title so that a single snapshot can be used for all deployment types + .replace( + /^(Serverless|Stateful)\s+([^\-]+)\s*-?\s*Deployment-agnostic/g, + 'Deployment-agnostic' + ) + ); +} + function expectToMatchSnapshot(snapshotContext: SnapshotContext, received: any) { const matcher = toMatchSnapshot.bind(snapshotContext as any); const result = matcher(received) as SyncExpectationResult; diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts index bc209186c869c..74013fcc56e87 100644 --- a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/index.ts @@ -40,6 +40,7 @@ export default function apmApiIntegrationTests({ loadTestFile(require.resolve('./suggestions')); loadTestFile(require.resolve('./throughput')); loadTestFile(require.resolve('./time_range_metadata')); + loadTestFile(require.resolve('./traces')); loadTestFile(require.resolve('./transactions')); }); } diff --git a/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.spec.snap b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/__snapshots__/top_traces.spec.snap similarity index 53% rename from x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.spec.snap rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/__snapshots__/top_traces.spec.snap index 77aba0cdd3bf6..b2a69a7a098d5 100644 --- a/x-pack/test/apm_api_integration/tests/traces/__snapshots__/top_traces.spec.snap +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/__snapshots__/top_traces.spec.snap @@ -1,76 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`APM API tests traces/top_traces.spec.ts basic apm_8.0.0 Top traces when data is loaded returns the correct buckets 1`] = ` +exports[`Deployment-agnostic APM API integration tests APM Traces Top traces when data is loaded returns the correct buckets 1`] = ` Array [ - Object { - "agentName": "java", - "averageResponseTime": 1639, - "impact": 0, - "key": Object { - "service.name": "opbeans-java", - "transaction.name": "DispatcherServlet#doPost", - }, - "serviceName": "opbeans-java", - "transactionName": "DispatcherServlet#doPost", - "transactionType": "request", - "transactionsPerMinute": 0.0333333333333333, - }, - Object { - "agentName": "nodejs", - "averageResponseTime": 3279, - "impact": 0.00144735571024101, - "key": Object { - "service.name": "opbeans-node", - "transaction.name": "POST /api/orders", - }, - "serviceName": "opbeans-node", - "transactionName": "POST /api/orders", - "transactionType": "request", - "transactionsPerMinute": 0.0333333333333333, - }, - Object { - "agentName": "nodejs", - "averageResponseTime": 6175, - "impact": 0.00400317408637392, - "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/products/:id", - }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/products/:id", - "transactionType": "request", - "transactionsPerMinute": 0.0333333333333333, - }, - Object { - "agentName": "dotnet", - "averageResponseTime": 3495, - "impact": 0.00472243927164613, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "POST Orders/Post", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "POST Orders/Post", - "transactionType": "request", - "transactionsPerMinute": 0.0666666666666667, - }, - Object { - "agentName": "python", - "averageResponseTime": 7039, - "impact": 0.00476568343615943, - "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.product", - }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.product", - "transactionType": "request", - "transactionsPerMinute": 0.0333333333333333, - }, Object { "agentName": "ruby", - "averageResponseTime": 6303, - "impact": 0.00967875004525193, + "averageResponseTime": 5664, + "impact": 0, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::OrdersController#create", @@ -78,12 +13,12 @@ Array [ "serviceName": "opbeans-ruby", "transactionName": "Api::OrdersController#create", "transactionType": "request", - "transactionsPerMinute": 0.0666666666666667, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "java", - "averageResponseTime": 7209.66666666667, - "impact": 0.0176418540534865, + "averageResponseTime": 6031, + "impact": 0.000810693162092553, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#products", @@ -91,12 +26,12 @@ Array [ "serviceName": "opbeans-java", "transactionName": "APIRestController#products", "transactionType": "request", - "transactionsPerMinute": 0.1, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "java", - "averageResponseTime": 4511, - "impact": 0.0224401912465233, + "averageResponseTime": 4506.5, + "impact": 0.00739785122574376, "key": Object { "service.name": "opbeans-java", "transaction.name": "APIRestController#orders", @@ -104,103 +39,51 @@ Array [ "serviceName": "opbeans-java", "transactionName": "APIRestController#orders", "transactionType": "request", - "transactionsPerMinute": 0.2, - }, - Object { - "agentName": "python", - "averageResponseTime": 7607, - "impact": 0.0254072704525173, - "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.order", - }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.order", - "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, - }, - Object { - "agentName": "nodejs", - "averageResponseTime": 10143, - "impact": 0.025408152986487, - "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/types", - }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/types", - "transactionType": "request", - "transactionsPerMinute": 0.1, - }, - Object { - "agentName": "ruby", - "averageResponseTime": 6105.66666666667, - "impact": 0.0308842762682221, - "key": Object { - "service.name": "opbeans-ruby", - "transaction.name": "Api::TypesController#index", - }, - "serviceName": "opbeans-ruby", - "transactionName": "Api::TypesController#index", - "transactionType": "request", - "transactionsPerMinute": 0.2, - }, - Object { - "agentName": "java", - "averageResponseTime": 6116.33333333333, - "impact": 0.0309407584422802, - "key": Object { - "service.name": "opbeans-java", - "transaction.name": "APIRestController#customerWhoBought", - }, - "serviceName": "opbeans-java", - "transactionName": "APIRestController#customerWhoBought", - "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "java", - "averageResponseTime": 12543, - "impact": 0.0317623975680329, + "averageResponseTime": 9534, + "impact": 0.00854872625966807, "key": Object { "service.name": "opbeans-java", - "transaction.name": "APIRestController#customers", + "transaction.name": "APIRestController#product", }, "serviceName": "opbeans-java", - "transactionName": "APIRestController#customers", + "transactionName": "APIRestController#product", "transactionType": "request", - "transactionsPerMinute": 0.1, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "nodejs", - "averageResponseTime": 5551, - "impact": 0.0328461492827744, + "averageResponseTime": 10075, + "impact": 0.00974378075746663, "key": Object { "service.name": "opbeans-node", - "transaction.name": "GET /api/orders/:id", + "transaction.name": "POST /api", }, "serviceName": "opbeans-node", - "transactionName": "GET /api/orders/:id", + "transactionName": "POST /api", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "java", - "averageResponseTime": 13183, - "impact": 0.0334568627897785, + "averageResponseTime": 4839.33333333333, + "impact": 0.0195582486571321, "key": Object { "service.name": "opbeans-java", - "transaction.name": "APIRestController#stats", + "transaction.name": "APIRestController#topProducts", }, "serviceName": "opbeans-java", - "transactionName": "APIRestController#stats", + "transactionName": "APIRestController#topProducts", "transactionType": "request", - "transactionsPerMinute": 0.1, + "transactionsPerMinute": 0.05, }, Object { "agentName": "go", - "averageResponseTime": 8050.2, - "impact": 0.0340764016364792, + "averageResponseTime": 7530.5, + "impact": 0.020757721101318, "key": Object { "service.name": "opbeans-go", "transaction.name": "POST /api/orders", @@ -208,51 +91,25 @@ Array [ "serviceName": "opbeans-go", "transactionName": "POST /api/orders", "transactionType": "request", - "transactionsPerMinute": 0.166666666666667, - }, - Object { - "agentName": "ruby", - "averageResponseTime": 10079, - "impact": 0.0341337663445071, - "key": Object { - "service.name": "opbeans-ruby", - "transaction.name": "Api::OrdersController#show", - }, - "serviceName": "opbeans-ruby", - "transactionName": "Api::OrdersController#show", - "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, - }, - Object { - "agentName": "nodejs", - "averageResponseTime": 8463, - "impact": 0.0358979517498557, - "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/products/:id/customers", - }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/products/:id/customers", - "transactionType": "request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "ruby", - "averageResponseTime": 10799, - "impact": 0.0366754641771254, + "averageResponseTime": 7582.5, + "impact": 0.0209874543134642, "key": Object { "service.name": "opbeans-ruby", - "transaction.name": "Api::ProductsController#show", + "transaction.name": "Api::CustomersController#show", }, "serviceName": "opbeans-ruby", - "transactionName": "Api::ProductsController#show", + "transactionName": "Api::CustomersController#show", "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "ruby", - "averageResponseTime": 7428.33333333333, - "impact": 0.0378880658514371, + "averageResponseTime": 8001, + "impact": 0.0228363648766017, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::TypesController#show", @@ -260,12 +117,12 @@ Array [ "serviceName": "opbeans-ruby", "transactionName": "Api::TypesController#show", "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "java", - "averageResponseTime": 3105.13333333333, - "impact": 0.039659311528543, + "averageResponseTime": 3259.4, + "impact": 0.0234880119687469, "key": Object { "service.name": "opbeans-java", "transaction.name": "ResourceHttpRequestHandler", @@ -273,454 +130,402 @@ Array [ "serviceName": "opbeans-java", "transactionName": "ResourceHttpRequestHandler", "transactionType": "request", - "transactionsPerMinute": 0.5, + "transactionsPerMinute": 0.0833333333333333, }, Object { - "agentName": "java", - "averageResponseTime": 6883.57142857143, - "impact": 0.0410784261517549, + "agentName": "nodejs", + "averageResponseTime": 5675, + "impact": 0.0250961444537697, "key": Object { - "service.name": "opbeans-java", - "transaction.name": "APIRestController#order", + "service.name": "opbeans-node", + "transaction.name": "GET /api/products/top", }, - "serviceName": "opbeans-java", - "transactionName": "APIRestController#order", + "serviceName": "opbeans-node", + "transactionName": "GET /api/products/top", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.05, }, Object { - "agentName": "dotnet", - "averageResponseTime": 3505, - "impact": 0.0480460318422139, + "agentName": "nodejs", + "averageResponseTime": 8537, + "impact": 0.0252043841402617, "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Products/Get", + "service.name": "opbeans-node", + "transaction.name": "GET /api/products/:id", }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Products/Get", + "serviceName": "opbeans-node", + "transactionName": "GET /api/products/:id", "transactionType": "request", - "transactionsPerMinute": 0.533333333333333, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "java", - "averageResponseTime": 5621.4, - "impact": 0.0481642913941483, + "averageResponseTime": 6006.33333333333, + "impact": 0.0272918638083201, "key": Object { "service.name": "opbeans-java", - "transaction.name": "APIRestController#topProducts", + "transaction.name": "APIRestController#customerWhoBought", }, "serviceName": "opbeans-java", - "transactionName": "APIRestController#topProducts", - "transactionType": "request", - "transactionsPerMinute": 0.333333333333333, - }, - Object { - "agentName": "nodejs", - "averageResponseTime": 8428.71428571429, - "impact": 0.0506239135675883, - "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/orders", - }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/orders", + "transactionName": "APIRestController#customerWhoBought", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.05, }, Object { "agentName": "nodejs", - "averageResponseTime": 8520.14285714286, - "impact": 0.0511887353081702, + "averageResponseTime": 18064, + "impact": 0.0273912676020372, "key": Object { "service.name": "opbeans-node", - "transaction.name": "GET /api/customers/:id", + "transaction.name": "GET /api/products", }, "serviceName": "opbeans-node", - "transactionName": "GET /api/customers/:id", + "transactionName": "GET /api/products", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "nodejs", - "averageResponseTime": 6683.44444444444, - "impact": 0.0516388276326964, + "averageResponseTime": 19217, + "impact": 0.0299382136943879, "key": Object { "service.name": "opbeans-node", - "transaction.name": "GET /api/products/top", + "transaction.name": "GET /api/customers", }, "serviceName": "opbeans-node", - "transactionName": "GET /api/products/top", - "transactionType": "request", - "transactionsPerMinute": 0.3, - }, - Object { - "agentName": "dotnet", - "averageResponseTime": 3482.78947368421, - "impact": 0.0569534471979838, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Types/Get", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Types/Get", + "transactionName": "GET /api/customers", "transactionType": "request", - "transactionsPerMinute": 0.633333333333333, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "python", - "averageResponseTime": 16703, - "impact": 0.057517386404596, + "averageResponseTime": 22023, + "impact": 0.0361365924759457, "key": Object { "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.product_type", + "transaction.name": "GET opbeans.views.customer", }, "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.product_type", - "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, - }, - Object { - "agentName": "dotnet", - "averageResponseTime": 4943, - "impact": 0.0596266425920813, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Products/Get {id}", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Products/Get {id}", - "transactionType": "request", - "transactionsPerMinute": 0.466666666666667, - }, - Object { - "agentName": "nodejs", - "averageResponseTime": 7892.33333333333, - "impact": 0.0612407972225879, - "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/types/:id", - }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/types/:id", + "transactionName": "GET opbeans.views.customer", "transactionType": "request", - "transactionsPerMinute": 0.3, + "transactionsPerMinute": 0.0166666666666667, }, Object { - "agentName": "dotnet", - "averageResponseTime": 6346.42857142857, - "impact": 0.0769666700279444, + "agentName": "ruby", + "averageResponseTime": 12106, + "impact": 0.0409720347969828, "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Orders/Get {id}", + "service.name": "opbeans-ruby", + "transaction.name": "Api::ProductsController#index", }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Orders/Get {id}", + "serviceName": "opbeans-ruby", + "transactionName": "Api::ProductsController#index", "transactionType": "request", - "transactionsPerMinute": 0.466666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "agentName": "go", - "averageResponseTime": 7052.84615384615, - "impact": 0.0794704188998674, + "agentName": "ruby", + "averageResponseTime": 12331.5, + "impact": 0.0419682817073472, "key": Object { - "service.name": "opbeans-go", - "transaction.name": "GET /api/products", + "service.name": "opbeans-ruby", + "transaction.name": "Api::TypesController#index", }, - "serviceName": "opbeans-go", - "transactionName": "GET /api/products", + "serviceName": "opbeans-ruby", + "transactionName": "Api::TypesController#index", "transactionType": "request", - "transactionsPerMinute": 0.433333333333333, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "java", - "averageResponseTime": 10484.3333333333, - "impact": 0.0818285496667966, + "averageResponseTime": 12897.5, + "impact": 0.0444688393626299, "key": Object { "service.name": "opbeans-java", - "transaction.name": "APIRestController#product", + "transaction.name": "APIRestController#customers", }, "serviceName": "opbeans-java", - "transactionName": "APIRestController#product", + "transactionName": "APIRestController#customers", "transactionType": "request", - "transactionsPerMinute": 0.3, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "agentName": "nodejs", - "averageResponseTime": 23711, - "impact": 0.0822565786420813, + "agentName": "java", + "averageResponseTime": 6831.75, + "impact": 0.0478529862953978, "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/stats", + "service.name": "opbeans-java", + "transaction.name": "APIRestController#customer", }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/stats", + "serviceName": "opbeans-java", + "transactionName": "APIRestController#customer", "transactionType": "request", - "transactionsPerMinute": 0.133333333333333, + "transactionsPerMinute": 0.0666666666666667, }, Object { - "agentName": "dotnet", - "averageResponseTime": 4491.36363636364, - "impact": 0.0857567083657495, + "agentName": "ruby", + "averageResponseTime": 29231, + "impact": 0.0520588712562267, "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Types/Get {id}", + "service.name": "opbeans-ruby", + "transaction.name": "Api::ProductsController#show", }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Types/Get {id}", + "serviceName": "opbeans-ruby", + "transactionName": "Api::ProductsController#show", "transactionType": "request", - "transactionsPerMinute": 0.733333333333333, + "transactionsPerMinute": 0.0166666666666667, }, Object { "agentName": "python", - "averageResponseTime": 20715.8, - "impact": 0.089965512867054, + "averageResponseTime": 16222.5, + "impact": 0.0591585111008193, "key": Object { "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.stats", + "transaction.name": "GET opbeans.views.orders", }, "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.stats", + "transactionName": "GET opbeans.views.orders", "transactionType": "request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "nodejs", - "averageResponseTime": 9036.33333333333, - "impact": 0.0942519803576885, + "averageResponseTime": 17629, + "impact": 0.065372352694733, "key": Object { "service.name": "opbeans-node", - "transaction.name": "GET /api/products", + "transaction.name": "GET /api/stats", }, "serviceName": "opbeans-node", - "transactionName": "GET /api/products", + "transactionName": "GET /api/stats", "transactionType": "request", - "transactionsPerMinute": 0.4, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "agentName": "java", - "averageResponseTime": 7504.06666666667, - "impact": 0.0978924329825326, + "agentName": "ruby", + "averageResponseTime": 9031.5, + "impact": 0.0672897414268756, "key": Object { - "service.name": "opbeans-java", - "transaction.name": "APIRestController#customer", + "service.name": "opbeans-ruby", + "transaction.name": "Api::OrdersController#show", }, - "serviceName": "opbeans-java", - "transactionName": "APIRestController#customer", + "serviceName": "opbeans-ruby", + "transactionName": "Api::OrdersController#show", "transactionType": "request", - "transactionsPerMinute": 0.5, + "transactionsPerMinute": 0.0666666666666667, }, Object { - "agentName": "go", - "averageResponseTime": 4250.55555555556, - "impact": 0.0998375378516613, + "agentName": "python", + "averageResponseTime": 38278, + "impact": 0.0720434517397453, "key": Object { - "service.name": "opbeans-go", - "transaction.name": "GET /api/types/:id", + "service.name": "opbeans-python", + "transaction.name": "GET opbeans.views.products", }, - "serviceName": "opbeans-go", - "transactionName": "GET /api/types/:id", + "serviceName": "opbeans-python", + "transactionName": "GET opbeans.views.products", "transactionType": "request", - "transactionsPerMinute": 0.9, + "transactionsPerMinute": 0.0166666666666667, }, Object { - "agentName": "nodejs", - "averageResponseTime": 21343, - "impact": 0.11156906191034, + "agentName": "python", + "averageResponseTime": 19176.5, + "impact": 0.0722091247292738, "key": Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/customers", + "service.name": "opbeans-python", + "transaction.name": "GET opbeans.views.product", }, - "serviceName": "opbeans-node", - "transactionName": "GET /api/customers", + "serviceName": "opbeans-python", + "transactionName": "GET opbeans.views.product", "transactionType": "request", - "transactionsPerMinute": 0.2, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "ruby", - "averageResponseTime": 16655, - "impact": 0.116142352941114, + "averageResponseTime": 21443, + "impact": 0.0822224002163734, "key": Object { "service.name": "opbeans-ruby", - "transaction.name": "Api::ProductsController#top", + "transaction.name": "Api::OrdersController#index", }, "serviceName": "opbeans-ruby", - "transactionName": "Api::ProductsController#top", + "transactionName": "Api::OrdersController#index", "transactionType": "request", - "transactionsPerMinute": 0.266666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "go", - "averageResponseTime": 5749, - "impact": 0.12032203382142, + "averageResponseTime": 7299.66666666667, + "impact": 0.0842369837690393, "key": Object { "service.name": "opbeans-go", - "transaction.name": "GET /api/types", + "transaction.name": "GET /api/orders", }, "serviceName": "opbeans-go", - "transactionName": "GET /api/types", + "transactionName": "GET /api/orders", "transactionType": "request", - "transactionsPerMinute": 0.8, + "transactionsPerMinute": 0.1, }, Object { "agentName": "ruby", - "averageResponseTime": 9951, - "impact": 0.121502864272824, + "averageResponseTime": 11738, + "impact": 0.0912040852220091, "key": Object { "service.name": "opbeans-ruby", - "transaction.name": "Api::StatsController#index", + "transaction.name": "Api::ProductsController#top", }, "serviceName": "opbeans-ruby", - "transactionName": "Api::StatsController#index", + "transactionName": "Api::ProductsController#top", "transactionType": "request", - "transactionsPerMinute": 0.466666666666667, + "transactionsPerMinute": 0.0666666666666667, }, Object { - "agentName": "go", - "averageResponseTime": 14040.6, - "impact": 0.122466591367692, + "agentName": "nodejs", + "averageResponseTime": 9640.8, + "impact": 0.0939697196605374, "key": Object { - "service.name": "opbeans-go", - "transaction.name": "GET /api/customers", + "service.name": "opbeans-node", + "transaction.name": "GET /api/orders/:id", }, - "serviceName": "opbeans-go", - "transactionName": "GET /api/customers", + "serviceName": "opbeans-node", + "transactionName": "GET /api/orders/:id", "transactionType": "request", - "transactionsPerMinute": 0.333333333333333, + "transactionsPerMinute": 0.0833333333333333, }, Object { "agentName": "ruby", - "averageResponseTime": 20963.5714285714, - "impact": 0.128060974201361, + "averageResponseTime": 8349.33333333333, + "impact": 0.0981490969430418, "key": Object { "service.name": "opbeans-ruby", - "transaction.name": "Api::OrdersController#index", + "transaction.name": "Api::StatsController#index", }, "serviceName": "opbeans-ruby", - "transactionName": "Api::OrdersController#index", + "transactionName": "Api::StatsController#index", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.1, }, Object { - "agentName": "python", - "averageResponseTime": 22874.4285714286, - "impact": 0.139865748579522, + "agentName": "nodejs", + "averageResponseTime": 9213.16666666667, + "impact": 0.109598205006055, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.customer", + "service.name": "opbeans-node", + "transaction.name": "GET /api/orders", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.customer", + "serviceName": "opbeans-node", + "transactionName": "GET /api/orders", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.1, }, Object { - "agentName": "python", - "averageResponseTime": 32203.8, - "impact": 0.140658264084276, + "agentName": "nodejs", + "averageResponseTime": 14031.25, + "impact": 0.111466996327935, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.customers", + "service.name": "opbeans-node", + "transaction.name": "GET /api/types/:id", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.customers", + "serviceName": "opbeans-node", + "transactionName": "GET /api/types/:id", "transactionType": "request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.0666666666666667, }, Object { - "agentName": "go", - "averageResponseTime": 4482.11111111111, - "impact": 0.140955678032051, + "agentName": "nodejs", + "averageResponseTime": 8779.85714285714, + "impact": 0.123249659343199, "key": Object { - "service.name": "opbeans-go", + "service.name": "opbeans-node", "transaction.name": "GET /api/customers/:id", }, - "serviceName": "opbeans-go", + "serviceName": "opbeans-node", "transactionName": "GET /api/customers/:id", "transactionType": "request", - "transactionsPerMinute": 1.2, + "transactionsPerMinute": 0.116666666666667, }, Object { - "agentName": "ruby", - "averageResponseTime": 12582.3846153846, - "impact": 0.142910490774846, + "agentName": "go", + "averageResponseTime": 6746.3, + "impact": 0.13651233439825, "key": Object { - "service.name": "opbeans-ruby", - "transaction.name": "Api::ProductsController#index", + "service.name": "opbeans-go", + "transaction.name": "GET /api/orders/:id", }, - "serviceName": "opbeans-ruby", - "transactionName": "Api::ProductsController#index", + "serviceName": "opbeans-go", + "transactionName": "GET /api/orders/:id", "transactionType": "request", - "transactionsPerMinute": 0.433333333333333, + "transactionsPerMinute": 0.166666666666667, }, Object { - "agentName": "ruby", - "averageResponseTime": 10009.9473684211, - "impact": 0.166401779979233, + "agentName": "go", + "averageResponseTime": 7179.9, + "impact": 0.146090442166188, "key": Object { - "service.name": "opbeans-ruby", - "transaction.name": "Api::CustomersController#show", + "service.name": "opbeans-go", + "transaction.name": "GET /api/types/:id", }, - "serviceName": "opbeans-ruby", - "transactionName": "Api::CustomersController#show", + "serviceName": "opbeans-go", + "transactionName": "GET /api/types/:id", "transactionType": "request", - "transactionsPerMinute": 0.633333333333333, + "transactionsPerMinute": 0.166666666666667, }, Object { - "agentName": "python", - "averageResponseTime": 27825.2857142857, - "impact": 0.170450845832029, + "agentName": "nodejs", + "averageResponseTime": 8171.11111111111, + "impact": 0.149936264496442, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.product_types", + "service.name": "opbeans-node", + "transaction.name": "GET /api/products/:id/customers", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.product_types", + "serviceName": "opbeans-node", + "transactionName": "GET /api/products/:id/customers", "transactionType": "request", - "transactionsPerMinute": 0.233333333333333, + "transactionsPerMinute": 0.15, }, Object { - "agentName": "python", - "averageResponseTime": 20562.2, - "impact": 0.180021926732983, + "agentName": "go", + "averageResponseTime": 9247.625, + "impact": 0.150910421674869, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.orders", + "service.name": "opbeans-go", + "transaction.name": "GET /api/customers", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.orders", + "serviceName": "opbeans-go", + "transactionName": "GET /api/customers", "transactionType": "request", - "transactionsPerMinute": 0.333333333333333, + "transactionsPerMinute": 0.133333333333333, }, Object { - "agentName": "dotnet", - "averageResponseTime": 7106.76470588235, - "impact": 0.21180020991247, + "agentName": "python", + "averageResponseTime": 19205, + "impact": 0.157181696571819, "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Customers/Get {id}", + "service.name": "opbeans-python", + "transaction.name": "GET opbeans.views.product_type", }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Customers/Get {id}", + "serviceName": "opbeans-python", + "transactionName": "GET opbeans.views.product_type", "transactionType": "request", - "transactionsPerMinute": 1.13333333333333, + "transactionsPerMinute": 0.0666666666666667, }, Object { "agentName": "go", - "averageResponseTime": 8612.51724137931, - "impact": 0.218977858687708, + "averageResponseTime": 10272.25, + "impact": 0.169017374943732, "key": Object { "service.name": "opbeans-go", - "transaction.name": "GET /api/orders/:id", + "transaction.name": "GET /api/types", }, "serviceName": "opbeans-go", - "transactionName": "GET /api/orders/:id", + "transactionName": "GET /api/types", "transactionType": "request", - "transactionsPerMinute": 0.966666666666667, + "transactionsPerMinute": 0.133333333333333, }, Object { "agentName": "ruby", - "averageResponseTime": 11295, - "impact": 0.277663720068132, + "averageResponseTime": 10371, + "impact": 0.170762463766765, "key": Object { "service.name": "opbeans-ruby", "transaction.name": "Api::CustomersController#index", @@ -728,77 +533,64 @@ Array [ "serviceName": "opbeans-ruby", "transactionName": "Api::CustomersController#index", "transactionType": "request", - "transactionsPerMinute": 0.933333333333333, + "transactionsPerMinute": 0.133333333333333, }, Object { - "agentName": "python", - "averageResponseTime": 65035.8, - "impact": 0.285535040543522, + "agentName": "java", + "averageResponseTime": 28415.3333333333, + "impact": 0.175794504702042, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.product_customers", + "service.name": "opbeans-java", + "transaction.name": "DispatcherServlet#doGet", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.product_customers", + "serviceName": "opbeans-java", + "transactionName": "DispatcherServlet#doGet", "transactionType": "request", - "transactionsPerMinute": 0.166666666666667, + "transactionsPerMinute": 0.05, }, Object { "agentName": "go", - "averageResponseTime": 30999.4705882353, - "impact": 0.463640986028375, + "averageResponseTime": 6374, + "impact": 0.184608307744956, "key": Object { "service.name": "opbeans-go", - "transaction.name": "GET /api/stats", + "transaction.name": "GET /api/products", }, "serviceName": "opbeans-go", - "transactionName": "GET /api/stats", + "transactionName": "GET /api/products", "transactionType": "request", - "transactionsPerMinute": 0.566666666666667, + "transactionsPerMinute": 0.233333333333333, }, Object { "agentName": "go", - "averageResponseTime": 20197.4, - "impact": 0.622424732781511, + "averageResponseTime": 6257.46666666667, + "impact": 0.194827017739071, "key": Object { "service.name": "opbeans-go", - "transaction.name": "GET /api/products/:id/customers", + "transaction.name": "GET /api/customers/:id", }, "serviceName": "opbeans-go", - "transactionName": "GET /api/products/:id/customers", + "transactionName": "GET /api/customers/:id", "transactionType": "request", - "transactionsPerMinute": 1.16666666666667, + "transactionsPerMinute": 0.25, }, Object { "agentName": "python", - "averageResponseTime": 64681.6666666667, - "impact": 0.68355874339377, + "averageResponseTime": 111027.5, + "impact": 0.47800191836068, "key": Object { "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.top_products", + "transaction.name": "GET opbeans.views.stats", }, "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.top_products", - "transactionType": "request", - "transactionsPerMinute": 0.4, - }, - Object { - "agentName": "dotnet", - "averageResponseTime": 41416.1428571429, - "impact": 0.766127739061111, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Customers/Get", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Customers/Get", + "transactionName": "GET opbeans.views.stats", "transactionType": "request", - "transactionsPerMinute": 0.7, + "transactionsPerMinute": 0.0333333333333333, }, Object { "agentName": "go", - "averageResponseTime": 19429, - "impact": 0.821597646656097, + "averageResponseTime": 19844.9333333333, + "impact": 0.645042262296039, "key": Object { "service.name": "opbeans-go", "transaction.name": "GET /api/products/:id", @@ -806,38 +598,38 @@ Array [ "serviceName": "opbeans-go", "transactionName": "GET /api/products/:id", "transactionType": "request", - "transactionsPerMinute": 1.6, + "transactionsPerMinute": 0.25, }, Object { - "agentName": "dotnet", - "averageResponseTime": 62390.652173913, - "impact": 1.26497653527507, + "agentName": "python", + "averageResponseTime": 153199, + "impact": 0.664313344437989, "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Products/Customerwhobought {id}", + "service.name": "opbeans-python", + "transaction.name": "GET opbeans.views.top_products", }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Products/Customerwhobought {id}", + "serviceName": "opbeans-python", + "transactionName": "GET opbeans.views.top_products", "transactionType": "request", - "transactionsPerMinute": 0.766666666666667, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "agentName": "python", - "averageResponseTime": 33266.2, - "impact": 1.76006661931225, + "agentName": "go", + "averageResponseTime": 22825, + "impact": 0.895045012467666, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "opbeans.tasks.sync_orders", + "service.name": "opbeans-go", + "transaction.name": "GET /api/stats", }, - "serviceName": "opbeans-python", - "transactionName": "opbeans.tasks.sync_orders", - "transactionType": "celery", - "transactionsPerMinute": 2, + "serviceName": "opbeans-go", + "transactionName": "GET /api/stats", + "transactionType": "request", + "transactionsPerMinute": 0.3, }, Object { "agentName": "nodejs", - "averageResponseTime": 38491.4444444444, - "impact": 1.83293391905112, + "averageResponseTime": 28576.8666666667, + "impact": 0.934371362235332, "key": Object { "service.name": "opbeans-node", "transaction.name": "GET /api", @@ -845,90 +637,77 @@ Array [ "serviceName": "opbeans-node", "transactionName": "GET /api", "transactionType": "request", - "transactionsPerMinute": 1.8, - }, - Object { - "agentName": "dotnet", - "averageResponseTime": 118488.6, - "impact": 2.08995781717084, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Stats/Get", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Stats/Get", - "transactionType": "request", - "transactionsPerMinute": 0.666666666666667, + "transactionsPerMinute": 0.25, }, Object { - "agentName": "dotnet", - "averageResponseTime": 250440.142857143, - "impact": 4.64001412901584, + "agentName": "go", + "averageResponseTime": 75613.8461538462, + "impact": 2.1588648457865, "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Products/Top", + "service.name": "opbeans-go", + "transaction.name": "GET /api/products/:id/customers", }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Products/Top", + "serviceName": "opbeans-go", + "transactionName": "GET /api/products/:id/customers", "transactionType": "request", - "transactionsPerMinute": 0.7, + "transactionsPerMinute": 0.216666666666667, }, Object { - "agentName": "java", - "averageResponseTime": 312096.523809524, - "impact": 5.782704992387, + "agentName": "python", + "averageResponseTime": 500211, + "impact": 2.19739375623124, "key": Object { - "service.name": "opbeans-java", - "transaction.name": "DispatcherServlet#doGet", + "service.name": "opbeans-python", + "transaction.name": "GET opbeans.views.customers", }, - "serviceName": "opbeans-java", - "transactionName": "DispatcherServlet#doGet", + "serviceName": "opbeans-python", + "transactionName": "GET opbeans.views.customers", "transactionType": "request", - "transactionsPerMinute": 0.7, + "transactionsPerMinute": 0.0333333333333333, }, Object { - "agentName": "ruby", - "averageResponseTime": 91519.7032967033, - "impact": 7.34855500859826, + "agentName": "rum-js", + "averageResponseTime": 631900, + "impact": 13.9459899869012, "key": Object { - "service.name": "opbeans-ruby", - "transaction.name": "Rack", + "service.name": "opbeans-rum", + "transaction.name": "/customers", }, - "serviceName": "opbeans-ruby", - "transactionName": "Rack", - "transactionType": "request", - "transactionsPerMinute": 3.03333333333333, + "serviceName": "opbeans-rum", + "transactionName": "/customers", + "transactionType": "page-load", + "transactionsPerMinute": 0.166666666666667, }, Object { "agentName": "rum-js", - "averageResponseTime": 648269.769230769, - "impact": 7.43611473386403, + "averageResponseTime": 1163466.66666667, + "impact": 38.5384885525045, "key": Object { "service.name": "opbeans-rum", - "transaction.name": "/customers", + "transaction.name": "/products", }, "serviceName": "opbeans-rum", - "transactionName": "/customers", + "transactionName": "/products", "transactionType": "page-load", - "transactionsPerMinute": 0.433333333333333, + "transactionsPerMinute": 0.25, }, Object { - "agentName": "python", - "averageResponseTime": 1398919.72727273, - "impact": 13.5790895084132, + "agentName": "ruby", + "averageResponseTime": 404792.666666667, + "impact": 40.2254151113471, "key": Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.products", + "service.name": "opbeans-ruby", + "transaction.name": "Rack", }, - "serviceName": "opbeans-python", - "transactionName": "GET opbeans.views.products", + "serviceName": "opbeans-ruby", + "transactionName": "Rack", "transactionType": "request", - "transactionsPerMinute": 0.366666666666667, + "transactionsPerMinute": 0.75, }, Object { "agentName": "rum-js", - "averageResponseTime": 1199907.57142857, - "impact": 14.8239822181408, + "averageResponseTime": 1756666.66666667, + "impact": 46.5526432992941, "key": Object { "service.name": "opbeans-rum", "transaction.name": "/orders", @@ -936,38 +715,12 @@ Array [ "serviceName": "opbeans-rum", "transactionName": "/orders", "transactionType": "page-load", - "transactionsPerMinute": 0.466666666666667, - }, - Object { - "agentName": "rum-js", - "averageResponseTime": 955876.052631579, - "impact": 16.026822184214, - "key": Object { - "service.name": "opbeans-rum", - "transaction.name": "/products", - }, - "serviceName": "opbeans-rum", - "transactionName": "/products", - "transactionType": "page-load", - "transactionsPerMinute": 0.633333333333333, - }, - Object { - "agentName": "go", - "averageResponseTime": 965009.526315789, - "impact": 16.1799735991728, - "key": Object { - "service.name": "opbeans-go", - "transaction.name": "GET /api/orders", - }, - "serviceName": "opbeans-go", - "transactionName": "GET /api/orders", - "transactionType": "request", - "transactionsPerMinute": 0.633333333333333, + "transactionsPerMinute": 0.2, }, Object { "agentName": "rum-js", - "averageResponseTime": 1213675.30769231, - "impact": 27.8474053933734, + "averageResponseTime": 1008291.66666667, + "impact": 53.4424306904839, "key": Object { "service.name": "opbeans-rum", "transaction.name": "/dashboard", @@ -975,12 +728,12 @@ Array [ "serviceName": "opbeans-rum", "transactionName": "/dashboard", "transactionType": "page-load", - "transactionsPerMinute": 0.866666666666667, + "transactionsPerMinute": 0.4, }, Object { "agentName": "nodejs", - "averageResponseTime": 924019.363636364, - "impact": 35.8796065162284, + "averageResponseTime": 987612.65, + "impact": 87.2518831606925, "key": Object { "service.name": "opbeans-node", "transaction.name": "Update shipping status", @@ -988,72 +741,33 @@ Array [ "serviceName": "opbeans-node", "transactionName": "Update shipping status", "transactionType": "Worker", - "transactionsPerMinute": 1.46666666666667, + "transactionsPerMinute": 0.666666666666667, }, Object { "agentName": "nodejs", - "averageResponseTime": 1060469.15384615, - "impact": 36.498655556576, + "averageResponseTime": 947544.214285714, + "impact": 87.8976786828476, "key": Object { "service.name": "opbeans-node", - "transaction.name": "Process payment", + "transaction.name": "Process completed order", }, "serviceName": "opbeans-node", - "transactionName": "Process payment", + "transactionName": "Process completed order", "transactionType": "Worker", - "transactionsPerMinute": 1.3, - }, - Object { - "agentName": "python", - "averageResponseTime": 118686.822222222, - "impact": 37.7068083771466, - "key": Object { - "service.name": "opbeans-python", - "transaction.name": "opbeans.tasks.update_stats", - }, - "serviceName": "opbeans-python", - "transactionName": "opbeans.tasks.update_stats", - "transactionType": "celery", - "transactionsPerMinute": 12, + "transactionsPerMinute": 0.7, }, Object { "agentName": "nodejs", - "averageResponseTime": 1039228.27659574, - "impact": 43.1048035741496, + "averageResponseTime": 1077989.66666667, + "impact": 100, "key": Object { "service.name": "opbeans-node", - "transaction.name": "Process completed order", + "transaction.name": "Process payment", }, "serviceName": "opbeans-node", - "transactionName": "Process completed order", + "transactionName": "Process payment", "transactionType": "Worker", - "transactionsPerMinute": 1.56666666666667, - }, - Object { - "agentName": "python", - "averageResponseTime": 1949922.55555556, - "impact": 61.9499776921889, - "key": Object { - "service.name": "opbeans-python", - "transaction.name": "opbeans.tasks.sync_customers", - }, - "serviceName": "opbeans-python", - "transactionName": "opbeans.tasks.sync_customers", - "transactionType": "celery", - "transactionsPerMinute": 1.2, - }, - Object { - "agentName": "dotnet", - "averageResponseTime": 5963775, - "impact": 100, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Orders/Get", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Orders/Get", - "transactionType": "request", - "transactionsPerMinute": 0.633333333333333, + "transactionsPerMinute": 0.7, }, ] `; diff --git a/x-pack/test/apm_api_integration/tests/traces/critical_path.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/critical_path.spec.ts similarity index 79% rename from x-pack/test/apm_api_integration/tests/traces/critical_path.spec.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/critical_path.spec.ts index 6d55c55ba6dbf..1f1d28215307c 100644 --- a/x-pack/test/apm_api_integration/tests/traces/critical_path.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/critical_path.spec.ts @@ -10,13 +10,13 @@ import expect from '@kbn/expect'; import { Assign } from '@kbn/utility-types'; import { compact, invert, sortBy, uniq } from 'lodash'; import { Readable } from 'stream'; -import { SupertestReturnType } from '../../common/apm_api_supertest'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { SupertestReturnType } from '../../../../services/apm_api'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); const start = new Date('2022-01-01T00:00:00.000Z').getTime(); const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; @@ -33,79 +33,86 @@ export default function ApiTest({ getService }: FtrProviderContext) { children: FormattedNode[]; } - // format tree in somewhat concise format for easier testing - function formatTree(nodes: HydratedNode[]): FormattedNode[] { - return sortBy( - nodes.map((node) => { - const name = - node.metadata?.['processor.event'] === 'transaction' - ? node.metadata['transaction.name'] - : node.metadata?.['span.name'] || 'root'; - return { name, value: node.countExclusive, children: formatTree(node.children) }; - }), - (node) => node.name - ); - } - - async function fetchAndBuildCriticalPathTree( - options: { fn: () => SynthtraceGenerator } & ( - | { serviceName: string; transactionName: string } - | {} - ) - ) { - const { fn } = options; - - const generator = fn(); - - const unserialized = Array.from(generator); - - const serialized = unserialized.flatMap((event) => event.serialize()); - - const traceIds = compact(uniq(serialized.map((event) => event['trace.id']))); - - await apmSynthtraceEsClient.index(Readable.from(unserialized)); - - return apmApiClient - .readUser({ - endpoint: 'POST /internal/apm/traces/aggregated_critical_path', - params: { - body: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - traceIds, - serviceName: 'serviceName' in options ? options.serviceName : null, - transactionName: 'transactionName' in options ? options.transactionName : null, + describe('Aggregated critical path', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + // format tree in somewhat concise format for easier testing + function formatTree(nodes: HydratedNode[]): FormattedNode[] { + return sortBy( + nodes.map((node) => { + const name = + node.metadata?.['processor.event'] === 'transaction' + ? node.metadata['transaction.name'] + : node.metadata?.['span.name'] || 'root'; + return { name, value: node.countExclusive, children: formatTree(node.children) }; + }), + (node) => node.name + ); + } + + async function fetchAndBuildCriticalPathTree( + options: { fn: () => SynthtraceGenerator } & ( + | { serviceName: string; transactionName: string } + | {} + ) + ) { + const { fn } = options; + + const generator = fn(); + + const unserialized = Array.from(generator); + + const serialized = unserialized.flatMap((event) => event.serialize()); + + const traceIds = compact(uniq(serialized.map((event) => event['trace.id']))); + + await apmSynthtraceEsClient.index(Readable.from(unserialized)); + + return apmApiClient + .readUser({ + endpoint: 'POST /internal/apm/traces/aggregated_critical_path', + params: { + body: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + traceIds, + serviceName: 'serviceName' in options ? options.serviceName : null, + transactionName: 'transactionName' in options ? options.transactionName : null, + }, }, - }, - }) - .then((response) => { - const criticalPath = response.body.criticalPath!; + }) + .then((response) => { + const criticalPath = response.body.criticalPath!; - const nodeIdByOperationId = invert(criticalPath.operationIdByNodeId); + const nodeIdByOperationId = invert(criticalPath.operationIdByNodeId); - const { rootNodes, maxDepth } = getAggregatedCriticalPathRootNodes({ - criticalPath, - }); + const { rootNodes, maxDepth } = getAggregatedCriticalPathRootNodes({ + criticalPath, + }); + + function hydrateNode(node: Node): HydratedNode { + return { + ...node, + metadata: criticalPath.metadata[criticalPath.operationIdByNodeId[node.nodeId]], + children: node.children.map(hydrateNode), + }; + } - function hydrateNode(node: Node): HydratedNode { return { - ...node, - metadata: criticalPath.metadata[criticalPath.operationIdByNodeId[node.nodeId]], - children: node.children.map(hydrateNode), + rootNodes: rootNodes.map(hydrateNode), + maxDepth, + criticalPath, + nodeIdByOperationId, }; - } - - return { - rootNodes: rootNodes.map(hydrateNode), - maxDepth, - criticalPath, - nodeIdByOperationId, - }; - }); - } + }); + } + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + }); + + after(() => apmSynthtraceEsClient.clean()); - // FLAKY: https://github.com/elastic/kibana/issues/177542 - registry.when('Aggregated critical path', { config: 'basic', archives: [] }, () => { it('builds up the correct tree for a single transaction', async () => { const java = apm .service({ name: 'java', environment: 'production', agentName: 'java' }) @@ -427,7 +434,5 @@ export default function ApiTest({ getService }: FtrProviderContext) { }, ]); }); - - after(() => apmSynthtraceEsClient.clean()); }); } diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/find_traces.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/find_traces.spec.ts new file mode 100644 index 0000000000000..b1bd8467456d9 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/find_traces.spec.ts @@ -0,0 +1,232 @@ +/* + * 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 { apm, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { TraceSearchType } from '@kbn/apm-plugin/common/trace_explorer'; +import { Environment } from '@kbn/apm-plugin/common/environment_rt'; +import { ENVIRONMENT_ALL } from '@kbn/apm-plugin/common/environment_filter_values'; +import { sortBy } from 'lodash'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { ApmApiError } from '../../../../services/apm_api'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; +import { generateTrace } from './generate_trace'; + +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); + + const start = new Date('2022-01-01T00:00:00.000Z').getTime(); + const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; + + // for EQL sequences to work, events need a slight time offset, + // as ES will sort based on @timestamp. to acommodate this offset + // we also add a little bit of a buffer to the requested time range + const endWithOffset = end + 100000; + + describe('Find traces', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + async function fetchTraceSamples({ + query, + type, + environment, + }: { + query: string; + type: TraceSearchType; + environment: Environment; + }) { + return apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/find`, + params: { + query: { + query, + type, + start: new Date(start).toISOString(), + end: new Date(endWithOffset).toISOString(), + environment, + }, + }, + }); + } + + function fetchTraces(traceSamples: Array<{ traceId: string; transactionId: string }>) { + if (!traceSamples.length) { + return []; + } + + return Promise.all( + traceSamples.map(async ({ traceId, transactionId }) => { + const response = await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/{traceId}`, + params: { + path: { traceId }, + query: { + start: new Date(start).toISOString(), + end: new Date(endWithOffset).toISOString(), + entryTransactionId: transactionId, + }, + }, + }); + return response.body.traceItems.traceDocs; + }) + ); + } + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + }); + + after(() => apmSynthtraceEsClient.clean()); + + describe('when traces do not exist', () => { + it('handles empty state', async () => { + const response = await fetchTraceSamples({ + query: '', + type: TraceSearchType.kql, + environment: ENVIRONMENT_ALL.value, + }); + + expect(response.status).to.be(200); + expect(response.body).to.eql({ + traceSamples: [], + }); + }); + }); + + describe('when traces exist', () => { + before(() => { + const java = apm + .service({ name: 'java', environment: 'production', agentName: 'java' }) + .instance('java'); + + const node = apm + .service({ name: 'node', environment: 'development', agentName: 'nodejs' }) + .instance('node'); + + const python = apm + .service({ name: 'python', environment: 'production', agentName: 'python' }) + .instance('python'); + + return apmSynthtraceEsClient.index( + timerange(start, end) + .interval('15m') + .rate(1) + .generator((timestamp) => { + return [ + generateTrace(timestamp, [java, node]), + generateTrace(timestamp, [node, java], 'redis'), + generateTrace(timestamp, [python], 'redis'), + generateTrace(timestamp, [python, node, java], 'elasticsearch'), + generateTrace(timestamp, [java, python, node]), + ]; + }) + ); + }); + + describe('when using KQL', () => { + describe('and the query is empty', () => { + it('returns all trace samples', async () => { + const { + body: { traceSamples }, + } = await fetchTraceSamples({ + query: '', + type: TraceSearchType.kql, + environment: 'ENVIRONMENT_ALL', + }); + + expect(traceSamples.length).to.eql(5); + }); + }); + + describe('and query is set', () => { + it('returns the relevant traces', async () => { + const { + body: { traceSamples }, + } = await fetchTraceSamples({ + query: 'span.destination.service.resource:elasticsearch', + type: TraceSearchType.kql, + environment: 'ENVIRONMENT_ALL', + }); + + expect(traceSamples.length).to.eql(1); + }); + }); + }); + + describe('when using EQL', () => { + describe('and the query is invalid', () => { + it.skip('returns a 400', async function () { + try { + await fetchTraceSamples({ + query: '', + type: TraceSearchType.eql, + environment: 'ENVIRONMENT_ALL', + }); + this.fail(); + } catch (error: unknown) { + const apiError = error as ApmApiError; + expect(apiError.res.status).to.eql(400); + } + }); + }); + + describe('and the query is set', () => { + it('returns the correct trace samples for transaction sequences', async () => { + const { + body: { traceSamples }, + } = await fetchTraceSamples({ + query: `sequence by trace.id + [ transaction where service.name == "java" ] + [ transaction where service.name == "node" ]`, + type: TraceSearchType.eql, + environment: 'ENVIRONMENT_ALL', + }); + + const traces = await fetchTraces(traceSamples); + + expect(traces.length).to.eql(2); + + const mapped = traces.map((traceDocs) => { + return sortBy(traceDocs, '@timestamp') + .filter((doc) => doc.processor.event === 'transaction') + .map((doc) => doc.service.name); + }); + + expect(mapped).to.eql([ + ['java', 'node'], + ['java', 'python', 'node'], + ]); + }); + }); + + it('returns the correct trace samples for join sequences', async () => { + const { + body: { traceSamples }, + } = await fetchTraceSamples({ + query: `sequence by trace.id + [ span where service.name == "java" ] by span.id + [ transaction where service.name == "python" ] by parent.id`, + type: TraceSearchType.eql, + environment: 'ENVIRONMENT_ALL', + }); + + const traces = await fetchTraces(traceSamples); + + expect(traces.length).to.eql(1); + + const mapped = traces.map((traceDocs) => { + return sortBy(traceDocs, '@timestamp') + .filter((doc) => doc.processor.event === 'transaction') + .map((doc) => doc.service.name); + }); + + expect(mapped).to.eql([['java', 'python', 'node']]); + }); + }); + }); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/traces/generate_trace.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/generate_trace.ts similarity index 100% rename from x-pack/test/apm_api_integration/tests/traces/generate_trace.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/generate_trace.ts diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/index.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/index.ts new file mode 100644 index 0000000000000..d54216b3f5d8f --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ loadTestFile }: DeploymentAgnosticFtrProviderContext) { + describe('Traces', () => { + loadTestFile(require.resolve('./large_trace/large_trace.spec.ts')); + loadTestFile(require.resolve('./critical_path.spec.ts')); + loadTestFile(require.resolve('./find_traces.spec.ts')); + loadTestFile(require.resolve('./span_details.spec.ts')); + loadTestFile(require.resolve('./top_traces.spec.ts')); + loadTestFile(require.resolve('./trace_by_id.spec.ts')); + loadTestFile(require.resolve('./transaction_details.spec.ts')); + }); +} diff --git a/x-pack/test/apm_api_integration/tests/traces/large_trace/generate_large_trace.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/large_trace/generate_large_trace.ts similarity index 100% rename from x-pack/test/apm_api_integration/tests/traces/large_trace/generate_large_trace.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/large_trace/generate_large_trace.ts diff --git a/x-pack/test/apm_api_integration/tests/traces/large_trace/large_trace.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/large_trace/large_trace.spec.ts similarity index 86% rename from x-pack/test/apm_api_integration/tests/traces/large_trace/large_trace.spec.ts rename to x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/large_trace/large_trace.spec.ts index 023db5c0d2ba0..7a0952b856c6b 100644 --- a/x-pack/test/apm_api_integration/tests/traces/large_trace/large_trace.spec.ts +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/large_trace/large_trace.spec.ts @@ -14,8 +14,9 @@ import { import type { Client } from '@elastic/elasticsearch'; import type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; import expect from '@kbn/expect'; -import { ApmApiClient } from '../../../common/config'; -import { FtrProviderContext } from '../../../common/ftr_provider_context'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { ApmApiClient } from '../../../../../services/apm_api'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../../ftr_provider_context'; import { generateLargeTrace } from './generate_large_trace'; const start = new Date('2023-01-01T00:00:00.000Z').getTime(); @@ -23,16 +24,17 @@ const end = new Date('2023-01-01T00:01:00.000Z').getTime() - 1; const rootTransactionName = 'Long trace'; const environment = 'long_trace_scenario'; -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); const es = getService('es'); - // FLAKY: https://github.com/elastic/kibana/issues/177660 - registry.when('Large trace', { config: 'basic', archives: [] }, () => { + describe('Large trace', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + describe('when the trace is large (>15.000 items)', () => { - before(() => { + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); return generateLargeTrace({ start, end, diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/span_details.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/span_details.spec.ts new file mode 100644 index 0000000000000..d5b2efc3479a6 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/span_details.spec.ts @@ -0,0 +1,134 @@ +/* + * 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 { apm, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { Readable } from 'stream'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); + + const start = new Date('2022-01-01T00:00:00.000Z').getTime(); + const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; + + describe('Span details', () => { + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + async function fetchSpanDetails({ + traceId, + spanId, + parentTransactionId, + }: { + traceId: string; + spanId: string; + parentTransactionId?: string; + }) { + return await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/{traceId}/spans/{spanId}`, + params: { + path: { traceId, spanId }, + query: { + parentTransactionId, + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, + }, + }); + } + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + }); + + after(() => apmSynthtraceEsClient.clean()); + + describe('when data is not loaded', () => { + it('handles empty state', async () => { + const response = await fetchSpanDetails({ + traceId: 'foo', + spanId: 'bar', + }); + + expect(response.status).to.be(200); + expect(response.body).to.eql({}); + }); + }); + + describe('when data is loaded', () => { + let traceId: string; + let spanId: string; + let parentTransactionId: string; + before(async () => { + const instanceJava = apm + .service({ name: 'synth-apple', environment: 'production', agentName: 'java' }) + .instance('instance-b'); + const events = timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return [ + instanceJava + .transaction({ transactionName: 'GET /apple 🍏' }) + .timestamp(timestamp) + .duration(1000) + .failure() + .errors( + instanceJava + .error({ message: '[ResponseError] index_not_found_exception' }) + .timestamp(timestamp + 50) + ) + .children( + instanceJava + .span({ + spanName: 'get_green_apple_🍏', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .timestamp(timestamp + 50) + .duration(900) + .success() + ), + ]; + }); + + const unserialized = Array.from(events); + + const entities = unserialized.flatMap((event) => event.serialize()); + + const span = entities.find((entity) => { + return entity['processor.event'] === 'span'; + }); + spanId = span?.['span.id']!; + parentTransactionId = span?.['parent.id']!; + traceId = span?.['trace.id']!; + + await apmSynthtraceEsClient.index(Readable.from(unserialized)); + }); + + after(() => apmSynthtraceEsClient.clean()); + + describe('span details', () => { + let spanDetails: Awaited>['body']; + before(async () => { + const response = await fetchSpanDetails({ + traceId, + spanId, + parentTransactionId, + }); + expect(response.status).to.eql(200); + spanDetails = response.body; + }); + it('returns span details', () => { + expect(spanDetails.span?.span.name).to.eql('get_green_apple_🍏'); + expect(spanDetails.parentTransaction?.transaction.name).to.eql('GET /apple 🍏'); + }); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/top_traces.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/top_traces.spec.ts new file mode 100644 index 0000000000000..1f2abda3d42f8 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/top_traces.spec.ts @@ -0,0 +1,144 @@ +/* + * 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 expect from '@kbn/expect'; +import { sortBy } from 'lodash'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; +import archives_metadata from '../constants/archives_metadata'; +import { ARCHIVER_ROUTES } from '../constants/archiver'; + +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const esArchiver = getService('esArchiver'); + + const archiveName = '8.0.0'; + const metadata = archives_metadata[archiveName]; + + // url parameters + const { start, end } = metadata; + + describe('Top traces', () => { + describe('when data is not loaded', () => { + it('handles empty state', async () => { + const response = await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces`, + params: { + query: { + start, + end, + kuery: '', + environment: 'ENVIRONMENT_ALL', + probability: 1, + }, + }, + }); + + expect(response.status).to.be(200); + expect(response.body.items.length).to.be(0); + }); + }); + + describe('when data is loaded', () => { + let response: any; + before(async () => { + await esArchiver.load(ARCHIVER_ROUTES[archiveName]); + response = await apmApiClient.readUser({ + endpoint: 'GET /internal/apm/traces', + params: { + query: { + start, + end, + kuery: '', + environment: 'ENVIRONMENT_ALL', + probability: 1, + }, + }, + }); + }); + + after(async () => { + await esArchiver.unload(ARCHIVER_ROUTES[archiveName]); + }); + + it('returns the correct status code', () => { + expect(response.status).to.be(200); + }); + + it('returns the correct number of buckets', () => { + expectSnapshot(response.body.items.length).toMatchInline(`59`); + }); + + it('returns the correct buckets', () => { + const sortedItems = sortBy(response.body.items, 'impact'); + + const firstItem = sortedItems[0]; + const lastItem = sortedItems[sortedItems.length - 1]; + + const groups = sortedItems.map((item) => item.key).slice(0, 5); + + expectSnapshot(sortedItems).toMatch(); + + expectSnapshot(firstItem).toMatchInline(` + Object { + "agentName": "ruby", + "averageResponseTime": 5664, + "impact": 0, + "key": Object { + "service.name": "opbeans-ruby", + "transaction.name": "Api::OrdersController#create", + }, + "serviceName": "opbeans-ruby", + "transactionName": "Api::OrdersController#create", + "transactionType": "request", + "transactionsPerMinute": 0.0166666666666667, + } + `); + + expectSnapshot(lastItem).toMatchInline(` + Object { + "agentName": "nodejs", + "averageResponseTime": 1077989.66666667, + "impact": 100, + "key": Object { + "service.name": "opbeans-node", + "transaction.name": "Process payment", + }, + "serviceName": "opbeans-node", + "transactionName": "Process payment", + "transactionType": "Worker", + "transactionsPerMinute": 0.7, + } + `); + + expectSnapshot(groups).toMatchInline(` + Array [ + Object { + "service.name": "opbeans-ruby", + "transaction.name": "Api::OrdersController#create", + }, + Object { + "service.name": "opbeans-java", + "transaction.name": "APIRestController#products", + }, + Object { + "service.name": "opbeans-java", + "transaction.name": "APIRestController#orders", + }, + Object { + "service.name": "opbeans-java", + "transaction.name": "APIRestController#product", + }, + Object { + "service.name": "opbeans-node", + "transaction.name": "POST /api", + }, + ] + `); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/trace_by_id.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/trace_by_id.spec.ts new file mode 100644 index 0000000000000..5599844e744b0 --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/trace_by_id.spec.ts @@ -0,0 +1,148 @@ +/* + * 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 type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; +import { apm, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { Readable } from 'stream'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); + + const start = new Date('2022-01-01T00:00:00.000Z').getTime(); + const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; + + describe('Trace by ID', () => { + describe('Trace does not exist', () => { + it('handles empty state', async () => { + const response = await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/{traceId}`, + params: { + path: { traceId: 'foo' }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + entryTransactionId: 'foo', + }, + }, + }); + + expect(response.status).to.be(200); + expect(response.body).to.eql({ + traceItems: { + exceedsMax: false, + traceDocs: [], + errorDocs: [], + spanLinksCountById: {}, + traceDocsTotal: 0, + maxTraceItems: 5000, + }, + }); + }); + }); + + describe('Trace exists', () => { + let entryTransactionId: string; + let serviceATraceId: string; + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + const instanceJava = apm + .service({ name: 'synth-apple', environment: 'production', agentName: 'java' }) + .instance('instance-b'); + const events = timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return [ + instanceJava + .transaction({ transactionName: 'GET /apple 🍏' }) + .timestamp(timestamp) + .duration(1000) + .failure() + .errors( + instanceJava + .error({ message: '[ResponseError] index_not_found_exception' }) + .timestamp(timestamp + 50) + ) + .children( + instanceJava + .span({ + spanName: 'get_green_apple_🍏', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .timestamp(timestamp + 50) + .duration(900) + .success() + ), + ]; + }); + const unserialized = Array.from(events); + + const serialized = unserialized.flatMap((event) => event.serialize()); + + entryTransactionId = serialized[0]['transaction.id']!; + serviceATraceId = serialized[0]['trace.id']!; + + await apmSynthtraceEsClient.index(Readable.from(unserialized)); + }); + + after(() => apmSynthtraceEsClient.clean()); + + describe('return trace', () => { + let traces: APIReturnType<'GET /internal/apm/traces/{traceId}'>; + before(async () => { + const response = await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/{traceId}`, + params: { + path: { traceId: serviceATraceId }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + entryTransactionId, + }, + }, + }); + + expect(response.status).to.eql(200); + traces = response.body; + }); + + it('returns some errors', () => { + expect(traces.traceItems.errorDocs.length).to.be.greaterThan(0); + expect(traces.traceItems.errorDocs[0].error.exception?.[0].message).to.eql( + '[ResponseError] index_not_found_exception' + ); + }); + + it('returns some trace docs', () => { + expect(traces.traceItems.traceDocs.length).to.be.greaterThan(0); + expect( + traces.traceItems.traceDocs.map((item) => { + if (item.span && 'name' in item.span) { + return item.span.name; + } + if (item.transaction && 'name' in item.transaction) { + return item.transaction.name; + } + }) + ).to.eql(['GET /apple 🍏', 'get_green_apple_🍏']); + }); + + it('returns entry transaction details', () => { + expect(traces.entryTransaction).to.not.be(undefined); + expect(traces.entryTransaction?.transaction.id).to.equal(entryTransactionId); + expect(traces.entryTransaction?.transaction.name).to.equal('GET /apple 🍏'); + }); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/transaction_details.spec.ts b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/transaction_details.spec.ts new file mode 100644 index 0000000000000..e29006e29989c --- /dev/null +++ b/x-pack/test/api_integration/deployment_agnostic/apis/observability/apm/traces/transaction_details.spec.ts @@ -0,0 +1,124 @@ +/* + * 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 { apm, timerange } from '@kbn/apm-synthtrace-client'; +import expect from '@kbn/expect'; +import { Readable } from 'stream'; +import type { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; +import type { DeploymentAgnosticFtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ApiTest({ getService }: DeploymentAgnosticFtrProviderContext) { + const apmApiClient = getService('apmApi'); + const synthtrace = getService('synthtrace'); + + const start = new Date('2022-01-01T00:00:00.000Z').getTime(); + const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; + + async function fetchTransactionDetails({ + traceId, + transactionId, + }: { + traceId: string; + transactionId: string; + }) { + return await apmApiClient.readUser({ + endpoint: `GET /internal/apm/traces/{traceId}/transactions/{transactionId}`, + params: { + path: { + traceId, + transactionId, + }, + query: { + start: new Date(start).toISOString(), + end: new Date(end).toISOString(), + }, + }, + }); + } + + describe('Transaction details', () => { + describe('when data is not loaded', () => { + it('handles empty state', async () => { + const response = await fetchTransactionDetails({ + traceId: 'foo', + transactionId: 'bar', + }); + + expect(response.status).to.be(200); + expect(response.body).to.eql({}); + }); + }); + + describe('when data is loaded', () => { + let traceId: string; + let transactionId: string; + let apmSynthtraceEsClient: ApmSynthtraceEsClient; + + before(async () => { + apmSynthtraceEsClient = await synthtrace.createApmSynthtraceEsClient(); + + const instanceJava = apm + .service({ name: 'synth-apple', environment: 'production', agentName: 'java' }) + .instance('instance-b'); + const events = timerange(start, end) + .interval('1m') + .rate(1) + .generator((timestamp) => { + return [ + instanceJava + .transaction({ transactionName: 'GET /apple 🍏' }) + .timestamp(timestamp) + .duration(1000) + .failure() + .errors( + instanceJava + .error({ message: '[ResponseError] index_not_found_exception' }) + .timestamp(timestamp + 50) + ) + .children( + instanceJava + .span({ + spanName: 'get_green_apple_🍏', + spanType: 'db', + spanSubtype: 'elasticsearch', + }) + .timestamp(timestamp + 50) + .duration(900) + .success() + ), + ]; + }); + + const unserialized = Array.from(events); + + const entities = unserialized.flatMap((event) => event.serialize()); + + const transaction = entities[0]; + transactionId = transaction?.['transaction.id']!; + traceId = transaction?.['trace.id']!; + + await apmSynthtraceEsClient.index(Readable.from(unserialized)); + }); + + after(() => apmSynthtraceEsClient.clean()); + + describe('transaction details', () => { + let transactionDetails: Awaited>['body']; + before(async () => { + const response = await fetchTransactionDetails({ + traceId, + transactionId, + }); + expect(response.status).to.eql(200); + transactionDetails = response.body; + }); + it('returns transaction details', () => { + expect(transactionDetails.transaction.name).to.eql('GET /apple 🍏'); + }); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts b/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts index bd423762255a5..1cf8493347a6a 100644 --- a/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts +++ b/x-pack/test/api_integration/deployment_agnostic/default_configs/stateful.config.base.ts @@ -124,7 +124,6 @@ export function createStatefulTestConfig) { - if (!traceSamples.length) { - return []; - } - - return Promise.all( - traceSamples.map(async ({ traceId, transactionId }) => { - const response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces/{traceId}`, - params: { - path: { traceId }, - query: { - start: new Date(start).toISOString(), - end: new Date(endWithOffset).toISOString(), - entryTransactionId: transactionId, - }, - }, - }); - return response.body.traceItems.traceDocs; - }) - ); - } - - registry.when('Find traces when traces do not exist', { config: 'basic', archives: [] }, () => { - it('handles empty state', async () => { - const response = await fetchTraceSamples({ - query: '', - type: TraceSearchType.kql, - environment: ENVIRONMENT_ALL.value, - }); - - expect(response.status).to.be(200); - expect(response.body).to.eql({ - traceSamples: [], - }); - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/177543 - registry.when('Find traces when traces exist', { config: 'basic', archives: [] }, () => { - before(() => { - const java = apm - .service({ name: 'java', environment: 'production', agentName: 'java' }) - .instance('java'); - - const node = apm - .service({ name: 'node', environment: 'development', agentName: 'nodejs' }) - .instance('node'); - - const python = apm - .service({ name: 'python', environment: 'production', agentName: 'python' }) - .instance('python'); - - return apmSynthtraceEsClient.index( - timerange(start, end) - .interval('15m') - .rate(1) - .generator((timestamp) => { - return [ - generateTrace(timestamp, [java, node]), - generateTrace(timestamp, [node, java], 'redis'), - generateTrace(timestamp, [python], 'redis'), - generateTrace(timestamp, [python, node, java], 'elasticsearch'), - generateTrace(timestamp, [java, python, node]), - ]; - }) - ); - }); - - describe('when using KQL', () => { - describe('and the query is empty', () => { - it('returns all trace samples', async () => { - const { - body: { traceSamples }, - } = await fetchTraceSamples({ - query: '', - type: TraceSearchType.kql, - environment: 'ENVIRONMENT_ALL', - }); - - expect(traceSamples.length).to.eql(5); - }); - }); - - describe('and query is set', () => { - it('returns the relevant traces', async () => { - const { - body: { traceSamples }, - } = await fetchTraceSamples({ - query: 'span.destination.service.resource:elasticsearch', - type: TraceSearchType.kql, - environment: 'ENVIRONMENT_ALL', - }); - - expect(traceSamples.length).to.eql(1); - }); - }); - }); - - describe('when using EQL', () => { - describe('and the query is invalid', () => { - it.skip('returns a 400', async function () { - try { - await fetchTraceSamples({ - query: '', - type: TraceSearchType.eql, - environment: 'ENVIRONMENT_ALL', - }); - this.fail(); - } catch (error: unknown) { - const apiError = error as ApmApiError; - expect(apiError.res.status).to.eql(400); - } - }); - }); - - describe('and the query is set', () => { - it('returns the correct trace samples for transaction sequences', async () => { - const { - body: { traceSamples }, - } = await fetchTraceSamples({ - query: `sequence by trace.id - [ transaction where service.name == "java" ] - [ transaction where service.name == "node" ]`, - type: TraceSearchType.eql, - environment: 'ENVIRONMENT_ALL', - }); - - const traces = await fetchTraces(traceSamples); - - expect(traces.length).to.eql(2); - - const mapped = traces.map((traceDocs) => { - return sortBy(traceDocs, '@timestamp') - .filter((doc) => doc.processor.event === 'transaction') - .map((doc) => doc.service.name); - }); - - expect(mapped).to.eql([ - ['java', 'node'], - ['java', 'python', 'node'], - ]); - }); - }); - - it('returns the correct trace samples for join sequences', async () => { - const { - body: { traceSamples }, - } = await fetchTraceSamples({ - query: `sequence by trace.id - [ span where service.name == "java" ] by span.id - [ transaction where service.name == "python" ] by parent.id`, - type: TraceSearchType.eql, - environment: 'ENVIRONMENT_ALL', - }); - - const traces = await fetchTraces(traceSamples); - - expect(traces.length).to.eql(1); - - const mapped = traces.map((traceDocs) => { - return sortBy(traceDocs, '@timestamp') - .filter((doc) => doc.processor.event === 'transaction') - .map((doc) => doc.service.name); - }); - - expect(mapped).to.eql([['java', 'python', 'node']]); - }); - }); - - after(() => apmSynthtraceEsClient.clean()); - }); -} diff --git a/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts b/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts deleted file mode 100644 index a428ea9cb2e50..0000000000000 --- a/x-pack/test/apm_api_integration/tests/traces/span_details.spec.ts +++ /dev/null @@ -1,125 +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 { apm, timerange } from '@kbn/apm-synthtrace-client'; -import expect from '@kbn/expect'; -import { Readable } from 'stream'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); - - const start = new Date('2022-01-01T00:00:00.000Z').getTime(); - const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; - - async function fetchSpanDetails({ - traceId, - spanId, - parentTransactionId, - }: { - traceId: string; - spanId: string; - parentTransactionId?: string; - }) { - return await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces/{traceId}/spans/{spanId}`, - params: { - path: { traceId, spanId }, - query: { - parentTransactionId, - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - }, - }, - }); - } - - registry.when('Span details dont exist', { config: 'basic', archives: [] }, () => { - it('handles empty state', async () => { - const response = await fetchSpanDetails({ - traceId: 'foo', - spanId: 'bar', - }); - - expect(response.status).to.be(200); - expect(response.body).to.eql({}); - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/177544 - registry.when('Span details', { config: 'basic', archives: [] }, () => { - let traceId: string; - let spanId: string; - let parentTransactionId: string; - before(async () => { - const instanceJava = apm - .service({ name: 'synth-apple', environment: 'production', agentName: 'java' }) - .instance('instance-b'); - const events = timerange(start, end) - .interval('1m') - .rate(1) - .generator((timestamp) => { - return [ - instanceJava - .transaction({ transactionName: 'GET /apple 🍏' }) - .timestamp(timestamp) - .duration(1000) - .failure() - .errors( - instanceJava - .error({ message: '[ResponseError] index_not_found_exception' }) - .timestamp(timestamp + 50) - ) - .children( - instanceJava - .span({ - spanName: 'get_green_apple_🍏', - spanType: 'db', - spanSubtype: 'elasticsearch', - }) - .timestamp(timestamp + 50) - .duration(900) - .success() - ), - ]; - }); - - const unserialized = Array.from(events); - - const entities = unserialized.flatMap((event) => event.serialize()); - - const span = entities.find((entity) => { - return entity['processor.event'] === 'span'; - }); - spanId = span?.['span.id']!; - parentTransactionId = span?.['parent.id']!; - traceId = span?.['trace.id']!; - - await apmSynthtraceEsClient.index(Readable.from(unserialized)); - }); - - after(() => apmSynthtraceEsClient.clean()); - - describe('span details', () => { - let spanDetails: Awaited>['body']; - before(async () => { - const response = await fetchSpanDetails({ - traceId, - spanId, - parentTransactionId, - }); - expect(response.status).to.eql(200); - spanDetails = response.body; - }); - it('returns span details', () => { - expect(spanDetails.span?.span.name).to.eql('get_green_apple_🍏'); - expect(spanDetails.parentTransaction?.transaction.name).to.eql('GET /apple 🍏'); - }); - }); - }); -} diff --git a/x-pack/test/apm_api_integration/tests/traces/top_traces.spec.ts b/x-pack/test/apm_api_integration/tests/traces/top_traces.spec.ts deleted file mode 100644 index b49133240c865..0000000000000 --- a/x-pack/test/apm_api_integration/tests/traces/top_traces.spec.ts +++ /dev/null @@ -1,140 +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 expect from '@kbn/expect'; -import { sortBy } from 'lodash'; -import archives_metadata from '../../common/fixtures/es_archiver/archives_metadata'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - - const archiveName = 'apm_8.0.0'; - const metadata = archives_metadata[archiveName]; - - // url parameters - const { start, end } = metadata; - - registry.when('Top traces when data is not loaded', { config: 'basic', archives: [] }, () => { - it('handles empty state', async () => { - const response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces`, - params: { - query: { - start, - end, - kuery: '', - environment: 'ENVIRONMENT_ALL', - probability: 1, - }, - }, - }); - - expect(response.status).to.be(200); - expect(response.body.items.length).to.be(0); - }); - }); - - registry.when( - 'Top traces when data is loaded', - { config: 'basic', archives: [archiveName] }, - () => { - let response: any; - before(async () => { - response = await apmApiClient.readUser({ - endpoint: 'GET /internal/apm/traces', - params: { - query: { - start, - end, - kuery: '', - environment: 'ENVIRONMENT_ALL', - probability: 1, - }, - }, - }); - }); - - it('returns the correct status code', async () => { - expect(response.status).to.be(200); - }); - - it('returns the correct number of buckets', async () => { - expectSnapshot(response.body.items.length).toMatchInline(`81`); - }); - - it('returns the correct buckets', async () => { - const sortedItems = sortBy(response.body.items, 'impact'); - - const firstItem = sortedItems[0]; - const lastItem = sortedItems[sortedItems.length - 1]; - - const groups = sortedItems.map((item) => item.key).slice(0, 5); - - expectSnapshot(sortedItems).toMatch(); - - expectSnapshot(firstItem).toMatchInline(` - Object { - "agentName": "java", - "averageResponseTime": 1639, - "impact": 0, - "key": Object { - "service.name": "opbeans-java", - "transaction.name": "DispatcherServlet#doPost", - }, - "serviceName": "opbeans-java", - "transactionName": "DispatcherServlet#doPost", - "transactionType": "request", - "transactionsPerMinute": 0.0333333333333333, - } - `); - - expectSnapshot(lastItem).toMatchInline(` - Object { - "agentName": "dotnet", - "averageResponseTime": 5963775, - "impact": 100, - "key": Object { - "service.name": "opbeans-dotnet", - "transaction.name": "GET Orders/Get", - }, - "serviceName": "opbeans-dotnet", - "transactionName": "GET Orders/Get", - "transactionType": "request", - "transactionsPerMinute": 0.633333333333333, - } - `); - - expectSnapshot(groups).toMatchInline(` - Array [ - Object { - "service.name": "opbeans-java", - "transaction.name": "DispatcherServlet#doPost", - }, - Object { - "service.name": "opbeans-node", - "transaction.name": "POST /api/orders", - }, - Object { - "service.name": "opbeans-node", - "transaction.name": "GET /api/products/:id", - }, - Object { - "service.name": "opbeans-dotnet", - "transaction.name": "POST Orders/Post", - }, - Object { - "service.name": "opbeans-python", - "transaction.name": "GET opbeans.views.product", - }, - ] - `); - }); - } - ); -} diff --git a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts b/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts deleted file mode 100644 index de07f3664104c..0000000000000 --- a/x-pack/test/apm_api_integration/tests/traces/trace_by_id.spec.ts +++ /dev/null @@ -1,145 +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 type { APIReturnType } from '@kbn/apm-plugin/public/services/rest/create_call_apm_api'; -import { apm, timerange } from '@kbn/apm-synthtrace-client'; -import expect from '@kbn/expect'; -import { Readable } from 'stream'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); - - const start = new Date('2022-01-01T00:00:00.000Z').getTime(); - const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; - - registry.when('Trace does not exist', { config: 'basic', archives: [] }, () => { - it('handles empty state', async () => { - const response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces/{traceId}`, - params: { - path: { traceId: 'foo' }, - query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - entryTransactionId: 'foo', - }, - }, - }); - - expect(response.status).to.be(200); - expect(response.body).to.eql({ - traceItems: { - exceedsMax: false, - traceDocs: [], - errorDocs: [], - spanLinksCountById: {}, - traceDocsTotal: 0, - maxTraceItems: 5000, - }, - }); - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/177545 - registry.when('Trace exists', { config: 'basic', archives: [] }, () => { - let entryTransactionId: string; - let serviceATraceId: string; - - before(async () => { - const instanceJava = apm - .service({ name: 'synth-apple', environment: 'production', agentName: 'java' }) - .instance('instance-b'); - const events = timerange(start, end) - .interval('1m') - .rate(1) - .generator((timestamp) => { - return [ - instanceJava - .transaction({ transactionName: 'GET /apple 🍏' }) - .timestamp(timestamp) - .duration(1000) - .failure() - .errors( - instanceJava - .error({ message: '[ResponseError] index_not_found_exception' }) - .timestamp(timestamp + 50) - ) - .children( - instanceJava - .span({ - spanName: 'get_green_apple_🍏', - spanType: 'db', - spanSubtype: 'elasticsearch', - }) - .timestamp(timestamp + 50) - .duration(900) - .success() - ), - ]; - }); - const unserialized = Array.from(events); - - const serialized = unserialized.flatMap((event) => event.serialize()); - - entryTransactionId = serialized[0]['transaction.id']!; - serviceATraceId = serialized[0]['trace.id']!; - - await apmSynthtraceEsClient.index(Readable.from(unserialized)); - }); - - after(() => apmSynthtraceEsClient.clean()); - - describe('return trace', () => { - let traces: APIReturnType<'GET /internal/apm/traces/{traceId}'>; - before(async () => { - const response = await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces/{traceId}`, - params: { - path: { traceId: serviceATraceId }, - query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - entryTransactionId, - }, - }, - }); - - expect(response.status).to.eql(200); - traces = response.body; - }); - - it('returns some errors', () => { - expect(traces.traceItems.errorDocs.length).to.be.greaterThan(0); - expect(traces.traceItems.errorDocs[0].error.exception?.[0].message).to.eql( - '[ResponseError] index_not_found_exception' - ); - }); - - it('returns some trace docs', () => { - expect(traces.traceItems.traceDocs.length).to.be.greaterThan(0); - expect( - traces.traceItems.traceDocs.map((item) => { - if (item.span && 'name' in item.span) { - return item.span.name; - } - if (item.transaction && 'name' in item.transaction) { - return item.transaction.name; - } - }) - ).to.eql(['GET /apple 🍏', 'get_green_apple_🍏']); - }); - - it('returns entry transaction details', () => { - expect(traces.entryTransaction).to.not.be(undefined); - expect(traces.entryTransaction?.transaction.id).to.equal(entryTransactionId); - expect(traces.entryTransaction?.transaction.name).to.equal('GET /apple 🍏'); - }); - }); - }); -} diff --git a/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts b/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts deleted file mode 100644 index 3665bfd8e8ea6..0000000000000 --- a/x-pack/test/apm_api_integration/tests/traces/transaction_details.spec.ts +++ /dev/null @@ -1,119 +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 { apm, timerange } from '@kbn/apm-synthtrace-client'; -import expect from '@kbn/expect'; -import { Readable } from 'stream'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; - -export default function ApiTest({ getService }: FtrProviderContext) { - const registry = getService('registry'); - const apmApiClient = getService('apmApiClient'); - const apmSynthtraceEsClient = getService('apmSynthtraceEsClient'); - - const start = new Date('2022-01-01T00:00:00.000Z').getTime(); - const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; - - async function fetchTransactionDetails({ - traceId, - transactionId, - }: { - traceId: string; - transactionId: string; - }) { - return await apmApiClient.readUser({ - endpoint: `GET /internal/apm/traces/{traceId}/transactions/{transactionId}`, - params: { - path: { - traceId, - transactionId, - }, - query: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - }, - }, - }); - } - - registry.when('Transaction details dont exist', { config: 'basic', archives: [] }, () => { - it('handles empty state', async () => { - const response = await fetchTransactionDetails({ - traceId: 'foo', - transactionId: 'bar', - }); - - expect(response.status).to.be(200); - expect(response.body).to.eql({}); - }); - }); - - // FLAKY: https://github.com/elastic/kibana/issues/177546 - registry.when('Transaction details', { config: 'basic', archives: [] }, () => { - let traceId: string; - let transactionId: string; - before(async () => { - const instanceJava = apm - .service({ name: 'synth-apple', environment: 'production', agentName: 'java' }) - .instance('instance-b'); - const events = timerange(start, end) - .interval('1m') - .rate(1) - .generator((timestamp) => { - return [ - instanceJava - .transaction({ transactionName: 'GET /apple 🍏' }) - .timestamp(timestamp) - .duration(1000) - .failure() - .errors( - instanceJava - .error({ message: '[ResponseError] index_not_found_exception' }) - .timestamp(timestamp + 50) - ) - .children( - instanceJava - .span({ - spanName: 'get_green_apple_🍏', - spanType: 'db', - spanSubtype: 'elasticsearch', - }) - .timestamp(timestamp + 50) - .duration(900) - .success() - ), - ]; - }); - - const unserialized = Array.from(events); - - const entities = unserialized.flatMap((event) => event.serialize()); - - const transaction = entities[0]; - transactionId = transaction?.['transaction.id']!; - traceId = transaction?.['trace.id']!; - - await apmSynthtraceEsClient.index(Readable.from(unserialized)); - }); - - after(() => apmSynthtraceEsClient.clean()); - - describe('transaction details', () => { - let transactionDetails: Awaited>['body']; - before(async () => { - const response = await fetchTransactionDetails({ - traceId, - transactionId, - }); - expect(response.status).to.eql(200); - transactionDetails = response.body; - }); - it('returns transaction details', () => { - expect(transactionDetails.transaction.name).to.eql('GET /apple 🍏'); - }); - }); - }); -} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/apm_api_integration/traces/critical_path.ts b/x-pack/test_serverless/api_integration/test_suites/observability/apm_api_integration/traces/critical_path.ts deleted file mode 100644 index 50aab783b4cf5..0000000000000 --- a/x-pack/test_serverless/api_integration/test_suites/observability/apm_api_integration/traces/critical_path.ts +++ /dev/null @@ -1,99 +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 expect from 'expect'; -import { apm, ApmFields, SynthtraceGenerator, timerange } from '@kbn/apm-synthtrace-client'; -import { compact, uniq } from 'lodash'; -import { Readable } from 'stream'; -import { ApmSynthtraceEsClient } from '@kbn/apm-synthtrace'; -import type { InternalRequestHeader, RoleCredentials } from '../../../../../shared/services'; -import { APMFtrContextProvider } from '../common/services'; - -export default function ({ getService }: APMFtrContextProvider) { - const apmApiClient = getService('apmApiClient'); - const svlUserManager = getService('svlUserManager'); - const svlCommonApi = getService('svlCommonApi'); - const synthtrace = getService('synthtrace'); - - const start = new Date('2022-01-01T00:00:00.000Z').getTime(); - const end = new Date('2022-01-01T00:15:00.000Z').getTime() - 1; - - async function fetchAndBuildCriticalPathTree( - synthtraceEsClient: ApmSynthtraceEsClient, - options: { - fn: () => SynthtraceGenerator; - roleAuthc: RoleCredentials; - internalReqHeader: InternalRequestHeader; - } & ({ serviceName: string; transactionName: string } | {}) - ) { - const { fn, roleAuthc, internalReqHeader } = options; - - const generator = fn(); - - const unserialized = Array.from(generator); - const serialized = unserialized.flatMap((event) => event.serialize()); - const traceIds = compact(uniq(serialized.map((event) => event['trace.id']))); - - await synthtraceEsClient.index(Readable.from(unserialized)); - - return apmApiClient.slsUser({ - endpoint: 'POST /internal/apm/traces/aggregated_critical_path', - params: { - body: { - start: new Date(start).toISOString(), - end: new Date(end).toISOString(), - traceIds, - serviceName: 'serviceName' in options ? options.serviceName : null, - transactionName: 'transactionName' in options ? options.transactionName : null, - }, - }, - roleAuthc, - internalReqHeader, - }); - } - - describe('APM Aggregated critical path', () => { - let roleAuthc: RoleCredentials; - let internalReqHeader: InternalRequestHeader; - let synthtraceEsClient: ApmSynthtraceEsClient; - - before(async () => { - synthtraceEsClient = await synthtrace.createSynthtraceEsClient(); - internalReqHeader = svlCommonApi.getInternalRequestHeader(); - roleAuthc = await svlUserManager.createM2mApiKeyWithRoleScope('admin'); - }); - - after(async () => { - await svlUserManager.invalidateM2mApiKeyWithRoleScope(roleAuthc); - return synthtraceEsClient.clean(); - }); - - it('returns service map elements', async () => { - const java = apm - .service({ name: 'java', environment: 'production', agentName: 'java' }) - .instance('java'); - - const duration = 1000; - const rate = 10; - - const response = await fetchAndBuildCriticalPathTree(synthtraceEsClient, { - fn: () => - timerange(start, end) - .interval('15m') - .rate(rate) - .generator((timestamp) => { - return java.transaction('GET /api').timestamp(timestamp).duration(duration); - }), - roleAuthc, - internalReqHeader, - }); - - expect(response.status).toBe(200); - expect(response.body.criticalPath).not.toBeUndefined(); - }); - }); -} diff --git a/x-pack/test_serverless/api_integration/test_suites/observability/index.ts b/x-pack/test_serverless/api_integration/test_suites/observability/index.ts index 89543982f2d44..d3d8d4805695a 100644 --- a/x-pack/test_serverless/api_integration/test_suites/observability/index.ts +++ b/x-pack/test_serverless/api_integration/test_suites/observability/index.ts @@ -12,7 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { this.tags(['esGate']); loadTestFile(require.resolve('./apm_api_integration/feature_flags.ts')); - loadTestFile(require.resolve('./apm_api_integration/traces/critical_path')); loadTestFile(require.resolve('./cases')); loadTestFile(require.resolve('./synthetics')); loadTestFile(require.resolve('./dataset_quality_api_integration'));