Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/observability/client_spec.js')
-rw-r--r--spec/frontend/observability/client_spec.js233
1 files changed, 176 insertions, 57 deletions
diff --git a/spec/frontend/observability/client_spec.js b/spec/frontend/observability/client_spec.js
index 056175eac07..68a53131539 100644
--- a/spec/frontend/observability/client_spec.js
+++ b/spec/frontend/observability/client_spec.js
@@ -12,7 +12,8 @@ describe('buildClient', () => {
const tracingUrl = 'https://example.com/tracing';
const provisioningUrl = 'https://example.com/provisioning';
-
+ const servicesUrl = 'https://example.com/services';
+ const operationsUrl = 'https://example.com/services/$SERVICE_NAME$/operations';
const FETCHING_TRACES_ERROR = 'traces are missing/invalid in the response';
beforeEach(() => {
@@ -22,6 +23,8 @@ describe('buildClient', () => {
client = buildClient({
tracingUrl,
provisioningUrl,
+ servicesUrl,
+ operationsUrl,
});
});
@@ -29,6 +32,27 @@ describe('buildClient', () => {
axiosMock.restore();
});
+ describe('buildClient', () => {
+ it('rejects if params are missing', () => {
+ const e = new Error(
+ 'missing required params. provisioningUrl, tracingUrl, servicesUrl, operationsUrl are required',
+ );
+ expect(() =>
+ buildClient({ tracingUrl: 'test', servicesUrl: 'test', operationsUrl: 'test' }),
+ ).toThrow(e);
+ expect(() =>
+ buildClient({ provisioningUrl: 'test', servicesUrl: 'test', operationsUrl: 'test' }),
+ ).toThrow(e);
+ expect(() =>
+ buildClient({ provisioningUrl: 'test', tracingUrl: 'test', operationsUrl: 'test' }),
+ ).toThrow(e);
+ expect(() =>
+ buildClient({ provisioningUrl: 'test', tracingUrl: 'test', servicesUrl: 'test' }),
+ ).toThrow(e);
+ expect(() => buildClient({})).toThrow(e);
+ });
+ });
+
describe('isTracingEnabled', () => {
it('returns true if requests succeedes', async () => {
axiosMock.onGet(provisioningUrl).reply(200, {
@@ -145,18 +169,18 @@ describe('buildClient', () => {
describe('fetchTraces', () => {
it('fetches traces from the tracing URL', async () => {
- const mockTraces = [
- {
- trace_id: 'trace-1',
- duration_nano: 3000,
- spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }],
- },
- { trace_id: 'trace-2', duration_nano: 3000, spans: [{ duration_nano: 2000 }] },
- ];
-
- axiosMock.onGet(tracingUrl).reply(200, {
- traces: mockTraces,
- });
+ const mockResponse = {
+ traces: [
+ {
+ trace_id: 'trace-1',
+ duration_nano: 3000,
+ spans: [{ duration_nano: 1000 }, { duration_nano: 2000 }],
+ },
+ { trace_id: 'trace-2', duration_nano: 3000, spans: [{ duration_nano: 2000 }] },
+ ],
+ };
+
+ axiosMock.onGet(tracingUrl).reply(200, mockResponse);
const result = await client.fetchTraces();
@@ -165,7 +189,7 @@ describe('buildClient', () => {
withCredentials: true,
params: new URLSearchParams(),
});
- expect(result).toEqual(mockTraces);
+ expect(result).toEqual(mockResponse);
});
it('rejects if traces are missing', async () => {
@@ -197,28 +221,42 @@ describe('buildClient', () => {
expect(getQueryParam()).toBe('');
});
+ it('appends page_token if specified', async () => {
+ await client.fetchTraces({ pageToken: 'page-token' });
+
+ expect(getQueryParam()).toBe('page_token=page-token');
+ });
+
+ it('appends page_size if specified', async () => {
+ await client.fetchTraces({ pageSize: 10 });
+
+ expect(getQueryParam()).toBe('page_size=10');
+ });
+
it('converts filter to proper query params', async () => {
await client.fetchTraces({
- durationMs: [
- { operator: '>', value: '100' },
- { operator: '<', value: '1000' },
- ],
- operation: [
- { operator: '=', value: 'op' },
- { operator: '!=', value: 'not-op' },
- ],
- serviceName: [
- { operator: '=', value: 'service' },
- { operator: '!=', value: 'not-service' },
- ],
- period: [{ operator: '=', value: '5m' }],
- traceId: [
- { operator: '=', value: 'trace-id' },
- { operator: '!=', value: 'not-trace-id' },
- ],
+ filters: {
+ durationMs: [
+ { operator: '>', value: '100' },
+ { operator: '<', value: '1000' },
+ ],
+ operation: [
+ { operator: '=', value: 'op' },
+ { operator: '!=', value: 'not-op' },
+ ],
+ serviceName: [
+ { operator: '=', value: 'service' },
+ { operator: '!=', value: 'not-service' },
+ ],
+ period: [{ operator: '=', value: '5m' }],
+ traceId: [
+ { operator: '=', value: 'trace-id' },
+ { operator: '!=', value: 'not-trace-id' },
+ ],
+ },
});
expect(getQueryParam()).toBe(
- 'gt[duration_nano]=100000&lt[duration_nano]=1000000' +
+ 'gt[duration_nano]=100000000&lt[duration_nano]=1000000000' +
'&operation=op&not[operation]=not-op' +
'&service_name=service&not[service_name]=not-service' +
'&period=5m' +
@@ -228,17 +266,21 @@ describe('buildClient', () => {
it('handles repeated params', async () => {
await client.fetchTraces({
- operation: [
- { operator: '=', value: 'op' },
- { operator: '=', value: 'op2' },
- ],
+ filters: {
+ operation: [
+ { operator: '=', value: 'op' },
+ { operator: '=', value: 'op2' },
+ ],
+ },
});
expect(getQueryParam()).toBe('operation=op&operation=op2');
});
it('ignores unsupported filters', async () => {
await client.fetchTraces({
- unsupportedFilter: [{ operator: '=', value: 'foo' }],
+ filters: {
+ unsupportedFilter: [{ operator: '=', value: 'foo' }],
+ },
});
expect(getQueryParam()).toBe('');
@@ -246,8 +288,10 @@ describe('buildClient', () => {
it('ignores empty filters', async () => {
await client.fetchTraces({
- durationMs: null,
- traceId: undefined,
+ filters: {
+ durationMs: null,
+ traceId: undefined,
+ },
});
expect(getQueryParam()).toBe('');
@@ -255,28 +299,103 @@ describe('buildClient', () => {
it('ignores unsupported operators', async () => {
await client.fetchTraces({
- durationMs: [
- { operator: '*', value: 'foo' },
- { operator: '=', value: 'foo' },
- { operator: '!=', value: 'foo' },
- ],
- operation: [
- { operator: '>', value: 'foo' },
- { operator: '<', value: 'foo' },
- ],
- serviceName: [
- { operator: '>', value: 'foo' },
- { operator: '<', value: 'foo' },
- ],
- period: [{ operator: '!=', value: 'foo' }],
- traceId: [
- { operator: '>', value: 'foo' },
- { operator: '<', value: 'foo' },
- ],
+ filters: {
+ durationMs: [
+ { operator: '*', value: 'foo' },
+ { operator: '=', value: 'foo' },
+ { operator: '!=', value: 'foo' },
+ ],
+ operation: [
+ { operator: '>', value: 'foo' },
+ { operator: '<', value: 'foo' },
+ ],
+ serviceName: [
+ { operator: '>', value: 'foo' },
+ { operator: '<', value: 'foo' },
+ ],
+ period: [{ operator: '!=', value: 'foo' }],
+ traceId: [
+ { operator: '>', value: 'foo' },
+ { operator: '<', value: 'foo' },
+ ],
+ },
});
expect(getQueryParam()).toBe('');
});
});
});
+
+ describe('fetchServices', () => {
+ it('fetches services from the services URL', async () => {
+ const mockResponse = {
+ services: [{ name: 'service-1' }, { name: 'service-2' }],
+ };
+
+ axiosMock.onGet(servicesUrl).reply(200, mockResponse);
+
+ const result = await client.fetchServices();
+
+ expect(axios.get).toHaveBeenCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith(servicesUrl, {
+ withCredentials: true,
+ });
+ expect(result).toEqual(mockResponse.services);
+ });
+
+ it('rejects if services are missing', async () => {
+ axiosMock.onGet(servicesUrl).reply(200, {});
+
+ const e = 'failed to fetch services. invalid response';
+ await expect(client.fetchServices()).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+ });
+
+ describe('fetchOperations', () => {
+ const serviceName = 'test-service';
+ const parsedOperationsUrl = `https://example.com/services/${serviceName}/operations`;
+
+ it('fetches operations from the operations URL', async () => {
+ const mockResponse = {
+ operations: [{ name: 'operation-1' }, { name: 'operation-2' }],
+ };
+
+ axiosMock.onGet(parsedOperationsUrl).reply(200, mockResponse);
+
+ const result = await client.fetchOperations(serviceName);
+
+ expect(axios.get).toHaveBeenCalledTimes(1);
+ expect(axios.get).toHaveBeenCalledWith(parsedOperationsUrl, {
+ withCredentials: true,
+ });
+ expect(result).toEqual(mockResponse.operations);
+ });
+
+ it('rejects if serviceName is missing', async () => {
+ const e = 'fetchOperations() - serviceName is required.';
+ await expect(client.fetchOperations()).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+
+ it('rejects if operationUrl does not contain $SERVICE_NAME$', async () => {
+ client = buildClient({
+ tracingUrl,
+ provisioningUrl,
+ servicesUrl,
+ operationsUrl: 'something',
+ });
+ const e = 'fetchOperations() - operationsUrl must contain $SERVICE_NAME$';
+ await expect(client.fetchOperations(serviceName)).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+
+ it('rejects if operations are missing', async () => {
+ axiosMock.onGet(parsedOperationsUrl).reply(200, {});
+
+ const e = 'failed to fetch operations. invalid response';
+ await expect(client.fetchOperations(serviceName)).rejects.toThrow(e);
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error(e));
+ });
+ });
});