260 lines
6.8 KiB
JavaScript
260 lines
6.8 KiB
JavaScript
const LogService = require("../../../src/tui/services/LogService.js");
|
|
|
|
describe("LogService Performance Optimizations", () => {
|
|
let service;
|
|
|
|
beforeEach(() => {
|
|
service = new LogService("test-progress.md");
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
afterEach(() => {
|
|
if (service) {
|
|
service.destroy();
|
|
}
|
|
});
|
|
|
|
describe("efficient pagination", () => {
|
|
it("should paginate logs efficiently", () => {
|
|
const logs = Array.from({ length: 100 }, (_, i) => ({
|
|
id: `log_${i}`,
|
|
timestamp: new Date(),
|
|
title: `Log Entry ${i}`,
|
|
message: `Message ${i}`,
|
|
level: "INFO",
|
|
}));
|
|
|
|
const result = service.paginateLogs(logs, 2, 10); // Page 2, 10 items per page
|
|
|
|
expect(result.entries).toHaveLength(10);
|
|
expect(result.pagination.currentPage).toBe(2);
|
|
expect(result.pagination.totalPages).toBe(10);
|
|
expect(result.pagination.hasNextPage).toBe(true);
|
|
expect(result.pagination.hasPreviousPage).toBe(true);
|
|
expect(result.pagination.startIndex).toBe(21); // 1-based index
|
|
expect(result.pagination.endIndex).toBe(30);
|
|
});
|
|
|
|
it("should handle edge cases in pagination", () => {
|
|
const logs = Array.from({ length: 5 }, (_, i) => ({
|
|
id: `log_${i}`,
|
|
timestamp: new Date(),
|
|
title: `Log Entry ${i}`,
|
|
message: `Message ${i}`,
|
|
level: "INFO",
|
|
}));
|
|
|
|
// Last page
|
|
const result = service.paginateLogs(logs, 0, 10);
|
|
|
|
expect(result.entries).toHaveLength(5);
|
|
expect(result.pagination.totalPages).toBe(1);
|
|
expect(result.pagination.hasNextPage).toBe(false);
|
|
expect(result.pagination.hasPreviousPage).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("streaming for large files", () => {
|
|
it("should parse log content in streaming mode", async () => {
|
|
const mockContent = "Test log content";
|
|
|
|
const result = await service.parseLogContentStreaming(
|
|
mockContent,
|
|
{
|
|
dateRange: "all",
|
|
operationType: "all",
|
|
status: "all",
|
|
searchTerm: "",
|
|
},
|
|
0,
|
|
10
|
|
);
|
|
|
|
expect(result).toHaveProperty("entries");
|
|
expect(result).toHaveProperty("totalCount");
|
|
expect(Array.isArray(result.entries)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("caching optimizations", () => {
|
|
it("should track cache statistics", () => {
|
|
const stats = service.getCacheStats();
|
|
|
|
expect(stats).toHaveProperty("size");
|
|
expect(stats).toHaveProperty("keys");
|
|
expect(typeof stats.size).toBe("number");
|
|
expect(Array.isArray(stats.keys)).toBe(true);
|
|
});
|
|
|
|
it("should provide memory usage statistics", () => {
|
|
const stats = service.getMemoryStats();
|
|
|
|
expect(stats).toHaveProperty("cacheEntries");
|
|
expect(stats).toHaveProperty("estimatedSizeBytes");
|
|
expect(stats).toHaveProperty("estimatedSizeMB");
|
|
expect(stats).toHaveProperty("maxEntries");
|
|
expect(stats).toHaveProperty("cacheHitRatio");
|
|
});
|
|
});
|
|
|
|
describe("memory management", () => {
|
|
it("should clean up expired cache entries", () => {
|
|
// Add some cache entries with old timestamps
|
|
service.cache.set("old_entry", {
|
|
data: { test: "data" },
|
|
timestamp: Date.now() - 10 * 60 * 1000, // 10 minutes ago
|
|
});
|
|
|
|
service.cache.set("new_entry", {
|
|
data: { test: "data" },
|
|
timestamp: Date.now(),
|
|
});
|
|
|
|
expect(service.cache.size).toBe(2);
|
|
|
|
service.cleanup();
|
|
|
|
expect(service.cache.size).toBe(1);
|
|
expect(service.cache.has("new_entry")).toBe(true);
|
|
expect(service.cache.has("old_entry")).toBe(false);
|
|
});
|
|
|
|
it("should limit cache size to prevent memory issues", () => {
|
|
// Fill cache beyond limit
|
|
for (let i = 0; i < 40; i++) {
|
|
service.cache.set(`entry_${i}`, {
|
|
data: { large: "data".repeat(1000) },
|
|
timestamp: Date.now() - i * 1000, // Different timestamps
|
|
});
|
|
}
|
|
|
|
expect(service.cache.size).toBeGreaterThan(30);
|
|
|
|
service.cleanup();
|
|
|
|
expect(service.cache.size).toBeLessThanOrEqual(30);
|
|
});
|
|
|
|
it("should clean up resources on destroy", () => {
|
|
service.destroy();
|
|
|
|
expect(service.cache.size).toBe(0);
|
|
expect(service.cleanupInterval).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("filtering optimizations", () => {
|
|
it("should filter logs efficiently", () => {
|
|
const logs = [
|
|
{
|
|
id: "log_1",
|
|
timestamp: new Date("2024-01-01"),
|
|
title: "Update Product A",
|
|
message: "Product updated successfully",
|
|
level: "SUCCESS",
|
|
type: "update",
|
|
details: "Product A details",
|
|
productTitle: "Product A",
|
|
},
|
|
{
|
|
id: "log_2",
|
|
timestamp: new Date("2024-01-02"),
|
|
title: "Error Product B",
|
|
message: "Product update failed",
|
|
level: "ERROR",
|
|
type: "update",
|
|
details: "Product B error details",
|
|
productTitle: "Product B",
|
|
},
|
|
{
|
|
id: "log_3",
|
|
timestamp: new Date("2024-01-03"),
|
|
title: "Rollback Product C",
|
|
message: "Product rollback completed",
|
|
level: "INFO",
|
|
type: "rollback",
|
|
details: "Product C rollback details",
|
|
productTitle: "Product C",
|
|
},
|
|
];
|
|
|
|
// Filter by operation type
|
|
const updateLogs = service.filterLogs(logs, { operationType: "update" });
|
|
expect(updateLogs).toHaveLength(2);
|
|
|
|
// Filter by status
|
|
const errorLogs = service.filterLogs(logs, { status: "error" });
|
|
expect(errorLogs).toHaveLength(1);
|
|
expect(errorLogs[0].level).toBe("ERROR");
|
|
|
|
// Filter by search term
|
|
const productALogs = service.filterLogs(logs, {
|
|
searchTerm: "Product A",
|
|
});
|
|
expect(productALogs).toHaveLength(1);
|
|
expect(productALogs[0].productTitle).toBe("Product A");
|
|
});
|
|
|
|
it("should handle date range filtering", () => {
|
|
const now = new Date();
|
|
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000);
|
|
const lastWeek = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
|
|
|
|
const logs = [
|
|
{
|
|
id: "log_1",
|
|
timestamp: now,
|
|
title: "Recent Log",
|
|
message: "Recent message",
|
|
level: "INFO",
|
|
},
|
|
{
|
|
id: "log_2",
|
|
timestamp: yesterday,
|
|
title: "Yesterday Log",
|
|
message: "Yesterday message",
|
|
level: "INFO",
|
|
},
|
|
{
|
|
id: "log_3",
|
|
timestamp: lastWeek,
|
|
title: "Old Log",
|
|
message: "Old message",
|
|
level: "INFO",
|
|
},
|
|
];
|
|
|
|
// Filter by today
|
|
const todayLogs = service.filterLogs(logs, { dateRange: "today" });
|
|
expect(todayLogs).toHaveLength(1);
|
|
expect(todayLogs[0].title).toBe("Recent Log");
|
|
|
|
// Filter by week
|
|
const weekLogs = service.filterLogs(logs, { dateRange: "week" });
|
|
expect(weekLogs.length).toBeGreaterThanOrEqual(2); // Should include recent and yesterday
|
|
});
|
|
});
|
|
|
|
describe("preloading", () => {
|
|
it("should preload next page without blocking", async () => {
|
|
const options = {
|
|
page: 0,
|
|
pageSize: 10,
|
|
dateRange: "all",
|
|
operationType: "all",
|
|
status: "all",
|
|
searchTerm: "",
|
|
};
|
|
|
|
// Mock the getFilteredLogs method to avoid actual file operations
|
|
service.getFilteredLogs = jest.fn().mockResolvedValue({
|
|
entries: [],
|
|
pagination: { hasNextPage: true },
|
|
});
|
|
|
|
// Preload should not throw errors
|
|
await expect(service.preloadNextPage(options)).resolves.toBeUndefined();
|
|
});
|
|
});
|
|
});
|