balena-supervisor/test/unit/memory.spec.ts
Christina Ying Wang f863075bdc Add memory usage healthcheck
This healthcheck fails when Supervisor memory usage is above a threshold
based on initial memory measurements after device state has settled.

Change-type: patch
Signed-off-by: Christina Ying Wang <christina@balena.io>
2024-04-11 18:16:47 -07:00

73 lines
2.1 KiB
TypeScript

import { expect } from 'chai';
import type { SinonStub } from 'sinon';
import { stub } from 'sinon';
import * as process from 'process';
import * as memory from '~/src/memory';
import * as deviceState from '~/src/device-state';
import log from '~/lib/supervisor-console';
describe('memory.healthcheck', () => {
let uptimeStub: SinonStub;
let rssStub: SinonStub;
let isApplyInProgressStub: SinonStub;
beforeEach(() => {
uptimeStub = stub(memory, 'processUptime').returns(20);
rssStub = stub(process.memoryUsage, 'rss').returns(100);
isApplyInProgressStub = stub(deviceState, 'isApplyInProgress').returns(
false,
);
});
afterEach(() => {
uptimeStub.restore();
rssStub.restore();
isApplyInProgressStub.restore();
});
it('passes healthcheck if process has not been running for 20s', async () => {
// @ts-expect-error - initialMemory is read-only
memory.initialMemory = 0;
uptimeStub.returns(19);
expect(await memory.healthcheck()).to.be.true;
});
it('passes healthcheck while initial memory not set and sets initial memory', async () => {
// @ts-expect-error - initialMemory is read-only
memory.initialMemory = 0;
expect(await memory.healthcheck()).to.be.true;
expect(memory.initialMemory).to.equal(100);
});
it('passes healthcheck while state apply in progress', async () => {
// @ts-expect-error - initialMemory is read-only
memory.initialMemory = 100;
isApplyInProgressStub.returns(true);
expect(await memory.healthcheck()).to.be.true;
});
it('passes healthcheck if memory usage is below threshold', async () => {
// @ts-expect-error - initialMemory is read-only
memory.initialMemory = 100;
rssStub.returns(150);
expect(await memory.healthcheck(100)).to.be.true;
});
it('fails healthcheck if memory usage is above threshold', async () => {
// @ts-expect-error - initialMemory is read-only
memory.initialMemory = 100;
uptimeStub.returns(61);
rssStub.returns(250);
expect(await memory.healthcheck(100)).to.be.false;
expect(log.info).to.have.been.calledWith(
`Healthcheck failure - memory usage above threshold after 0h 1m 1s`,
);
});
});