feat: implement smoketest and extend host provisioning with template linking

- Add runSmoketest mutation to automate end-to-end verification.

- Add SmoketestExecutor and HostDeleter to support automated testing and cleanup.

- Extend createHost and importHosts to allow linking templates by name or ID.

- Update docs/howtos/cookbook.md with new recipe steps and AI/MCP guidance.

- Update .junie/guidelines.md with new verification and deployment standards.

- Add src/test/template_link.test.ts and update existing tests to cover new functionality.

- Regenerate GraphQL types to match schema updates.
This commit is contained in:
Andreas Hilbig 2026-01-31 11:46:02 +01:00
parent b56255ffaa
commit 67357d0bc3
20 changed files with 690 additions and 50 deletions

View file

@ -71,8 +71,8 @@ describe("HostImporter", () => {
// Mocking template lookup for deviceType
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce([{ templateid: "301" }]);
// Mocking host.create via requestByPath
(zabbixAPI.requestByPath as jest.Mock).mockResolvedValueOnce({ hostids: ["401"] });
// Mocking host.create via post (called by ZabbixCreateHostRequest)
(zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ hostids: ["401"] });
const result = await HostImporter.importHosts(hosts, "token");

View file

@ -62,9 +62,8 @@ describe("Host Integration Tests", () => {
(zabbixAPI.post as jest.Mock)
.mockResolvedValueOnce([{ groupid: "201", name: ZABBIX_EDGE_DEVICE_BASE_GROUP }]) // Base group
.mockResolvedValueOnce([{ groupid: "202", name: ZABBIX_EDGE_DEVICE_BASE_GROUP + "/ConstructionSite/Test" }]) // Specific group
.mockResolvedValueOnce([{ templateid: "301" }]); // Template lookup
(zabbixAPI.requestByPath as jest.Mock).mockResolvedValueOnce({ hostids: ["401"] });
.mockResolvedValueOnce([{ templateid: "301" }]) // Template lookup
.mockResolvedValueOnce({ hostids: ["401"] }); // Host creation
const response = await server.executeOperation({
query: mutation,

View file

@ -0,0 +1,95 @@
import {ApolloServer} from '@apollo/server';
import {schema_loader} from '../api/schema.js';
import {zabbixAPI} from '../datasources/zabbix-api.js';
// Mocking ZabbixAPI
jest.mock("../datasources/zabbix-api.js", () => ({
zabbixAPI: {
post: jest.fn(),
executeRequest: jest.fn(),
baseURL: 'http://localhost/zabbix',
requestByPath: jest.fn()
},
ZABBIX_EDGE_DEVICE_BASE_GROUP: "Roadwork"
}));
describe("Template Linking Tests", () => {
let server: ApolloServer;
beforeAll(async () => {
const schema = await schema_loader();
server = new ApolloServer({
schema,
});
});
test("createHost with templateNames", async () => {
const mutation = `
mutation CreateHost($host: String!, $hostgroupids: [Int!]!, $templateNames: [String!]!) {
createHost(host: $host, hostgroupids: $hostgroupids, templateNames: $templateNames) {
hostids
}
}
`;
const variables = {
host: "TestHost",
hostgroupids: [1],
templateNames: ["Test Template"]
};
(zabbixAPI.post as jest.Mock)
.mockResolvedValueOnce([{ templateid: "101", name: "Test Template" }]) // Template lookup
.mockResolvedValueOnce({ hostids: ["201"] }); // Host creation
const response = await server.executeOperation({
query: mutation,
variables: variables,
}, {
contextValue: { zabbixAuthToken: 'test-token', dataSources: { zabbixAPI: zabbixAPI } }
});
expect(response.body.kind).toBe('single');
// @ts-ignore
const result = response.body.singleResult;
expect(result.errors).toBeUndefined();
expect(result.data.createHost.hostids).toContain(201);
});
test("importHosts with templateids and templateNames", async () => {
const mutation = `
mutation ImportHosts($hosts: [CreateHost!]!) {
importHosts(hosts: $hosts) {
hostid
}
}
`;
const variables = {
hosts: [{
deviceKey: "TestDevice",
deviceType: "TestType",
groupNames: ["TestGroup"],
templateids: [101],
templateNames: ["Another Template"]
}]
};
(zabbixAPI.post as jest.Mock)
.mockResolvedValueOnce([{ groupid: "501", name: "Roadwork" }]) // Base group lookup
.mockResolvedValueOnce([{ groupid: "502", name: "Roadwork/TestGroup" }]) // Specific group lookup
.mockResolvedValueOnce([{ templateid: "102", name: "Another Template" }]) // Template lookup
.mockResolvedValueOnce({ hostids: ["202"] }); // Host creation
const response = await server.executeOperation({
query: mutation,
variables: variables,
}, {
contextValue: { zabbixAuthToken: 'test-token', dataSources: { zabbixAPI: zabbixAPI } }
});
expect(response.body.kind).toBe('single');
// @ts-ignore
const result = response.body.singleResult;
expect(result.errors).toBeUndefined();
expect(result.data.importHosts[0].hostid).toBe("202");
});
});