Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 27 additions & 32 deletions x-pack/test/api_integration/services/usage_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,49 +5,44 @@
* 2.0.
*/

import { TelemetryCollectionManagerPlugin } from '@kbn/telemetry-collection-manager-plugin/server/plugin';
import { UsageStatsPayload } from '@kbn/telemetry-collection-manager-plugin/server';
import { FtrProviderContext } from '../ftr_provider_context';

export interface UsageStatsPayloadTestFriendly extends UsageStatsPayload {
// Overwriting the `object` type to a more test-friendly type
stack_stats: Record<string, any>;
}

export function UsageAPIProvider({ getService }: FtrProviderContext) {
const supertest = getService('supertest');
const supertestNoAuth = getService('supertestWithoutAuth');

return {
async getUsageStatsNoAuth(): Promise<undefined> {
const { body } = await supertestNoAuth
.get('/api/stats?extended=true')
.set('kbn-xsrf', 'xxx')
.expect(401);
return body.usage;
},

/**
* Public stats API: it returns the usage in camelCase format
*/
async getUsageStats() {
const { body } = await supertest
.get('/api/stats?extended=true')
.set('kbn-xsrf', 'xxx')
.expect(200);
return body.usage;
},
Comment on lines 24 to 33
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the API as it not recommended for its use to fetch usage.

async function getTelemetryStats(payload: {
unencrypted: true;
refreshCache?: boolean;
}): Promise<Array<{ clusterUuid: string; stats: UsageStatsPayloadTestFriendly }>>;
async function getTelemetryStats(payload: {
unencrypted: false;
refreshCache?: boolean;
}): Promise<Array<{ clusterUuid: string; stats: string }>>;
async function getTelemetryStats(payload: {
unencrypted?: boolean;
refreshCache?: boolean;
}): Promise<Array<{ clusterUuid: string; stats: UsageStatsPayloadTestFriendly | string }>> {
const { body } = await supertest
.post('/api/telemetry/v2/clusters/_stats')
.set('kbn-xsrf', 'xxx')
.send({ refreshCache: true, ...payload })
.expect(200);
return body;
}

return {
/**
* Retrieve the stats via the private telemetry API:
* It returns the usage in as a string encrypted blob or the plain payload if `unencrypted: false`
*
* @param payload Request parameters to retrieve the telemetry stats
*/
async getTelemetryStats(payload: {
unencrypted?: boolean;
refreshCache?: boolean;
}): Promise<ReturnType<TelemetryCollectionManagerPlugin['getStats']>> {
const { body } = await supertest
.post('/api/telemetry/v2/clusters/_stats')
.set('kbn-xsrf', 'xxx')
.send({ refreshCache: true, ...payload })
.expect(200);
return body;
},
getTelemetryStats,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
`--xpack.reporting.capture.maxAttempts=1`,
`--xpack.reporting.csv.maxSizeBytes=6000`,
'--xpack.reporting.roles.enabled=false', // Reporting access control is implemented by sub-feature application privileges
// for testing set buffer duration to 0 to immediately flush counters into saved objects.
'--usageCollection.usageCounters.bufferDuration=0',
],
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import expect from '@kbn/expect';
import { createPdfV2Params, createPngV2Params } from '..';
import { FtrProviderContext } from '../../ftr_provider_context';
import { UsageStatsPayloadTestFriendly } from '../../../api_integration/services/usage_api';

// eslint-disable-next-line import/no-default-export
export default function ({ getService }: FtrProviderContext) {
Expand Down Expand Up @@ -35,10 +36,11 @@ export default function ({ getService }: FtrProviderContext) {
describe('server', function () {
this.tags('skipCloud');
it('configuration settings of the tests_server', async () => {
const usage = await usageAPI.getUsageStats();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if this will help resolve #134517

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried unskipping it, but it was still flaky. I can try to debug it on a follow up PR. I wouldn't like to delay this one further because it's blocking a community PR 🧡

expect(usage.kibana_config_usage.xpack_reporting_capture_max_attempts).to.be(1);
expect(usage.kibana_config_usage.xpack_reporting_csv_max_size_bytes).to.be(6000);
expect(usage.kibana_config_usage.xpack_reporting_roles_enabled).to.be(false);
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
const usage = stats.stack_stats.kibana.plugins;
expect(usage.kibana_config_usage['xpack.reporting.capture.maxAttempts']).to.be(1);
expect(usage.kibana_config_usage['xpack.reporting.csv.maxSizeBytes']).to.be(6000);
expect(usage.kibana_config_usage['xpack.reporting.roles.enabled']).to.be(false);
});
});

Expand All @@ -52,12 +54,12 @@ export default function ({ getService }: FtrProviderContext) {
DIAG_SCREENSHOT = '/api/reporting/diagnose/screenshot',
}

let initialStats: any;
let stats: any;
let initialStats: UsageStatsPayloadTestFriendly;
let stats: UsageStatsPayloadTestFriendly;
const CALL_COUNT = 3;

before('call APIs', async () => {
initialStats = await usageAPI.getUsageStats();
[{ stats: initialStats }] = await usageAPI.getTelemetryStats({ unencrypted: true });

await Promise.all(
Object.keys(paths).map(async (key) => {
Expand All @@ -73,30 +75,36 @@ export default function ({ getService }: FtrProviderContext) {
await waitOnAggregation();

// determine the result usage count
stats = await usageAPI.getUsageStats();
[{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
});

it('job listing', async () => {
expect(getUsageCount(initialStats, `get ${paths.LIST}`)).to.be(0);
expect(getUsageCount(stats, `get ${paths.LIST}`)).to.be(CALL_COUNT);
const initialCount = getUsageCount(initialStats, `get ${paths.LIST}`);
expect(getUsageCount(stats, `get ${paths.LIST}`)).to.be(CALL_COUNT + initialCount);
});

it('job count', async () => {
expect(getUsageCount(initialStats, `get ${paths.COUNT}`)).to.be(0);
expect(getUsageCount(stats, `get ${paths.COUNT}`)).to.be(CALL_COUNT);
const initialCount = getUsageCount(initialStats, `get ${paths.COUNT}`);
expect(getUsageCount(stats, `get ${paths.COUNT}`)).to.be(CALL_COUNT + initialCount);
});

it('job info', async () => {
expect(
getUsageCount(initialStats, `get /api/reporting/jobs/info/{docId}:printable_pdf`)
).to.be(0);
const initialCount = getUsageCount(
initialStats,
`get /api/reporting/jobs/info/{docId}:printable_pdf`
);
expect(getUsageCount(stats, `get /api/reporting/jobs/info/{docId}:printable_pdf`)).to.be(
CALL_COUNT
CALL_COUNT + initialCount
);
});
});

describe('downloading and deleting', () => {
let initialStats: UsageStatsPayloadTestFriendly;
before('gather initial stats', async () => {
[{ stats: initialStats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
});

it('downloading', async () => {
try {
await Promise.all([
Expand All @@ -119,12 +127,14 @@ export default function ({ getService }: FtrProviderContext) {
log.info(`waiting on aggregation completed.`);

log.info(`calling getUsageStats...`);
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
const initialCount = getUsageCount(
initialStats,
`get /api/reporting/jobs/download/{docId}:printable_pdf`
);
expect(
getUsageCount(
await usageAPI.getUsageStats(),
`get /api/reporting/jobs/download/{docId}:printable_pdf`
)
).to.be(3);
getUsageCount(stats, `get /api/reporting/jobs/download/{docId}:printable_pdf`)
).to.be(3 + initialCount);
});

it('deleting', async () => {
Expand All @@ -145,17 +155,19 @@ export default function ({ getService }: FtrProviderContext) {
log.info(`waiting on aggregation completed.`);

log.info(`calling getUsageStats...`);
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
const initialCount = getUsageCount(
initialStats,
`delete /api/reporting/jobs/delete/{docId}:csv_searchsource`
);
expect(
getUsageCount(
await usageAPI.getUsageStats(),
`delete /api/reporting/jobs/delete/{docId}:csv_searchsource`
)
).to.be(1);
getUsageCount(stats, `delete /api/reporting/jobs/delete/{docId}:csv_searchsource`)
).to.be(1 + initialCount);
});
});

describe('API counters: job generation', () => {
let stats: any;
let stats: UsageStatsPayloadTestFriendly;

before(async () => {
// call generation APIs
Expand All @@ -172,7 +184,7 @@ export default function ({ getService }: FtrProviderContext) {

await waitOnAggregation();

stats = await usageAPI.getUsageStats();
[{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
});

it('PNG', async () => {
Expand Down Expand Up @@ -201,10 +213,13 @@ export default function ({ getService }: FtrProviderContext) {
});
};

const getUsageCount = (checkUsage: any, counterName: string): number => {
const getUsageCount = (
checkUsage: UsageStatsPayloadTestFriendly,
counterName: string
): number => {
return (
checkUsage.usage_counters.daily_events.find(
(item: any) => item.counter_name === counterName
checkUsage.stack_stats.kibana.plugins.usage_counters.dailyEvents.find(
(item: any) => item.counterName === counterName
)?.total || 0
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export default function ({ getService }: FtrProviderContext) {
describe('from archive data', () => {
it('generated from 6.2', async () => {
await esArchiver.load('x-pack/test/functional/es_archives/reporting/bwc/6_2');
const usage = await usageAPI.getUsageStats();
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
const usage = stats.stack_stats.kibana.plugins.reporting;

reportingAPI.expectRecentJobTypeTotalStats(usage, 'printable_pdf', 0);
reportingAPI.expectAllTimeJobTypeTotalStats(usage, 'printable_pdf', 7);
Expand All @@ -36,7 +37,8 @@ export default function ({ getService }: FtrProviderContext) {

it('generated from 6.3', async () => {
await esArchiver.load('x-pack/test/functional/es_archives/reporting/bwc/6_3');
const usage = await usageAPI.getUsageStats();
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
const usage = stats.stack_stats.kibana.plugins.reporting;

reportingAPI.expectRecentJobTypeTotalStats(usage, 'printable_pdf', 0);
reportingAPI.expectRecentPdfAppStats(usage, 'visualization', 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,8 @@
*/

import expect from '@kbn/expect';
import { ReportingUsageType } from '@kbn/reporting-plugin/server/usage/types';
import { FtrProviderContext } from '../../ftr_provider_context';
import { UsageStats } from '../../services/usage';

type ReportingUsage = UsageStats['reporting'];
interface ReportingUsageApiResponse {
all: ReportingUsage['_all'];
csv_searchsource: ReportingUsage['csv_searchsource'];
pngv_2: ReportingUsage['PNGV2'];
printable_pdf_v_2: ReportingUsage['printable_pdf_v2'];
}

const DATA_ARCHIVE_PATH = 'x-pack/test/functional/es_archives/reporting/errors';

Expand All @@ -26,12 +18,13 @@ export default function ({ getService }: FtrProviderContext) {
const usageAPI = getService('usageAPI');

describe(`error codes`, () => {
let reporting: ReportingUsageApiResponse;
let reporting: ReportingUsageType;

before(async () => {
await reportingAPI.deleteAllReports();
await esArchiver.load(DATA_ARCHIVE_PATH);
({ reporting } = await usageAPI.getUsageStats());
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
reporting = stats.stack_stats.kibana.plugins.reporting;
});

after(async () => {
Expand All @@ -40,10 +33,10 @@ export default function ({ getService }: FtrProviderContext) {
});

it('includes error code statistics', async () => {
expect(reporting.all).equal(3);
expect(reporting._all).equal(3);
expectSnapshot(
['csv_searchsource', 'pngv_2', 'printable_pdf_v_2'].map((k) => {
const field = reporting[k as keyof Omit<ReportingUsageApiResponse, 'all'>];
(['csv_searchsource', 'PNGV2', 'printable_pdf_v2'] as const).map((k) => {
const field = reporting[k];
return { key: k, error_codes: field.error_codes, total: field.total };
})
).toMatchInline(`
Expand All @@ -55,15 +48,15 @@ export default function ({ getService }: FtrProviderContext) {
},
Object {
"error_codes": undefined,
"key": "pngv_2",
"key": "PNGV2",
"total": 0,
},
Object {
"error_codes": Object {
"queue_timeout_error": 1,
"unknown_error": 1,
},
"key": "printable_pdf_v_2",
"key": "printable_pdf_v2",
"total": 3,
},
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
*/

import expect from '@kbn/expect';
import { ReportingUsageType } from '@kbn/reporting-plugin/server/usage/types';
import { FtrProviderContext } from '../../ftr_provider_context';
import { UsageStats } from '../../services/usage';

// eslint-disable-next-line import/no-default-export
export default function ({ getService }: FtrProviderContext) {
Expand All @@ -16,18 +16,19 @@ export default function ({ getService }: FtrProviderContext) {
const usageAPI = getService('usageAPI');

describe('initial state', () => {
let usage: UsageStats;
let usage: ReportingUsageType;

before(async () => {
await retry.try(async () => {
// use retry for stability - usage API could return 503
usage = (await usageAPI.getUsageStats()) as UsageStats;
const [{ stats }] = await usageAPI.getTelemetryStats({ unencrypted: true });
usage = stats.stack_stats.kibana.plugins.reporting;
});
});

it('shows reporting as available and enabled', async () => {
expect(usage.reporting.available).to.be(true);
expect(usage.reporting.enabled).to.be(true);
expect(usage.available).to.be(true);
expect(usage.enabled).to.be(true);
});

it('all counts are 0', async () => {
Expand Down
Loading