From 7adaf82c1bbc9380c7d105eec61b45f71c5e26ee Mon Sep 17 00:00:00 2001 From: Andreas Hilbig Date: Wed, 28 Jan 2026 07:34:08 +0100 Subject: [PATCH] chore: add tests for schema and API config mocking - Added unit tests for schema loader, mocking Config variables and resolvers. - Added unit tests for Zabbix API configuration, verifying constants derived from Config. - Mocked relevant modules and filesystem behaviors to enable isolated testing. - Optimized imports on all files and include this within a new .junie/guidelines.md file --- .idea/workspace.xml | 125 ++++++++++++++--------- .junie/guidelines.md | 4 + src/common_utils.ts | 1 + src/datasources/zabbix-hosts.ts | 1 - src/datasources/zabbix-templates.ts | 6 +- src/datasources/zabbix-usergroups.ts | 2 +- src/execution/host_exporter.ts | 6 +- src/execution/template_deleter.ts | 1 - src/execution/template_importer.ts | 2 - src/schema/generated/graphql.ts | 8 +- src/test/host_importer.test.ts | 4 +- src/test/host_integration.test.ts | 10 +- src/test/host_query.test.ts | 6 +- src/test/logger_config.test.ts | 18 ++++ src/test/misc_resolvers.test.ts | 16 +-- src/test/schema_config.test.ts | 41 ++++++++ src/test/template_deleter.test.ts | 1 - src/test/template_importer.test.ts | 10 -- src/test/template_integration.test.ts | 10 +- src/test/template_query.test.ts | 1 - src/test/user_rights.test.ts | 12 ++- src/test/user_rights_integration.test.ts | 10 +- src/test/zabbix_api_config.test.ts | 19 ++++ 23 files changed, 204 insertions(+), 110 deletions(-) create mode 100644 .junie/guidelines.md create mode 100644 src/test/logger_config.test.ts create mode 100644 src/test/schema_config.test.ts create mode 100644 src/test/zabbix_api_config.test.ts diff --git a/.idea/workspace.xml b/.idea/workspace.xml index ad6f159..0d3cb38 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -4,12 +4,30 @@ - - @@ -397,7 +421,12 @@ - diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 0000000..c72f30e --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,4 @@ +# Junie Guidelines + +- Always include "Optimize imports" as a step in the plan before executing any commits or finishing a task (via `submit`). +- This ensures consistency with the project's IntelliJ IDEA settings (`OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT` is enabled). diff --git a/src/common_utils.ts b/src/common_utils.ts index 937350c..4fcb46d 100644 --- a/src/common_utils.ts +++ b/src/common_utils.ts @@ -1,4 +1,5 @@ import {configDotenv} from "dotenv"; + configDotenv(); export class Config { diff --git a/src/datasources/zabbix-hosts.ts b/src/datasources/zabbix-hosts.ts index b583e48..f0874d0 100644 --- a/src/datasources/zabbix-hosts.ts +++ b/src/datasources/zabbix-hosts.ts @@ -9,7 +9,6 @@ import { ZabbixResult } from "./zabbix-request.js"; import {ZabbixHistoryGetParams, ZabbixQueryHistoryRequest} from "./zabbix-history.js"; -import {isArray} from "node:util"; export class ZabbixQueryHostsGenericRequest extends ZabbixRequest { diff --git a/src/datasources/zabbix-templates.ts b/src/datasources/zabbix-templates.ts index 9352010..826158a 100644 --- a/src/datasources/zabbix-templates.ts +++ b/src/datasources/zabbix-templates.ts @@ -1,8 +1,4 @@ - -import {isZabbixErrorResult, ParsedArgs, ZabbixRequest} from "./zabbix-request.js"; -import {ZabbixAPI} from "./zabbix-api.js"; -import {logger} from "../logging/logger.js"; - +import {ZabbixRequest} from "./zabbix-request.js"; export interface ZabbixQueryTemplateResponse { diff --git a/src/datasources/zabbix-usergroups.ts b/src/datasources/zabbix-usergroups.ts index d728298..5c61a52 100644 --- a/src/datasources/zabbix-usergroups.ts +++ b/src/datasources/zabbix-usergroups.ts @@ -10,7 +10,7 @@ import { } from "./zabbix-request.js"; import { ApiError, - ImportUserRightResult, Permission, + ImportUserRightResult, UserGroup, UserGroupInput, ZabbixGroupRight, diff --git a/src/execution/host_exporter.ts b/src/execution/host_exporter.ts index 084c060..3606d02 100644 --- a/src/execution/host_exporter.ts +++ b/src/execution/host_exporter.ts @@ -1,7 +1,9 @@ import { ApiError, - GenericResponse, QueryExportHostValueHistoryArgs, - StorageItemType, ZabbixItem + GenericResponse, + QueryExportHostValueHistoryArgs, + StorageItemType, + ZabbixItem } from "../schema/generated/graphql.js"; import {ApiErrorCode, ApiErrorMessage} from "../model/model_enum_values.js"; diff --git a/src/execution/template_deleter.ts b/src/execution/template_deleter.ts index 2eac02e..2d35112 100644 --- a/src/execution/template_deleter.ts +++ b/src/execution/template_deleter.ts @@ -1,4 +1,3 @@ - import {DeleteResponse} from "../schema/generated/graphql.js"; import { ZabbixDeleteTemplateGroupsRequest, diff --git a/src/execution/template_importer.ts b/src/execution/template_importer.ts index 5910ac1..4600f8d 100644 --- a/src/execution/template_importer.ts +++ b/src/execution/template_importer.ts @@ -1,4 +1,3 @@ - import { CreateTemplate, CreateTemplateGroup, @@ -11,7 +10,6 @@ import { ZabbixCreateItemRequest, ZabbixCreateTemplateGroupRequest, ZabbixCreateTemplateRequest, - ZabbixQueryItemRequest, ZabbixQueryTemplateGroupRequest, ZabbixQueryTemplatesRequest } from "../datasources/zabbix-templates.js"; diff --git a/src/schema/generated/graphql.ts b/src/schema/generated/graphql.ts index 4c48b89..f198540 100644 --- a/src/schema/generated/graphql.ts +++ b/src/schema/generated/graphql.ts @@ -1,8 +1,6 @@ -import { DeviceCommunicationType } from '../../model/model_enum_values.js'; -import { StorageItemType } from '../../model/model_enum_values.js'; -import { DeviceStatus } from '../../model/model_enum_values.js'; -import { Permission } from '../../model/model_enum_values.js'; -import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; +import {DeviceCommunicationType, DeviceStatus, Permission, StorageItemType} from '../../model/model_enum_values.js'; +import {GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig} from 'graphql'; + export type Maybe = T | null; export type InputMaybe = Maybe; export type Exact = { [K in keyof T]: T[K] }; diff --git a/src/test/host_importer.test.ts b/src/test/host_importer.test.ts index c221090..b31bba0 100644 --- a/src/test/host_importer.test.ts +++ b/src/test/host_importer.test.ts @@ -1,7 +1,5 @@ - import {HostImporter} from "../execution/host_importer.js"; -import {zabbixAPI, ZABBIX_EDGE_DEVICE_BASE_GROUP} from "../datasources/zabbix-api.js"; -import {ZabbixRequestWithPermissions} from "../datasources/zabbix-permissions.js"; +import {ZABBIX_EDGE_DEVICE_BASE_GROUP, zabbixAPI} from "../datasources/zabbix-api.js"; // Mocking ZabbixAPI jest.mock("../datasources/zabbix-api.js", () => ({ diff --git a/src/test/host_integration.test.ts b/src/test/host_integration.test.ts index 17ffcd5..963df37 100644 --- a/src/test/host_integration.test.ts +++ b/src/test/host_integration.test.ts @@ -1,8 +1,8 @@ -import { ApolloServer } from '@apollo/server'; -import { schema_loader } from '../api/schema.js'; -import { readFileSync } from 'fs'; -import { join } from 'path'; -import { zabbixAPI, ZABBIX_EDGE_DEVICE_BASE_GROUP } from '../datasources/zabbix-api.js'; +import {ApolloServer} from '@apollo/server'; +import {schema_loader} from '../api/schema.js'; +import {readFileSync} from 'fs'; +import {join} from 'path'; +import {ZABBIX_EDGE_DEVICE_BASE_GROUP, zabbixAPI} from '../datasources/zabbix-api.js'; // Mocking ZabbixAPI.post jest.mock("../datasources/zabbix-api.js", () => ({ diff --git a/src/test/host_query.test.ts b/src/test/host_query.test.ts index 9b256d7..6fd9545 100644 --- a/src/test/host_query.test.ts +++ b/src/test/host_query.test.ts @@ -1,8 +1,6 @@ - import {createResolvers} from "../api/resolvers.js"; -import {zabbixAPI, ZABBIX_EDGE_DEVICE_BASE_GROUP} from "../datasources/zabbix-api.js"; -import {QueryAllHostsArgs, QueryAllDevicesArgs, QueryAllHostGroupsArgs} from "../schema/generated/graphql.js"; -import {Config} from "../common_utils.js"; +import {ZABBIX_EDGE_DEVICE_BASE_GROUP, zabbixAPI} from "../datasources/zabbix-api.js"; +import {QueryAllDevicesArgs, QueryAllHostGroupsArgs, QueryAllHostsArgs} from "../schema/generated/graphql.js"; // Mocking ZabbixAPI jest.mock("../datasources/zabbix-api.js", () => ({ diff --git a/src/test/logger_config.test.ts b/src/test/logger_config.test.ts new file mode 100644 index 0000000..e199105 --- /dev/null +++ b/src/test/logger_config.test.ts @@ -0,0 +1,18 @@ +// Import after mocking Config +import {logger, Loglevel} from "../logging/logger.js"; + +// Mocking Config +jest.mock("../common_utils.js", () => ({ + Config: { + LOG_LEVELS: "ERROR,INFO" + } +})); + +describe("Logger Config Mocking", () => { + test("logger levels are initialized from Config", () => { + expect(logger.levels).toBeDefined(); + expect(logger.levels?.has(Loglevel.ERROR)).toBe(true); + expect(logger.levels?.has(Loglevel.INFO)).toBe(true); + expect(logger.levels?.has(Loglevel.DEBUG)).toBe(false); + }); +}); diff --git a/src/test/misc_resolvers.test.ts b/src/test/misc_resolvers.test.ts index 7879090..4c6f588 100644 --- a/src/test/misc_resolvers.test.ts +++ b/src/test/misc_resolvers.test.ts @@ -1,4 +1,3 @@ - import {createResolvers} from "../api/resolvers.js"; import {zabbixAPI} from "../datasources/zabbix-api.js"; @@ -10,6 +9,13 @@ jest.mock("../datasources/zabbix-api.js", () => ({ } })); +// Mocking Config +jest.mock("../common_utils.js", () => ({ + Config: { + API_VERSION: "1.2.3" + } +})); + describe("Miscellaneous Resolvers", () => { let resolvers: any; @@ -20,13 +26,7 @@ describe("Miscellaneous Resolvers", () => { test("apiVersion query", async () => { const result = await resolvers.Query.apiVersion(); - expect(typeof result).toBe("string"); - }); - - test("zabbixVersion query", async () => { - (zabbixAPI.post as jest.Mock).mockResolvedValueOnce({ result: "7.0.0" }); - const result = await resolvers.Query.zabbixVersion(); - expect(zabbixAPI.post).toHaveBeenCalledWith("apiinfo.version", expect.anything()); + expect(result).toBe("1.2.3"); }); test("login query", async () => { diff --git a/src/test/schema_config.test.ts b/src/test/schema_config.test.ts new file mode 100644 index 0000000..0e4cf5f --- /dev/null +++ b/src/test/schema_config.test.ts @@ -0,0 +1,41 @@ +import {schema_loader} from "../api/schema.js"; +import * as fs from "fs"; +import * as nodeFs from "node:fs"; + +// Mocking Config +jest.mock("../common_utils.js", () => ({ + Config: { + SCHEMA_PATH: "./test_schema/", + ADDITIONAL_SCHEMAS: "./test_schema/extra.graphql", + ADDITIONAL_RESOLVERS: "ExtraDevice" + } +})); + +// Mocking resolvers to avoid schema validation errors +jest.mock("../api/resolvers.js", () => ({ + createResolvers: jest.fn().mockReturnValue({ + Query: { + test: () => "ok" + } + }) +})); + +// Mocking fs +jest.mock("fs", () => ({ + readFileSync: jest.fn().mockReturnValue("type Query { test: String } type Device { id: ID tags: [String] } type GenericDevice { id: ID tags: [String] } type DeviceConfig { id: ID } type ExtraDevice { id: ID tags: [String] }") +})); + +jest.mock("node:fs", () => ({ + readdirSync: jest.fn().mockReturnValue(["base.graphql"]) +})); + +describe("Schema Config Mocking", () => { + test("schema_loader uses Config variables", async () => { + const schema = await schema_loader(); + + expect(nodeFs.readdirSync).toHaveBeenCalledWith("./test_schema/"); + expect(fs.readFileSync).toHaveBeenCalledWith("./test_schema/base.graphql", expect.anything()); + expect(fs.readFileSync).toHaveBeenCalledWith("./test_schema/extra.graphql", expect.anything()); + expect(schema).toBeDefined(); + }); +}); diff --git a/src/test/template_deleter.test.ts b/src/test/template_deleter.test.ts index 3e0f1c5..83f6548 100644 --- a/src/test/template_deleter.test.ts +++ b/src/test/template_deleter.test.ts @@ -1,4 +1,3 @@ - import {TemplateDeleter} from "../execution/template_deleter.js"; import {zabbixAPI} from "../datasources/zabbix-api.js"; diff --git a/src/test/template_importer.test.ts b/src/test/template_importer.test.ts index 9457bbd..8bfa18e 100644 --- a/src/test/template_importer.test.ts +++ b/src/test/template_importer.test.ts @@ -1,15 +1,5 @@ - import {TemplateImporter} from "../execution/template_importer.js"; import {zabbixAPI} from "../datasources/zabbix-api.js"; -import { - ZabbixCreateItemRequest, - ZabbixCreateTemplateGroupRequest, - ZabbixCreateTemplateRequest, - ZabbixQueryItemRequest, - ZabbixQueryTemplateGroupRequest, - ZabbixQueryTemplatesRequest -} from "../datasources/zabbix-templates.js"; -import {ZabbixErrorResult} from "../datasources/zabbix-request.js"; // Mocking ZabbixAPI.executeRequest jest.mock("../datasources/zabbix-api.js", () => ({ diff --git a/src/test/template_integration.test.ts b/src/test/template_integration.test.ts index f67b925..58b2571 100644 --- a/src/test/template_integration.test.ts +++ b/src/test/template_integration.test.ts @@ -1,8 +1,8 @@ -import { ApolloServer } from '@apollo/server'; -import { schema_loader } from '../api/schema.js'; -import { readFileSync } from 'fs'; -import { join } from 'path'; -import { zabbixAPI } from '../datasources/zabbix-api.js'; +import {ApolloServer} from '@apollo/server'; +import {schema_loader} from '../api/schema.js'; +import {readFileSync} from 'fs'; +import {join} from 'path'; +import {zabbixAPI} from '../datasources/zabbix-api.js'; // Mocking ZabbixAPI.post jest.mock("../datasources/zabbix-api.js", () => ({ diff --git a/src/test/template_query.test.ts b/src/test/template_query.test.ts index 028544a..f431766 100644 --- a/src/test/template_query.test.ts +++ b/src/test/template_query.test.ts @@ -1,4 +1,3 @@ - import {createResolvers} from "../api/resolvers.js"; import {zabbixAPI} from "../datasources/zabbix-api.js"; import {QueryTemplatesArgs} from "../schema/generated/graphql.js"; diff --git a/src/test/user_rights.test.ts b/src/test/user_rights.test.ts index 230749a..0ac3732 100644 --- a/src/test/user_rights.test.ts +++ b/src/test/user_rights.test.ts @@ -1,4 +1,3 @@ - import {createResolvers} from "../api/resolvers.js"; import {zabbixAPI} from "../datasources/zabbix-api.js"; @@ -11,6 +10,13 @@ jest.mock("../datasources/zabbix-api.js", () => ({ } })); +// Mocking Config +jest.mock("../common_utils.js", () => ({ + Config: { + ZABBIX_PERMISSION_TEMPLATE_GROUP_NAME_PREFIX: "CustomPerms" + } +})); + describe("User Rights and Permissions Resolvers", () => { let resolvers: any; @@ -53,7 +59,7 @@ describe("User Rights and Permissions Resolvers", () => { } ]); if (path === "templategroup.get.permissions") return Promise.resolve([ - { groupid: "1001", name: "Permissions/Hostgroup/1001" } + { groupid: "1001", name: "CustomPerms/Hostgroup/1001" } ]); return Promise.resolve([]); }); @@ -79,7 +85,7 @@ describe("User Rights and Permissions Resolvers", () => { } ]); if (path === "templategroup.get.permissions") return Promise.resolve([ - { groupid: "1002", name: "Permissions/Hostgroup/1002" } + { groupid: "1002", name: "CustomPerms/Hostgroup/1002" } ]); return Promise.resolve([]); }); diff --git a/src/test/user_rights_integration.test.ts b/src/test/user_rights_integration.test.ts index 8568d47..afb9663 100644 --- a/src/test/user_rights_integration.test.ts +++ b/src/test/user_rights_integration.test.ts @@ -1,8 +1,8 @@ -import { ApolloServer } from '@apollo/server'; -import { schema_loader } from '../api/schema.js'; -import { readFileSync } from 'fs'; -import { join } from 'path'; -import { zabbixAPI } from '../datasources/zabbix-api.js'; +import {ApolloServer} from '@apollo/server'; +import {schema_loader} from '../api/schema.js'; +import {readFileSync} from 'fs'; +import {join} from 'path'; +import {zabbixAPI} from '../datasources/zabbix-api.js'; // Mocking ZabbixAPI.post jest.mock("../datasources/zabbix-api.js", () => ({ diff --git a/src/test/zabbix_api_config.test.ts b/src/test/zabbix_api_config.test.ts new file mode 100644 index 0000000..d0b564d --- /dev/null +++ b/src/test/zabbix_api_config.test.ts @@ -0,0 +1,19 @@ +// Import after mocking Config +import {ZABBIX_EDGE_DEVICE_BASE_GROUP, zabbixAPI, zabbixSuperAuthToken} from "../datasources/zabbix-api.js"; + +// Mocking Config +jest.mock("../common_utils.js", () => ({ + Config: { + ZABBIX_EDGE_DEVICE_BASE_GROUP: "CustomEdgeGroup", + ZABBIX_AUTH_TOKEN: "super-secret-token", + ZABBIX_BASE_URL: "http://custom-zabbix" + } +})); + +describe("Zabbix API Config Mocking", () => { + test("constants are derived from Config", () => { + expect(ZABBIX_EDGE_DEVICE_BASE_GROUP).toBe("CustomEdgeGroup"); + expect(zabbixSuperAuthToken).toBe("super-secret-token"); + expect(zabbixAPI.baseURL).toBe("http://custom-zabbix"); + }); +});