Skip to main content
Glama
config.test.ts18.3 kB
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; import { getConfig, clearConfigCache, isToolCategoryEnabled, getEnabledToolCategories, displayConfig, } from './config.js'; import type { Config, ToolCategory } from './types.js'; // Mock console methods vi.mock('console', () => ({ log: vi.fn(), })); describe('config', () => { const originalEnv = process.env; beforeEach(() => { vi.clearAllMocks(); clearConfigCache(); // Reset environment to clean state process.env = { ...originalEnv }; delete process.env.GRAFANA_URL; delete process.env.GRAFANA_TOKEN; delete process.env.GRAFANA_DEBUG; delete process.env.GRAFANA_TIMEOUT; delete process.env.GRAFANA_DISABLE_TOOLS; delete process.env.GRAFANA_TLS_CERT_FILE; delete process.env.GRAFANA_TLS_KEY_FILE; delete process.env.GRAFANA_TLS_CA_FILE; delete process.env.GRAFANA_TLS_SKIP_VERIFY; }); afterEach(() => { process.env = originalEnv; clearConfigCache(); }); describe('getConfig', () => { it('should parse valid configuration successfully', () => { process.env.GRAFANA_URL = 'https://grafana.example.com'; process.env.GRAFANA_TOKEN = 'test-token-123'; const config = getConfig(); expect(config).toEqual({ GRAFANA_URL: 'https://grafana.example.com', GRAFANA_TOKEN: 'test-token-123', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, }); }); it('should apply defaults for optional fields', () => { process.env.GRAFANA_URL = 'http://localhost:3000'; process.env.GRAFANA_TOKEN = 'token'; const config = getConfig(); expect(config.GRAFANA_DEBUG).toBe(false); expect(config.GRAFANA_TIMEOUT).toBe(30000); expect(config.GRAFANA_DISABLE_TOOLS).toEqual([]); expect(config.GRAFANA_TLS_SKIP_VERIFY).toBe(false); }); it('should parse boolean environment variables correctly', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DEBUG = 'true'; process.env.GRAFANA_TLS_SKIP_VERIFY = 'true'; const config = getConfig(); expect(config.GRAFANA_DEBUG).toBe(true); expect(config.GRAFANA_TLS_SKIP_VERIFY).toBe(true); }); it('should handle false boolean values', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DEBUG = 'false'; process.env.GRAFANA_TLS_SKIP_VERIFY = 'false'; const config = getConfig(); expect(config.GRAFANA_DEBUG).toBe(false); expect(config.GRAFANA_TLS_SKIP_VERIFY).toBe(false); }); it('should parse timeout as integer', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TIMEOUT = '60000'; const config = getConfig(); expect(config.GRAFANA_TIMEOUT).toBe(60000); }); it('should parse disabled tools list correctly', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DISABLE_TOOLS = 'dashboards,prometheus,admin'; const config = getConfig(); expect(config.GRAFANA_DISABLE_TOOLS).toEqual(['dashboards', 'prometheus', 'admin']); }); it('should handle disabled tools with spaces', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DISABLE_TOOLS = ' dashboards , prometheus , admin '; const config = getConfig(); expect(config.GRAFANA_DISABLE_TOOLS).toEqual(['dashboards', 'prometheus', 'admin']); }); it('should handle empty disabled tools string', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DISABLE_TOOLS = ''; const config = getConfig(); expect(config.GRAFANA_DISABLE_TOOLS).toEqual([]); }); it('should handle disabled tools with empty segments', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DISABLE_TOOLS = 'dashboards,,prometheus,'; const config = getConfig(); expect(config.GRAFANA_DISABLE_TOOLS).toEqual(['dashboards', 'prometheus']); }); it('should include TLS configuration when provided', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TLS_CERT_FILE = '/path/to/cert.pem'; process.env.GRAFANA_TLS_KEY_FILE = '/path/to/key.pem'; process.env.GRAFANA_TLS_CA_FILE = '/path/to/ca.pem'; const config = getConfig(); expect(config.GRAFANA_TLS_CERT_FILE).toBe('/path/to/cert.pem'); expect(config.GRAFANA_TLS_KEY_FILE).toBe('/path/to/key.pem'); expect(config.GRAFANA_TLS_CA_FILE).toBe('/path/to/ca.pem'); }); it('should cache configuration on subsequent calls', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; const config1 = getConfig(); const config2 = getConfig(); expect(config1).toBe(config2); // Same object reference }); it('should throw error for missing GRAFANA_URL', () => { process.env.GRAFANA_TOKEN = 'token'; // GRAFANA_URL is missing expect(() => getConfig()).toThrow('Configuration validation failed'); }); it('should throw error for invalid GRAFANA_URL', () => { process.env.GRAFANA_URL = 'not-a-url'; process.env.GRAFANA_TOKEN = 'token'; expect(() => getConfig()).toThrow('GRAFANA_URL must be a valid URL'); }); it('should throw error for missing GRAFANA_TOKEN', () => { process.env.GRAFANA_URL = 'https://grafana.test'; // GRAFANA_TOKEN is missing expect(() => getConfig()).toThrow('Configuration validation failed'); }); it('should throw error for empty GRAFANA_TOKEN', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = ''; expect(() => getConfig()).toThrow('GRAFANA_TOKEN is required'); }); it('should throw error for invalid GRAFANA_TIMEOUT', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TIMEOUT = 'not-a-number'; expect(() => getConfig()).toThrow('Configuration validation failed'); }); it('should throw error for negative GRAFANA_TIMEOUT', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TIMEOUT = '-1000'; expect(() => getConfig()).toThrow('Configuration validation failed'); }); it('should throw error for zero GRAFANA_TIMEOUT', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TIMEOUT = '0'; expect(() => getConfig()).toThrow('Configuration validation failed'); }); it('should handle floating point timeout values', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TIMEOUT = '5000.5'; expect(() => getConfig()).toThrow('Configuration validation failed'); }); it('should provide detailed error messages for multiple validation failures', () => { process.env.GRAFANA_URL = 'invalid-url'; process.env.GRAFANA_TOKEN = ''; process.env.GRAFANA_TIMEOUT = '-100'; try { getConfig(); expect.fail('Should have thrown validation error'); } catch (error: any) { expect(error.message).toContain('Configuration validation failed'); expect(error.message).toContain('GRAFANA_URL'); expect(error.message).toContain('GRAFANA_TOKEN'); expect(error.message).toContain('GRAFANA_TIMEOUT'); } }); }); describe('clearConfigCache', () => { it('should clear cached configuration', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; const config1 = getConfig(); clearConfigCache(); // Change environment process.env.GRAFANA_DEBUG = 'true'; const config2 = getConfig(); expect(config1).not.toBe(config2); // Different object references expect(config1.GRAFANA_DEBUG).toBe(false); expect(config2.GRAFANA_DEBUG).toBe(true); }); }); describe('isToolCategoryEnabled', () => { it('should return true for enabled categories', () => { const config: Config = { GRAFANA_URL: 'https://test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: ['admin', 'oncall'], GRAFANA_TLS_SKIP_VERIFY: false, }; expect(isToolCategoryEnabled('dashboards', config)).toBe(true); expect(isToolCategoryEnabled('prometheus', config)).toBe(true); expect(isToolCategoryEnabled('loki', config)).toBe(true); }); it('should return false for disabled categories', () => { const config: Config = { GRAFANA_URL: 'https://test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: ['admin', 'oncall'], GRAFANA_TLS_SKIP_VERIFY: false, }; expect(isToolCategoryEnabled('admin', config)).toBe(false); expect(isToolCategoryEnabled('oncall', config)).toBe(false); }); it('should return true for all categories when none are disabled', () => { const config: Config = { GRAFANA_URL: 'https://test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, }; const allCategories: ToolCategory[] = [ 'dashboards', 'datasources', 'prometheus', 'loki', 'alerting', 'incident', 'sift', 'oncall', 'admin', 'navigation' ]; allCategories.forEach(category => { expect(isToolCategoryEnabled(category, config)).toBe(true); }); }); }); describe('getEnabledToolCategories', () => { it('should return all categories when none are disabled', () => { const config: Config = { GRAFANA_URL: 'https://test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, }; const enabled = getEnabledToolCategories(config); expect(enabled).toEqual([ 'dashboards', 'datasources', 'prometheus', 'loki', 'alerting', 'incident', 'sift', 'oncall', 'admin', 'navigation' ]); }); it('should exclude disabled categories', () => { const config: Config = { GRAFANA_URL: 'https://test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: ['admin', 'oncall', 'incident'], GRAFANA_TLS_SKIP_VERIFY: false, }; const enabled = getEnabledToolCategories(config); expect(enabled).toEqual([ 'dashboards', 'datasources', 'prometheus', 'loki', 'alerting', 'sift', 'navigation' ]); expect(enabled).not.toContain('admin'); expect(enabled).not.toContain('oncall'); expect(enabled).not.toContain('incident'); }); it('should return empty array when all categories are disabled', () => { const config: Config = { GRAFANA_URL: 'https://test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [ 'dashboards', 'datasources', 'prometheus', 'loki', 'alerting', 'incident', 'sift', 'oncall', 'admin', 'navigation' ], GRAFANA_TLS_SKIP_VERIFY: false, }; const enabled = getEnabledToolCategories(config); expect(enabled).toEqual([]); }); }); describe('displayConfig', () => { it('should display basic configuration', () => { const config: Config = { GRAFANA_URL: 'https://grafana.test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, }; displayConfig(config); expect(console.log).toHaveBeenCalledWith('Grafana MCP Server Configuration:'); expect(console.log).toHaveBeenCalledWith(' URL: https://grafana.test.com'); expect(console.log).toHaveBeenCalledWith(' Debug: false'); expect(console.log).toHaveBeenCalledWith(' Timeout: 30000ms'); expect(console.log).toHaveBeenCalledWith(' TLS Skip Verify: false'); expect(console.log).toHaveBeenCalledWith(' Enabled Tools: dashboards, datasources, prometheus, loki, alerting, incident, sift, oncall, admin, navigation'); }); it('should display disabled tools when present', () => { const config: Config = { GRAFANA_URL: 'https://grafana.test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: true, GRAFANA_TIMEOUT: 60000, GRAFANA_DISABLE_TOOLS: ['admin', 'oncall'], GRAFANA_TLS_SKIP_VERIFY: true, }; displayConfig(config); expect(console.log).toHaveBeenCalledWith(' Debug: true'); expect(console.log).toHaveBeenCalledWith(' Timeout: 60000ms'); expect(console.log).toHaveBeenCalledWith(' TLS Skip Verify: true'); expect(console.log).toHaveBeenCalledWith(' Enabled Tools: dashboards, datasources, prometheus, loki, alerting, incident, sift, navigation'); expect(console.log).toHaveBeenCalledWith(' Disabled Tools: admin, oncall'); }); it('should display TLS configuration when present', () => { const config: Config = { GRAFANA_URL: 'https://grafana.test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, GRAFANA_TLS_CERT_FILE: '/path/to/cert.pem', GRAFANA_TLS_KEY_FILE: '/path/to/key.pem', GRAFANA_TLS_CA_FILE: '/path/to/ca.pem', }; displayConfig(config); expect(console.log).toHaveBeenCalledWith(' TLS Configuration:'); expect(console.log).toHaveBeenCalledWith(' Cert File: /path/to/cert.pem'); expect(console.log).toHaveBeenCalledWith(' Key File: /path/to/key.pem'); expect(console.log).toHaveBeenCalledWith(' CA File: /path/to/ca.pem'); }); it('should display partial TLS configuration', () => { const config: Config = { GRAFANA_URL: 'https://grafana.test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, GRAFANA_TLS_CERT_FILE: '/path/to/cert.pem', // No key file or CA file }; displayConfig(config); expect(console.log).toHaveBeenCalledWith(' TLS Configuration:'); expect(console.log).toHaveBeenCalledWith(' Cert File: /path/to/cert.pem'); expect(console.log).not.toHaveBeenCalledWith(expect.stringContaining('Key File')); expect(console.log).not.toHaveBeenCalledWith(expect.stringContaining('CA File')); }); it('should not display TLS section when no TLS config is present', () => { const config: Config = { GRAFANA_URL: 'https://grafana.test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, }; displayConfig(config); expect(console.log).not.toHaveBeenCalledWith(' TLS Configuration:'); }); it('should always end with empty line', () => { const config: Config = { GRAFANA_URL: 'https://grafana.test.com', GRAFANA_TOKEN: 'token', GRAFANA_DEBUG: false, GRAFANA_TIMEOUT: 30000, GRAFANA_DISABLE_TOOLS: [], GRAFANA_TLS_SKIP_VERIFY: false, }; displayConfig(config); const calls = (console.log as any).mock.calls; const lastCall = calls[calls.length - 1]; expect(lastCall[0]).toBe(''); }); }); describe('environment variable edge cases', () => { it('should handle boolean strings case-insensitively', () => { process.env.GRAFANA_URL = 'https://grafana.test'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_DEBUG = 'TRUE'; process.env.GRAFANA_TLS_SKIP_VERIFY = 'False'; const config = getConfig(); // Note: The current implementation only checks for 'true', so 'TRUE' and 'False' would be false expect(config.GRAFANA_DEBUG).toBe(false); // 'TRUE' !== 'true' expect(config.GRAFANA_TLS_SKIP_VERIFY).toBe(false); // 'False' !== 'true' }); it('should handle various URL schemes', () => { const urlTestCases = [ 'http://localhost:3000', 'https://grafana.company.com', 'https://grafana.company.com:8080', 'https://grafana.company.com/path', 'https://grafana.company.com:8080/path', ]; urlTestCases.forEach(url => { clearConfigCache(); process.env.GRAFANA_URL = url; process.env.GRAFANA_TOKEN = 'token'; expect(() => getConfig()).not.toThrow(); const config = getConfig(); expect(config.GRAFANA_URL).toBe(url); }); }); it('should handle timeout parsing edge cases', () => { const timeoutCases = [ { input: '1', expected: 1 }, { input: '999999', expected: 999999 }, { input: '2147483647', expected: 2147483647 }, // Max safe integer ]; timeoutCases.forEach(({ input, expected }) => { clearConfigCache(); process.env.GRAFANA_URL = 'https://test.com'; process.env.GRAFANA_TOKEN = 'token'; process.env.GRAFANA_TIMEOUT = input; const config = getConfig(); expect(config.GRAFANA_TIMEOUT).toBe(expected); }); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/quanticsoul4772/grafana-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server