fix(session-manager): convert blocking sync I/O to async for improved concurrency
Convert session-manager storage layer from synchronous blocking I/O (readdirSync, readFileSync) to non-blocking async I/O (readdir, readFile from fs/promises). This fixes hanging issues in session_search and other tools caused by blocking filesystem operations. Changes: - storage.ts: getAllSessions, readSessionMessages, getSessionInfo now async - utils.ts: Updated utility functions to be async-compatible - tools.ts: Added await calls for async storage functions - storage.test.ts, utils.test.ts: Updated tests with async/await patterns This resolves the session_search tool hang issue and improves overall responsiveness. 🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -1,21 +1,39 @@
|
||||
import { describe, test, expect } from "bun:test"
|
||||
import { formatSessionList, formatSessionMessages, formatSessionInfo, formatSearchResults, filterSessionsByDate, searchInSession } from "./utils"
|
||||
import {
|
||||
formatSessionList,
|
||||
formatSessionMessages,
|
||||
formatSessionInfo,
|
||||
formatSearchResults,
|
||||
filterSessionsByDate,
|
||||
searchInSession,
|
||||
} from "./utils"
|
||||
import type { SessionInfo, SessionMessage, SearchResult } from "./types"
|
||||
|
||||
describe("session-manager utils", () => {
|
||||
test("formatSessionList handles empty array", () => {
|
||||
const result = formatSessionList([])
|
||||
|
||||
test("formatSessionList handles empty array", async () => {
|
||||
// #given
|
||||
const sessions: string[] = []
|
||||
|
||||
// #when
|
||||
const result = await formatSessionList(sessions)
|
||||
|
||||
// #then
|
||||
expect(result).toContain("No sessions found")
|
||||
})
|
||||
|
||||
test("formatSessionMessages handles empty array", () => {
|
||||
const result = formatSessionMessages([])
|
||||
|
||||
// #given
|
||||
const messages: SessionMessage[] = []
|
||||
|
||||
// #when
|
||||
const result = formatSessionMessages(messages)
|
||||
|
||||
// #then
|
||||
expect(result).toContain("No messages")
|
||||
})
|
||||
|
||||
test("formatSessionMessages includes message content", () => {
|
||||
// #given
|
||||
const messages: SessionMessage[] = [
|
||||
{
|
||||
id: "msg_001",
|
||||
@@ -24,14 +42,17 @@ describe("session-manager utils", () => {
|
||||
parts: [{ id: "prt_001", type: "text", text: "Hello world" }],
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
// #when
|
||||
const result = formatSessionMessages(messages)
|
||||
|
||||
|
||||
// #then
|
||||
expect(result).toContain("user")
|
||||
expect(result).toContain("Hello world")
|
||||
})
|
||||
|
||||
test("formatSessionMessages includes todos when requested", () => {
|
||||
// #given
|
||||
const messages: SessionMessage[] = [
|
||||
{
|
||||
id: "msg_001",
|
||||
@@ -40,20 +61,22 @@ describe("session-manager utils", () => {
|
||||
parts: [{ id: "prt_001", type: "text", text: "Test" }],
|
||||
},
|
||||
]
|
||||
|
||||
const todos = [
|
||||
{ id: "1", content: "Task 1", status: "completed" as const },
|
||||
{ id: "2", content: "Task 2", status: "pending" as const },
|
||||
]
|
||||
|
||||
|
||||
// #when
|
||||
const result = formatSessionMessages(messages, true, todos)
|
||||
|
||||
|
||||
// #then
|
||||
expect(result).toContain("Todos")
|
||||
expect(result).toContain("Task 1")
|
||||
expect(result).toContain("Task 2")
|
||||
})
|
||||
|
||||
test("formatSessionInfo includes all metadata", () => {
|
||||
// #given
|
||||
const info: SessionInfo = {
|
||||
id: "ses_test123",
|
||||
message_count: 42,
|
||||
@@ -65,9 +88,11 @@ describe("session-manager utils", () => {
|
||||
todos: [{ id: "1", content: "Test", status: "pending" }],
|
||||
transcript_entries: 123,
|
||||
}
|
||||
|
||||
|
||||
// #when
|
||||
const result = formatSessionInfo(info)
|
||||
|
||||
|
||||
// #then
|
||||
expect(result).toContain("ses_test123")
|
||||
expect(result).toContain("42")
|
||||
expect(result).toContain("build, oracle")
|
||||
@@ -75,12 +100,18 @@ describe("session-manager utils", () => {
|
||||
})
|
||||
|
||||
test("formatSearchResults handles empty array", () => {
|
||||
const result = formatSearchResults([])
|
||||
|
||||
// #given
|
||||
const results: SearchResult[] = []
|
||||
|
||||
// #when
|
||||
const result = formatSearchResults(results)
|
||||
|
||||
// #then
|
||||
expect(result).toContain("No matches")
|
||||
})
|
||||
|
||||
test("formatSearchResults formats matches correctly", () => {
|
||||
// #given
|
||||
const results: SearchResult[] = [
|
||||
{
|
||||
session_id: "ses_test123",
|
||||
@@ -91,9 +122,11 @@ describe("session-manager utils", () => {
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
// #when
|
||||
const result = formatSearchResults(results)
|
||||
|
||||
|
||||
// #then
|
||||
expect(result).toContain("Found 1 matches")
|
||||
expect(result).toContain("ses_test123")
|
||||
expect(result).toContain("msg_001")
|
||||
@@ -101,17 +134,26 @@ describe("session-manager utils", () => {
|
||||
expect(result).toContain("Matches: 3")
|
||||
})
|
||||
|
||||
test("filterSessionsByDate filters correctly", () => {
|
||||
test("filterSessionsByDate filters correctly", async () => {
|
||||
// #given
|
||||
const sessionIDs = ["ses_001", "ses_002", "ses_003"]
|
||||
|
||||
const result = filterSessionsByDate(sessionIDs)
|
||||
|
||||
|
||||
// #when
|
||||
const result = await filterSessionsByDate(sessionIDs)
|
||||
|
||||
// #then
|
||||
expect(Array.isArray(result)).toBe(true)
|
||||
})
|
||||
|
||||
test("searchInSession finds matches case-insensitively", () => {
|
||||
const results = searchInSession("ses_nonexistent", "test", false)
|
||||
|
||||
test("searchInSession finds matches case-insensitively", async () => {
|
||||
// #given
|
||||
const sessionID = "ses_nonexistent"
|
||||
const query = "test"
|
||||
|
||||
// #when
|
||||
const results = await searchInSession(sessionID, query, false)
|
||||
|
||||
// #then
|
||||
expect(Array.isArray(results)).toBe(true)
|
||||
expect(results.length).toBe(0)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user