import { describe, it, expect, vi, beforeEach } from "vitest";
import { createIndexesResource } from "../indexes.js";
import type { MySQLAdapter } from "../../MySQLAdapter.js";
import {
createMockMySQLAdapter,
createMockRequestContext,
createMockQueryResult,
} from "../../../../__tests__/mocks/index.js";
describe("createIndexesResource", () => {
let mockAdapter: ReturnType<typeof createMockMySQLAdapter>;
let mockContext: ReturnType<typeof createMockRequestContext>;
let resource: ReturnType<typeof createIndexesResource>;
beforeEach(() => {
vi.clearAllMocks();
mockAdapter = createMockMySQLAdapter();
mockContext = createMockRequestContext();
resource = createIndexesResource(mockAdapter as unknown as MySQLAdapter);
});
it("should return error if no database selected", async () => {
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([])); // DB select returns empty/null
const result = await resource.handler(resource.uri, mockContext);
expect(result).toEqual({ error: "No database selected" });
});
it("should return index stats, unused, and duplicates when all queries succeed", async () => {
// Mock Database select
mockAdapter.executeQuery.mockResolvedValueOnce(
createMockQueryResult([{ db: "test_db" }]),
);
// Mock Index Stats
mockAdapter.executeQuery.mockResolvedValueOnce(
createMockQueryResult([
{ table_name: "users", index_name: "PRIMARY", non_unique: 0 },
]),
);
// Mock Unused Indexes
mockAdapter.executeQuery.mockResolvedValueOnce(
createMockQueryResult([
{ schema_name: "test_db", table_name: "users", index_name: "idx_old" },
]),
);
// Mock Duplicate Indexes
mockAdapter.executeQuery.mockResolvedValueOnce(
createMockQueryResult([
{
table_name: "users",
redundant_index: "idx_dup",
dominant_index: "PRIMARY",
},
]),
);
const result = await resource.handler(resource.uri, mockContext);
expect(result).toEqual({
database: "test_db",
total_indexes: 1,
indexes: expect.any(Array),
unused_indexes: expect.any(Array),
potential_duplicates: expect.any(Array),
});
expect((result as any).indexes).toHaveLength(1);
expect((result as any).unused_indexes).toHaveLength(1);
expect((result as any).potential_duplicates).toHaveLength(1);
});
it("should handle failures in optional queries (unused/duplicates) gracefully", async () => {
// Mock Database select
mockAdapter.executeQuery.mockResolvedValueOnce(
createMockQueryResult([{ db: "test_db" }]),
);
// Mock Index Stats
mockAdapter.executeQuery.mockResolvedValueOnce(createMockQueryResult([]));
// Mock Unused Indexes FAILURE
mockAdapter.executeQuery.mockRejectedValueOnce(
new Error("Performance Schema error"),
);
// Mock Duplicate Indexes FAILURE
mockAdapter.executeQuery.mockRejectedValueOnce(
new Error("Info Schema error"),
);
const result = await resource.handler(resource.uri, mockContext);
expect(result).toEqual({
database: "test_db",
total_indexes: 0,
indexes: [],
unused_indexes: [], // Should default to empty array on error
potential_duplicates: [], // Should default to empty array on error
});
});
it("should handle undefined rows gracefully", async () => {
// Mock Database select with undefined rows
mockAdapter.executeQuery.mockResolvedValueOnce({ rows: undefined } as any);
// First attempt with undefined rows for database selection
const result1 = await resource.handler(resource.uri, mockContext);
expect(result1).toEqual({ error: "No database selected" });
// Now test undefined rows for other queries
mockAdapter.executeQuery.mockResolvedValueOnce(
createMockQueryResult([{ db: "test_db" }]),
);
mockAdapter.executeQuery.mockResolvedValueOnce({ rows: undefined } as any); // Indexes
mockAdapter.executeQuery.mockResolvedValueOnce({ rows: undefined } as any); // Unused
mockAdapter.executeQuery.mockResolvedValueOnce({ rows: undefined } as any); // Duplicates
const result2 = await resource.handler(resource.uri, mockContext);
expect(result2).toEqual({
database: "test_db",
total_indexes: 0,
indexes: [],
unused_indexes: [],
potential_duplicates: [],
});
});
});