Skip to content

Commit 550ddd9

Browse files
committed
more fixes
1 parent b42b4d0 commit 550ddd9

File tree

4 files changed

+146
-1
lines changed

4 files changed

+146
-1
lines changed

app/api/container.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1000,6 +1000,22 @@ describe('Container Router', () => {
10001000
expect(res.json).toHaveBeenCalledWith(expect.any(Array));
10011001
});
10021002

1003+
test('should associate trigger when configuration is missing', async () => {
1004+
const res = await callGetContainerTriggers({ id: 'c1' }, [
1005+
{ type: 'slack', name: 'default' },
1006+
]);
1007+
1008+
const triggers = getTriggersFromResponse(res);
1009+
expect(triggers).toHaveLength(1);
1010+
expect(triggers[0]).toEqual(
1011+
expect.objectContaining({
1012+
type: 'slack',
1013+
name: 'default',
1014+
configuration: {},
1015+
}),
1016+
);
1017+
});
1018+
10031019
test('should filter triggers with triggerInclude', async () => {
10041020
Trigger.parseIncludeOrIncludeTriggerString.mockReturnValue({ id: 'slack.default' });
10051021
Trigger.doesReferenceMatchId.mockImplementation((ref, id) => ref === id);

app/api/trigger.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,32 @@ describe('Trigger Router', () => {
261261
}),
262262
);
263263
});
264+
265+
test('should return 400 when trigger conditions are not met and container id is missing', async () => {
266+
const mockTrigger = {
267+
mustTrigger: vi.fn().mockReturnValue(false),
268+
trigger: vi.fn(),
269+
};
270+
registry.getState.mockReturnValue({
271+
trigger: { 'slack.default': mockTrigger },
272+
});
273+
274+
const req = {
275+
params: { type: 'slack', name: 'default' },
276+
body: {},
277+
};
278+
const res = createResponse();
279+
280+
await runTrigger(req, res);
281+
282+
expect(mockTrigger.trigger).not.toHaveBeenCalled();
283+
expect(res.status).toHaveBeenCalledWith(400);
284+
expect(res.json).toHaveBeenCalledWith(
285+
expect.objectContaining({
286+
error: expect.stringContaining('Trigger conditions not met'),
287+
}),
288+
);
289+
});
264290
});
265291

