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
153 changes: 73 additions & 80 deletions src/core/server/status/get_summary_status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,93 +81,86 @@ describe('getSummaryStatus', () => {
});

describe('summary', () => {
describe('when a single service is at highest level', () => {
it('returns all information about that single service', () => {
expect(
getSummaryStatus(
Object.entries({
s1: degraded,
s2: {
level: ServiceStatusLevels.unavailable,
summary: 'Lorem ipsum',
meta: {
custom: { data: 'here' },
},
it('returns correct summary when a single service is affected', () => {
expect(
getSummaryStatus(
Object.entries({
s1: degraded,
s2: {
level: ServiceStatusLevels.unavailable,
summary: 'Lorem ipsum',
meta: {
custom: { data: 'here' },
},
})
)
).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '[s2]: Lorem ipsum',
detail: 'See the status page for more information',
meta: {
affectedServices: ['s2'],
},
});
},
})
)
).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '1 service is unavailable: s2',
detail: 'See the status page for more information',
meta: {
affectedServices: ['s2'],
},
});
});

it('allows the single service to override the detail and documentationUrl fields', () => {
expect(
getSummaryStatus(
Object.entries({
s1: degraded,
s2: {
level: ServiceStatusLevels.unavailable,
summary: 'Lorem ipsum',
detail: 'Vivamus pulvinar sem ac luctus ultrices.',
documentationUrl: 'http://helpmenow.com/problem1',
meta: {
custom: { data: 'here' },
},
it('returns correct summary when multiple services are affected', () => {
expect(
getSummaryStatus(
Object.entries({
s1: degraded,
s2: {
level: ServiceStatusLevels.unavailable,
summary: 'Lorem ipsum',
detail: 'Vivamus pulvinar sem ac luctus ultrices.',
documentationUrl: 'http://helpmenow.com/problem1',
meta: {
custom: { data: 'here' },
},
},
s3: {
level: ServiceStatusLevels.unavailable,
summary: 'Proin mattis',
detail: 'Nunc quis nulla at mi lobortis pretium.',
documentationUrl: 'http://helpmenow.com/problem2',
meta: {
other: { data: 'over there' },
},
})
)
).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '[s2]: Lorem ipsum',
detail: 'Vivamus pulvinar sem ac luctus ultrices.',
documentationUrl: 'http://helpmenow.com/problem1',
meta: {
affectedServices: ['s2'],
},
});
},
})
)
).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '2 services are unavailable: s2, s3',
detail: 'See the status page for more information',
meta: {
affectedServices: ['s2', 's3'],
},
});
});

describe('when multiple services is at highest level', () => {
it('returns aggregated information about the affected services', () => {
expect(
getSummaryStatus(
Object.entries({
s1: degraded,
s2: {
level: ServiceStatusLevels.unavailable,
summary: 'Lorem ipsum',
detail: 'Vivamus pulvinar sem ac luctus ultrices.',
documentationUrl: 'http://helpmenow.com/problem1',
meta: {
custom: { data: 'here' },
},
},
s3: {
level: ServiceStatusLevels.unavailable,
summary: 'Proin mattis',
detail: 'Nunc quis nulla at mi lobortis pretium.',
documentationUrl: 'http://helpmenow.com/problem2',
meta: {
other: { data: 'over there' },
},
},
})
)
).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '[2] services are unavailable',
detail: 'See the status page for more information',
meta: {
affectedServices: ['s2', 's3'],
},
});
it('returns correct summary more than `maxServices` services are affected', () => {
expect(
getSummaryStatus(
Object.entries({
s1: degraded,
s2: available,
s3: degraded,
s4: degraded,
s5: degraded,
s6: available,
s7: degraded,
}),
{ maxServices: 3 }
)
).toEqual({
level: ServiceStatusLevels.degraded,
summary: '5 services are degraded: s1, s3, s4 and 2 other(s)',
detail: 'See the status page for more information',
meta: {
affectedServices: ['s1', 's3', 's4', 's5', 's7'],
},
});
});
});
Expand Down
40 changes: 25 additions & 15 deletions src/core/server/status/get_summary_status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { ServiceStatus, ServiceStatusLevels, ServiceStatusLevel } from './types'

/**
* Returns a single {@link ServiceStatus} that summarizes the most severe status level from a group of statuses.
* @param statuses
*/
export const getSummaryStatus = (
statuses: Array<[string, ServiceStatus]>,
{ allAvailableSummary = `All services are available` }: { allAvailableSummary?: string } = {}
{
allAvailableSummary = `All services are available`,
maxServices = 3,
}: { allAvailableSummary?: string; maxServices?: number } = {}
): ServiceStatus => {
const { highestLevel, highestStatuses } = highestLevelSummary(statuses);

Expand All @@ -23,30 +25,38 @@ export const getSummaryStatus = (
level: ServiceStatusLevels.available,
summary: allAvailableSummary,
};
} else if (highestStatuses.length === 1) {
const [serviceName, status] = highestStatuses[0]! as [string, ServiceStatus];
return {
...status,
summary: `[${serviceName}]: ${status.summary!}`,
// TODO: include URL to status page
detail: status.detail ?? `See the status page for more information`,
meta: {
affectedServices: [serviceName],
},
};
} else {
const affectedServices = highestStatuses.map(([serviceName]) => serviceName);
return {
level: highestLevel,
summary: `[${highestStatuses.length}] services are ${highestLevel.toString()}`,
summary: getSummaryContent(affectedServices, highestLevel, maxServices),
// TODO: include URL to status page
detail: `See the status page for more information`,
meta: {
affectedServices: highestStatuses.map(([serviceName]) => serviceName),
affectedServices,
},
};
}
};

const getSummaryContent = (
affectedServices: string[],
statusLevel: ServiceStatusLevel,
maxServices: number
): string => {
const serviceCount = affectedServices.length;
if (serviceCount === 1) {
return `1 service is ${statusLevel.toString()}: ${affectedServices[0]}`;
} else if (serviceCount > maxServices) {
const exceedingCount = serviceCount - maxServices;
return `${serviceCount} services are ${statusLevel.toString()}: ${affectedServices
.slice(0, maxServices)
.join(', ')} and ${exceedingCount} other(s)`;
} else {
return `${serviceCount} services are ${statusLevel.toString()}: ${affectedServices.join(', ')}`;
}
};

type StatusPair = [string, ServiceStatus];

const highestLevelSummary = (
Expand Down
32 changes: 16 additions & 16 deletions src/core/server/status/plugins_status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('PluginStatusService', () => {
});
expect(await serviceDegraded.getDerivedStatus$('a').pipe(first()).toPromise()).toEqual({
level: ServiceStatusLevels.degraded,
summary: '[savedObjects]: savedObjects degraded',
summary: '1 service is degraded: savedObjects',
detail: 'See the status page for more information',
meta: expect.any(Object),
});
Expand All @@ -84,7 +84,7 @@ describe('PluginStatusService', () => {
});
expect(await serviceCritical.getDerivedStatus$('a').pipe(first()).toPromise()).toEqual({
level: ServiceStatusLevels.critical,
summary: '[elasticsearch]: elasticsearch critical',
summary: '1 service is critical: elasticsearch',
detail: 'See the status page for more information',
meta: expect.any(Object),
});
Expand All @@ -95,7 +95,7 @@ describe('PluginStatusService', () => {
service.set('a', of({ level: ServiceStatusLevels.degraded, summary: 'a is degraded' }));
expect(await service.getDerivedStatus$('b').pipe(first()).toPromise()).toEqual({
level: ServiceStatusLevels.degraded,
summary: '[2] services are degraded',
summary: '2 services are degraded: savedObjects, a',
detail: 'See the status page for more information',
meta: expect.any(Object),
});
Expand All @@ -106,7 +106,7 @@ describe('PluginStatusService', () => {
service.set('a', of({ level: ServiceStatusLevels.unavailable, summary: 'a is not working' }));
expect(await service.getDerivedStatus$('b').pipe(first()).toPromise()).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '[a]: a is not working',
summary: '1 service is unavailable: a',
detail: 'See the status page for more information',
meta: expect.any(Object),
});
Expand All @@ -120,7 +120,7 @@ describe('PluginStatusService', () => {
service.set('a', of({ level: ServiceStatusLevels.unavailable, summary: 'a is not working' }));
expect(await service.getDerivedStatus$('b').pipe(first()).toPromise()).toEqual({
level: ServiceStatusLevels.critical,
summary: '[elasticsearch]: elasticsearch critical',
summary: '1 service is critical: elasticsearch',
detail: 'See the status page for more information',
meta: expect.any(Object),
});
Expand All @@ -132,7 +132,7 @@ describe('PluginStatusService', () => {
service.set('b', of({ level: ServiceStatusLevels.unavailable, summary: 'b is not working' }));
expect(await service.getDerivedStatus$('c').pipe(first()).toPromise()).toEqual({
level: ServiceStatusLevels.unavailable,
summary: '[b]: b is not working',
summary: '1 service is unavailable: b',
detail: 'See the status page for more information',
meta: expect.any(Object),
});
Expand Down Expand Up @@ -166,19 +166,19 @@ describe('PluginStatusService', () => {
expect(await serviceDegraded.getAll$().pipe(first()).toPromise()).toEqual({
a: {
level: ServiceStatusLevels.degraded,
summary: '[savedObjects]: savedObjects degraded',
summary: '1 service is degraded: savedObjects',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
b: {
level: ServiceStatusLevels.degraded,
summary: '[savedObjects]: savedObjects degraded',
summary: '1 service is degraded: savedObjects',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
c: {
level: ServiceStatusLevels.degraded,
summary: '[savedObjects]: savedObjects degraded',
summary: '1 service is degraded: savedObjects',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
Expand All @@ -191,19 +191,19 @@ describe('PluginStatusService', () => {
expect(await serviceCritical.getAll$().pipe(first()).toPromise()).toEqual({
a: {
level: ServiceStatusLevels.critical,
summary: '[elasticsearch]: elasticsearch critical',
summary: '1 service is critical: elasticsearch',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
b: {
level: ServiceStatusLevels.critical,
summary: '[elasticsearch]: elasticsearch critical',
summary: '1 service is critical: elasticsearch',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
c: {
level: ServiceStatusLevels.critical,
summary: '[elasticsearch]: elasticsearch critical',
summary: '1 service is critical: elasticsearch',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
Expand All @@ -218,13 +218,13 @@ describe('PluginStatusService', () => {
a: { level: ServiceStatusLevels.available, summary: 'a status' }, // a is available depsite savedObjects being degraded
b: {
level: ServiceStatusLevels.degraded,
summary: '[savedObjects]: savedObjects degraded',
summary: '1 service is degraded: savedObjects',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
c: {
level: ServiceStatusLevels.degraded,
summary: '[2] services are degraded',
summary: '2 services are degraded: savedObjects, b',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
Expand Down Expand Up @@ -298,7 +298,7 @@ describe('PluginStatusService', () => {
a: { level: ServiceStatusLevels.unavailable, summary: 'Status check timed out after 30s' },
b: {
level: ServiceStatusLevels.unavailable,
summary: '[a]: Status check timed out after 30s',
summary: '1 service is unavailable: a',
detail: 'See the status page for more information',
meta: {
affectedServices: ['a'],
Expand Down Expand Up @@ -341,7 +341,7 @@ describe('PluginStatusService', () => {
a: { level: ServiceStatusLevels.available, summary: 'a status' }, // a is available depsite savedObjects being degraded
b: {
level: ServiceStatusLevels.degraded,
summary: '[savedObjects]: savedObjects degraded',
summary: '1 service is degraded: savedObjects',
detail: 'See the status page for more information',
meta: expect.any(Object),
},
Expand Down
Loading