Skip to main content
Glama
security-scanner-pagination-unit-test.jsโ€ข8.73 kB
/** * Unit Test for scan_security_vulnerabilities Pagination Logic */ // Mock vulnerability data for testing function createMockVulnData(count = 10) { const vulnerabilities = []; const severities = ['low', 'moderate', 'high', 'critical']; for (let i = 0; i < count; i++) { vulnerabilities.push({ package: `package-${i}`, severity: severities[i % severities.length], title: `Vulnerability ${i} in package-${i}`, url: `https://example.com/vuln-${i}`, range: '>=1.0.0 <2.0.0', fixAvailable: i % 2 === 0 }); } return { vulnerabilities, summary: { info: 0, low: Math.floor(count * 0.3), moderate: Math.floor(count * 0.3), high: Math.floor(count * 0.2), critical: Math.floor(count * 0.2), total: count }, fixCommands: ['npm audit fix'], hasVulnerabilities: count > 0 }; } // Import the pagination function (we need to make it exportable) // For now, let's recreate the logic here for testing const SEVERITY_LEVELS = { low: 1, moderate: 2, high: 3, critical: 4, }; function applyPaginationAndSorting(vulnData, options) { const { limit, offset, sortBy, sortOrder } = options; const { vulnerabilities, ...rest } = vulnData; // Sort vulnerabilities const sortedVulnerabilities = [...vulnerabilities].sort((a, b) => { let comparison = 0; switch (sortBy) { case 'severity': const aSeverity = SEVERITY_LEVELS[a.severity] || 0; const bSeverity = SEVERITY_LEVELS[b.severity] || 0; comparison = aSeverity - bSeverity; break; case 'package': comparison = a.package.localeCompare(b.package); break; case 'title': comparison = (a.title || '').localeCompare(b.title || ''); break; default: comparison = 0; } return sortOrder === 'desc' ? -comparison : comparison; }); // Apply pagination const totalVulnerabilities = sortedVulnerabilities.length; const paginatedVulnerabilities = sortedVulnerabilities.slice(offset, offset + limit); const hasMore = offset + limit < totalVulnerabilities; const nextOffset = hasMore ? offset + limit : null; return { ...rest, vulnerabilities: paginatedVulnerabilities, pagination: { offset, limit, totalVulnerabilities, hasMore, nextOffset, currentPage: Math.floor(offset / limit) + 1, totalPages: Math.ceil(totalVulnerabilities / limit) } }; } function formatVulnerabilityReport(vulnData, format, manager, options = {}) { const { vulnerabilities, summary, fixCommands, hasVulnerabilities, pagination } = vulnData; const { sortBy, sortOrder } = options; let output = '๐Ÿ”’ Security Vulnerability Scan Results:\\n\\n'; // Add pagination info if available if (pagination) { output += `๐Ÿ“„ Results: Page ${pagination.currentPage} of ${pagination.totalPages} ` + `(${pagination.offset + 1}-${Math.min(pagination.offset + pagination.limit, pagination.totalVulnerabilities)} ` + `of ${pagination.totalVulnerabilities} vulnerabilities)\\n`; output += `๐Ÿ”„ Sorted by: ${sortBy} (${sortOrder})\\n\\n`; } if (!hasVulnerabilities) { output += 'โœ… No security vulnerabilities found!\\n'; return output; } // Summary output += `๐Ÿ“Š Summary (Total: ${summary.total}):\\n`; if (summary.critical > 0) output += ` ๐Ÿ”ด Critical: ${summary.critical}\\n`; if (summary.high > 0) output += ` ๐ŸŸ  High: ${summary.high}\\n`; if (summary.moderate > 0) output += ` ๐ŸŸก Moderate: ${summary.moderate}\\n`; if (summary.low > 0) output += ` ๐ŸŸข Low: ${summary.low}\\n`; output += '\\n'; // Vulnerabilities list if (vulnerabilities.length > 0) { output += `๐Ÿ” Vulnerabilities (showing ${vulnerabilities.length}):\\n`; vulnerabilities.forEach((vuln, i) => { output += `\\n${i + 1}. ${vuln.package}\\n`; output += ` Severity: ${vuln.severity}\\n`; output += ` Title: ${vuln.title}\\n`; if (vuln.fixAvailable) output += ' โœ… Fix available\\n'; }); output += '\\n'; } // Pagination navigation if (pagination && pagination.totalVulnerabilities > 0) { output += '\\n๐Ÿ“„ Pagination:\\n'; if (pagination.offset > 0) { const prevOffset = Math.max(0, pagination.offset - pagination.limit); output += ` โ† Previous: offset=${prevOffset}, limit=${pagination.limit}\\n`; } if (pagination.hasMore) { output += ` โ†’ Next: offset=${pagination.nextOffset}, limit=${pagination.limit}\\n`; } output += ` ๐Ÿ“Š Total vulnerabilities: ${pagination.totalVulnerabilities}\\n`; output += '\\n'; } return output; } async function testPaginationLogic() { console.log('๐Ÿงช Testing Pagination Logic with Mock Data'); console.log('=========================================='); // Test 1: Basic pagination console.log('โœ“ Testing basic pagination...'); const mockData = createMockVulnData(20); const paginatedData = applyPaginationAndSorting(mockData, { limit: 5, offset: 0, sortBy: 'severity', sortOrder: 'desc' }); console.log('โœ… Basic pagination results:'); console.log(' - Total vulnerabilities:', paginatedData.pagination.totalVulnerabilities); console.log(' - Returned vulnerabilities:', paginatedData.vulnerabilities.length); console.log(' - Has more:', paginatedData.pagination.hasMore); console.log(' - Next offset:', paginatedData.pagination.nextOffset); console.log(' - Current page:', paginatedData.pagination.currentPage); console.log(' - Total pages:', paginatedData.pagination.totalPages); // Test 2: Severity sorting console.log('\\nโœ“ Testing severity sorting...'); const severitySorted = applyPaginationAndSorting(mockData, { limit: 10, offset: 0, sortBy: 'severity', sortOrder: 'desc' }); const severityOrder = severitySorted.vulnerabilities.map(v => v.severity); console.log('โœ… Severity order (desc):', severityOrder.slice(0, 5)); // Verify descending order let properlyOrdered = true; for (let i = 1; i < severitySorted.vulnerabilities.length; i++) { const prev = SEVERITY_LEVELS[severitySorted.vulnerabilities[i-1].severity]; const curr = SEVERITY_LEVELS[severitySorted.vulnerabilities[i].severity]; if (prev < curr) { properlyOrdered = false; break; } } console.log(' - Properly ordered:', properlyOrdered); // Test 3: Package name sorting console.log('\\nโœ“ Testing package name sorting...'); const packageSorted = applyPaginationAndSorting(mockData, { limit: 10, offset: 0, sortBy: 'package', sortOrder: 'asc' }); const packageOrder = packageSorted.vulnerabilities.map(v => v.package); console.log('โœ… Package order (asc):', packageOrder.slice(0, 5)); // Test 4: Format output console.log('\\nโœ“ Testing format output...'); const report = formatVulnerabilityReport(paginatedData, 'detailed', 'npm', { sortBy: 'severity', sortOrder: 'desc' }); console.log('โœ… Report formatting:'); console.log(' - Contains pagination header:', report.includes('๐Ÿ“„ Results:')); console.log(' - Contains sorting info:', report.includes('๐Ÿ”„ Sorted by:')); console.log(' - Contains pagination navigation:', report.includes('๐Ÿ“„ Pagination:')); console.log(' - Contains next navigation:', report.includes('โ†’ Next:')); // Test 5: Edge cases console.log('\\nโœ“ Testing edge cases...'); // Empty data const emptyData = createMockVulnData(0); const emptyPaginated = applyPaginationAndSorting(emptyData, { limit: 5, offset: 0, sortBy: 'severity', sortOrder: 'desc' }); console.log('โœ… Empty data handling:', emptyPaginated.vulnerabilities.length === 0); // High offset const highOffsetData = applyPaginationAndSorting(mockData, { limit: 5, offset: 100, sortBy: 'severity', sortOrder: 'desc' }); console.log('โœ… High offset handling:', highOffsetData.vulnerabilities.length === 0); // Last page const lastPageData = applyPaginationAndSorting(mockData, { limit: 5, offset: 15, // For 20 items, offset 15 should give last 5 sortBy: 'severity', sortOrder: 'desc' }); console.log('โœ… Last page handling:'); console.log(' - Items returned:', lastPageData.vulnerabilities.length); console.log(' - Has more:', lastPageData.pagination.hasMore); console.log(' - Next offset:', lastPageData.pagination.nextOffset); console.log('\\n๐ŸŽ‰ All pagination logic tests completed successfully!'); } // Run tests if called directly if (import.meta.url === `file://${process.argv[1]}`) { testPaginationLogic(); }

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/moikas-code/moidvk'

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