266292
describe('runRemoteTrigger', () => {

app/api/trigger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ async function runRemoteTrigger(req, res) {
115115
!localProxyTrigger.mustTrigger(containerToTrigger)
116116
) {
117117
log.warn(
118-
`Remote trigger conditions not met (agent=${sanitizeLogParam(agentName)}, type=${sanitizeLogParam(triggerType)}, name=${sanitizeLogParam(triggerName)}, container=${sanitizeLogParam(containerToTrigger.id || 'unknown')})`,
118+
`Remote trigger conditions not met (agent=${sanitizeLogParam(agentName)}, type=${sanitizeLogParam(triggerType)}, name=${sanitizeLogParam(triggerName)}, container=${sanitizeLogParam(containerToTrigger.id)})`,
119119
);
120120
res.status(400).json({
121121
error: `Trigger conditions not met for ${triggerType}.${triggerName} on agent ${agentName} (check include/exclude and requireinclude settings)`,

app/watchers/providers/docker/Docker.test.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,105 @@ describe('Docker Watcher', () => {
14161416
expect(storeContainer.updateContainer).not.toHaveBeenCalled();
14171417
});
14181418

1419+
test('should use old container name when inspect name is empty and compose trigger is created', async () => {
1420+
await docker.register('watcher', 'docker', 'test', {});
1421+
docker.log = createMockLogWithChild(['info']);
1422+
mockContainer.inspect.mockResolvedValue({
1423+
Name: '',
1424+
State: { Status: 'running' },
1425+
Config: {
1426+
Labels: {
1427+
'dd.compose.file': '/tmp/my-stack/docker-compose.yml',
1428+
},
1429+
},
1430+
});
1431+
const existingContainer = {
1432+
id: 'container123',
1433+
name: 'old-compose-name',
1434+
displayName: 'old-compose-name',
1435+
status: 'running',
1436+
image: { name: 'library/nginx' },
1437+
labels: {
1438+
'dd.compose.file': '/tmp/my-stack/docker-compose.yml',
1439+
},
1440+
};
1441+
storeContainer.getContainer.mockReturnValue(existingContainer);
1442+
1443+
await docker.onDockerEvent(Buffer.from('{"Action":"start","id":"container123"}\n'));
1444+
1445+
expect(registry.ensureDockercomposeTriggerForContainer).toHaveBeenCalledWith(
1446+
'old-compose-name',
1447+
'/tmp/my-stack/docker-compose.yml',
1448+
{},
1449+
);
1450+
});
1451+
1452+
test('should use old container name in warning when compose trigger creation fails and inspect name is empty', async () => {
1453+
await docker.register('watcher', 'docker', 'test', {});
1454+
docker.log = createMockLogWithChild(['warn']);
1455+
mockContainer.inspect.mockResolvedValue({
1456+
Name: '',
1457+
State: { Status: 'running' },
1458+
Config: {
1459+
Labels: {
1460+
'dd.compose.file': '/tmp/my-stack/docker-compose.yml',
1461+
},
1462+
},
1463+
});
1464+
const existingContainer = {
1465+
id: 'container123',
1466+
name: 'old-compose-name',
1467+
displayName: 'old-compose-name',
1468+
status: 'running',
1469+
image: { name: 'library/nginx' },
1470+
labels: {
1471+
'dd.compose.file': '/tmp/my-stack/docker-compose.yml',
1472+
},
1473+
};
1474+
storeContainer.getContainer.mockReturnValue(existingContainer);
1475+
1476+
vi.spyOn(registry, 'ensureDockercomposeTriggerForContainer').mockRejectedValueOnce(
1477+
new Error('event create failed'),
1478+
);
1479+
1480+
await docker.onDockerEvent(Buffer.from('{"Action":"start","id":"container123"}\n'));
1481+
1482+
expect(docker.log._child.warn).toHaveBeenCalledWith(
1483+
expect.stringContaining('old-compose-name'),
1484+
);
1485+
});
1486+
1487+
test('should skip update when compose label is absent, cached trigger exists, and trigger include is unchanged', async () => {
1488+
await docker.register('watcher', 'docker', 'test', {});
1489+
docker.log = createMockLogWithChild(['info']);
1490+
mockContainer.inspect.mockResolvedValue({
1491+
Name: '/compose-container',
1492+
State: { Status: 'running' },
1493+
Config: {
1494+
Labels: {},
1495+
},
1496+
});
1497+
const existingContainer = {
1498+
id: 'container123',
1499+
name: 'compose-container',
1500+
displayName: 'compose-container',
1501+
status: 'running',
1502+
image: { name: 'library/nginx' },
1503+
labels: {},
1504+
triggerInclude: undefined,
1505+
};
1506+
docker.composeTriggersByContainer = {
1507+
container123: 'dockercompose.my-stack-compose-container',
1508+
};
1509+
storeContainer.getContainer.mockReturnValue(existingContainer);
1510+
1511+
await docker.onDockerEvent(Buffer.from('{"Action":"start","id":"container123"}\n'));
1512+
1513+
expect(existingContainer.triggerInclude).toBeUndefined();
1514+
expect(docker.composeTriggersByContainer.container123).toBeUndefined();
1515+
expect(storeContainer.updateContainer).not.toHaveBeenCalled();
1516+
});
1517+
14191518
test('should skip store update when inspect payload does not change tracked fields', async () => {
14201519
await docker.register('watcher', 'docker', 'test', {});
14211520
docker.log = createMockLogWithChild(['info']);
@@ -4619,6 +4718,10 @@ describe('Docker Watcher', () => {
46194718
expect(testable_removeTriggerId('ntfy.default:major', undefined)).toBe('ntfy.default:major');
46204719
});
46214720

4721+
test('removeTriggerId should return undefined when last trigger is removed', () => {
4722+
expect(testable_removeTriggerId('dockercompose.test', 'dockercompose.test')).toBeUndefined();
4723+
});
4724+
46224725

46234726
test('getCurrentPrefix should return the non-numeric prefix before the first digit', () => {
46244727
expect(testable_getCurrentPrefix('v2026.2.1')).toBe('v');

0 commit comments

Comments
 (0)