Skip to content

Commit

Permalink
Test that only one create_service_install task is created per PATCH
Browse files Browse the repository at this point in the history
Change-type: patch
  • Loading branch information
thgreasi committed Nov 25, 2024
1 parent 80bb9ad commit 8bf34dc
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 2 deletions.
63 changes: 63 additions & 0 deletions test/25_service-installs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as fixtures from './test-lib/fixtures.js';
import { assertExists, expectToEventually } from './test-lib/common.js';
import * as config from '../src/lib/config.js';
import { supertest } from './test-lib/supertest.js';
import { expectNewTasks, resetLatestTaskIds } from './test-lib/api-helpers.js';

export default () => {
versions.test((version, pineTest) => {
Expand Down Expand Up @@ -45,6 +46,8 @@ export default () => {

config.TEST_MOCK_ONLY.ASYNC_TASK_CREATE_SERVICE_INSTALLS_ENABLED =
isServiceInstallEnabled;

await resetLatestTaskIds('create_service_installs');
});

after(async () => {
Expand Down Expand Up @@ -74,6 +77,19 @@ export default () => {
ctx.app1Service1.id,
);
});
await expectNewTasks(
'create_service_installs',
isServiceInstallEnabled
? [
{
is_executed_with__parameter_set: {
devices: [ctx.device.id],
},
status: 'succeeded',
},
]
: [],
);
});

it('for pinning an application to a release', async () => {
Expand Down Expand Up @@ -104,6 +120,19 @@ export default () => {
ctx.app1Service2.id,
);
});
await expectNewTasks(
'create_service_installs',
isServiceInstallEnabled
? [
{
is_executed_with__parameter_set: {
devices: [ctx.device.id],
},
status: 'succeeded',
},
]
: [],
);
});

it('when a device is pinned on a different release', async () => {
Expand Down Expand Up @@ -133,6 +162,19 @@ export default () => {
ctx.app1Service3.id,
);
});
await expectNewTasks(
'create_service_installs',
isServiceInstallEnabled
? [
{
is_executed_with__parameter_set: {
devices: [ctx.device.id],
},
status: 'succeeded',
},
]
: [],
);
});

it('when device is moved to different application', async () => {
Expand Down Expand Up @@ -170,6 +212,27 @@ export default () => {
ctx.app2Service1.id,
);
});
await expectNewTasks(
'create_service_installs',
isServiceInstallEnabled
? [
// the first one is from unpinning
{
is_executed_with__parameter_set: {
devices: [ctx.device.id],
},
status: 'succeeded',
},
// the second one is from moving application
{
is_executed_with__parameter_set: {
devices: [ctx.device.id],
},
status: 'succeeded',
},
]
: [],
);
});

it('should be able to use service_install to create a device_service_environment_variable', async () => {
Expand Down
89 changes: 87 additions & 2 deletions test/test-lib/api-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import type { UserObjectParam } from '../test-lib/supertest.js';
import { supertest } from '../test-lib/supertest.js';
import type { TokenUserPayload } from '../../src/index.js';
import type { RequiredField } from '@balena/pinejs/out/sbvr-api/common-types.js';
import { assertExists } from './common.js';
import { assertExists, expectToEventually } from './common.js';
import { sbvrUtils, permissions } from '@balena/pinejs';
import type { tasks } from '@balena/pinejs';

const version = 'resin';

Expand Down Expand Up @@ -208,7 +210,7 @@ export const thatIsDateStringAfter = (

const validJwtProps = ['id', 'jwt_secret', 'authTime', 'iat', 'exp'].sort();

export function expectJwt(tokenOrJwt: string | AnyObject) {
export function expectJwt(tokenOrJwt: string | object) {
const decoded = (
typeof tokenOrJwt === 'string'
? jsonwebtoken.decode(tokenOrJwt)
Expand All @@ -232,3 +234,86 @@ export function expectJwt(tokenOrJwt: string | AnyObject) {

return decoded;
}

export type TaskExpectation = Pick<
tasks.Task['Read'],
'is_executed_with__parameter_set' | 'status'
>;

const expectTasks = async (
handler: string,
expectedTasks: TaskExpectation[],
lastId = '0',
) => {
const tasks = await sbvrUtils.api.tasks.get({
resource: 'task',
passthrough: { req: permissions.rootRead },
options: {
$select: ['id', 'is_executed_with__parameter_set', 'status'],
$filter: {
id: { $gt: lastId },
is_executed_by__handler: handler,
},
$orderby: { id: 'asc' },
},
});
const actual = tasks.map((t) =>
_.pick(t, ['is_executed_with__parameter_set', 'status']),
);

expect(actual).to.deep.equal(expectedTasks);
return tasks;
};

const latestTaskIdByHandler: Dictionary<string | undefined> = {};

export const expectNewTasks = async (
handler: string,
expectedUsage: TaskExpectation[],
) => {
const tasks = await expectTasks(
handler,
expectedUsage,
latestTaskIdByHandler[handler],
);
const lastTaskId = tasks.at(-1)?.id;
if (lastTaskId != null) {
latestTaskIdByHandler[handler] = lastTaskId;
}
};

export const resetLatestTaskIds = async (handler: string) => {
await expectToEventually(async () => {
const runningTasks = await sbvrUtils.api.tasks.get({
resource: 'task',
passthrough: { req: permissions.rootRead },
options: {
$top: 1,
$select: 'id',
$filter: {
status: 'queued',
is_executed_by__handler: handler,
},
$orderby: { id: 'desc' },
},
});
expect(runningTasks).to.have.lengthOf(0);
});
const [latestTask] = await sbvrUtils.api.tasks.get({
resource: 'task',
passthrough: { req: permissions.rootRead },
options: {
$top: 1,
$select: 'id',
$filter: {
status: 'succeeded',
is_executed_by__handler: handler,
},
$orderby: { id: 'desc' },
},
});
if (latestTask == null) {
return;
}
latestTaskIdByHandler[handler] = latestTask?.id;
};

0 comments on commit 8bf34dc

Please sign in to comment.