Files
wehub-resource-sync f99010fae1
CI / lint (push) Failing after 1s
CI / frontend (push) Failing after 1s
CI / scripts (push) Failing after 1s
CI / Go Test (ubuntu-latest) (push) Failing after 0s
CI / frontend-node-25 (push) Failing after 1s
CI / docs (push) Failing after 0s
CI / coverage (push) Failing after 0s
CI / e2e (push) Failing after 0s
Docker / build-and-push (push) Failing after 1s
CI / integration (push) Failing after 4m43s
CI / Go Test (windows-latest) (push) Has been cancelled
CI / Desktop Unit Tests (Windows) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux (arm64)) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Linux) (push) Has been cancelled
Desktop Artifacts / Desktop Build (Windows) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (aarch64)) (push) Has been cancelled
Desktop Artifacts (macOS) / Desktop Build (macOS (x86_64)) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:30:36 +08:00

320 lines
11 KiB
Go

package db
import (
"context"
"database/sql"
"fmt"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestExecWithoutCancelDropsTempTableWithCanceledContext(t *testing.T) {
path := filepath.Join(t.TempDir(), "test.db")
pool, err := sql.Open("sqlite3", path)
require.NoError(t, err, "open sqlite")
defer pool.Close()
baseCtx := context.Background()
conn, err := pool.Conn(baseCtx)
require.NoError(t, err, "pin sqlite connection")
defer conn.Close()
_, err = conn.ExecContext(baseCtx, `
CREATE TEMP TABLE _test_cleanup (
id TEXT PRIMARY KEY
)`)
require.NoError(t, err, "create temp table")
ctx, cancel := context.WithCancel(baseCtx)
cancel()
_, err = execWithoutCancel(ctx, conn,
"DROP TABLE IF EXISTS _test_cleanup")
require.NoError(t, err, "drop with canceled context")
_, err = conn.ExecContext(baseCtx, `
CREATE TEMP TABLE _test_cleanup (
id TEXT PRIMARY KEY
)`)
require.NoError(t, err, "recreate temp table after cleanup")
}
func TestCopyOrphanedDataSanitizesCopiedContent(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()
srcPath := filepath.Join(dir, "old.db")
srcDB := testDBAtPath(t, srcPath, "src")
insertSession(t, srcDB, "poison-orphan", "proj")
insertMessages(t, srcDB, userMsg("poison-orphan", 0, "clean"))
var messageID int64
require.NoError(t, srcDB.getWriter().QueryRowContext(ctx,
`SELECT id FROM messages WHERE session_id = ? AND ordinal = 0`,
"poison-orphan",
).Scan(&messageID), "query source message id")
messageContent := "message\x00body\x01\nkept"
toolInput := "{\"cmd\":\"tool\x00input\x04\"}"
emptyToolInput := "\x00\x04"
toolResult := "tool\x00result\x02"
emptyToolResult := "\x00\x04"
eventContent := "event\x00content\x03"
const (
messageLengthExcess = 7
toolLengthExcess = 11
eventLengthExcess = 5
emptyResultLength = 7
)
_, err := srcDB.getWriter().ExecContext(ctx,
`UPDATE messages
SET content = ?, content_length = ?
WHERE id = ?`,
messageContent, len(messageContent)+messageLengthExcess, messageID,
)
require.NoError(t, err, "plant poisoned message")
_, err = srcDB.getWriter().ExecContext(ctx,
`INSERT INTO tool_calls (
message_id, session_id, tool_name, category,
tool_use_id, input_json, result_content_length,
result_content, call_index
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
messageID, "poison-orphan", "Read", "file", "tool-1",
toolInput, len(toolResult)+toolLengthExcess, toolResult, 0,
)
require.NoError(t, err, "plant poisoned tool call")
_, err = srcDB.getWriter().ExecContext(ctx,
`INSERT INTO tool_calls (
message_id, session_id, tool_name, category,
tool_use_id, input_json, call_index
) VALUES (?, ?, ?, ?, ?, ?, ?)`,
messageID, "poison-orphan", "Read", "file", "tool-empty",
emptyToolInput, 1,
)
require.NoError(t, err, "plant empty-sanitized tool input")
_, err = srcDB.getWriter().ExecContext(ctx,
`INSERT INTO tool_calls (
message_id, session_id, tool_name, category,
tool_use_id, result_content_length, result_content,
call_index
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
messageID, "poison-orphan", "Read", "file", "tool-empty-result",
emptyResultLength, emptyToolResult, 2,
)
require.NoError(t, err, "plant empty-sanitized tool result")
_, err = srcDB.getWriter().ExecContext(ctx,
`INSERT INTO tool_result_events (
session_id, tool_call_message_ordinal, call_index,
tool_use_id, source, status, content, content_length,
event_index
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
"poison-orphan", 0, 0, "tool-1", "tool_result", "ok",
eventContent, len(eventContent)+eventLengthExcess, 0,
)
require.NoError(t, err, "plant poisoned tool result event")
// Dirty content only exists in archives written before
// sanitizedSourceDataVersion; sources at or above it skip the
// sanitize pass entirely.
_, err = srcDB.getWriter().ExecContext(ctx, fmt.Sprintf(
"PRAGMA user_version = %d", sanitizedSourceDataVersion-1,
))
require.NoError(t, err, "downgrade source data version")
require.NoError(t, srcDB.Close(), "close source")
dstPath := filepath.Join(dir, "new.db")
dstDB := testDBAtPath(t, dstPath, "dst")
defer dstDB.Close()
count, err := dstDB.CopyOrphanedDataFrom(srcPath)
require.NoError(t, err, "CopyOrphanedDataFrom")
require.Equal(t, 1, count, "expected one orphan")
var gotMessage string
var gotMessageLength int
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT content, content_length
FROM messages
WHERE session_id = ? AND ordinal = 0`,
"poison-orphan",
).Scan(&gotMessage, &gotMessageLength), "query copied message")
wantMessage := SanitizeUTF8(messageContent)
assert.Equal(t, wantMessage, gotMessage)
assert.Equal(t, len(wantMessage)+messageLengthExcess, gotMessageLength)
var gotToolInput string
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT input_json
FROM tool_calls
WHERE session_id = ? AND call_index = 0`,
"poison-orphan",
).Scan(&gotToolInput), "query copied tool input")
assert.Equal(t, SanitizeUTF8(toolInput), gotToolInput)
var gotEmptyToolInput sql.NullString
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT input_json
FROM tool_calls
WHERE session_id = ? AND call_index = 1`,
"poison-orphan",
).Scan(&gotEmptyToolInput), "query empty copied tool input")
assert.False(t, gotEmptyToolInput.Valid)
var gotToolResult string
var gotToolResultLength int
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT result_content, result_content_length
FROM tool_calls
WHERE session_id = ? AND call_index = 0`,
"poison-orphan",
).Scan(&gotToolResult, &gotToolResultLength), "query copied tool call")
wantToolResult := SanitizeUTF8(toolResult)
assert.Equal(t, wantToolResult, gotToolResult)
assert.Equal(t, len(wantToolResult)+toolLengthExcess, gotToolResultLength)
var gotEmptyToolResult sql.NullString
var gotEmptyToolResultLength sql.NullInt64
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT result_content, result_content_length
FROM tool_calls
WHERE session_id = ? AND call_index = 2`,
"poison-orphan",
).Scan(
&gotEmptyToolResult,
&gotEmptyToolResultLength,
), "query empty copied tool call result")
assert.False(t, gotEmptyToolResult.Valid)
require.True(t, gotEmptyToolResultLength.Valid)
assert.Equal(t,
int64(emptyResultLength-len(emptyToolResult)),
gotEmptyToolResultLength.Int64,
)
var gotEventContent string
var gotEventLength int
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT content, content_length
FROM tool_result_events
WHERE session_id = ? AND event_index = 0`,
"poison-orphan",
).Scan(&gotEventContent, &gotEventLength), "query copied tool result event")
wantEventContent := SanitizeUTF8(eventContent)
assert.Equal(t, wantEventContent, gotEventContent)
assert.Equal(t, len(wantEventContent)+eventLengthExcess, gotEventLength)
}
// TestCopySkipsSanitizeForSanitizedSource guards the resync fast
// path: each sanitize pass is skipped once the source data version
// proves ingest already sanitized that field — content/results at
// sanitizedSourceDataVersion, input_json at the later
// sanitizedInputSourceDataVersion — and skipped rows survive the
// copy verbatim.
func TestCopySkipsSanitizeForSanitizedSource(t *testing.T) {
const rawContent = "nul\x00byte\x01kept"
const rawToolInput = "{\"cmd\":\"a\x00b\x01\"}"
const rawToolResult = "result\x00kept\x01"
copies := []struct {
name string
trash bool
copy func(dst *DB, srcPath string) (int, error)
}{
{
name: "orphaned",
copy: func(dst *DB, srcPath string) (int, error) {
return dst.CopyOrphanedDataFrom(srcPath)
},
},
{
name: "trashed",
trash: true,
copy: func(dst *DB, srcPath string) (int, error) {
return dst.CopyTrashedDataFrom(srcPath)
},
},
}
versions := []struct {
name string
sourceVersion int
wantInput string
}{
{
// Ingest at v58 sanitized content and results but not
// input_json, so only the input pass runs for it.
name: "content-sanitized source pays input pass",
sourceVersion: sanitizedSourceDataVersion,
wantInput: SanitizeUTF8(rawToolInput),
},
{
// A source at the input watermark is fully clean; every
// pass is skipped and rows copy verbatim.
name: "fully sanitized source copies verbatim",
sourceVersion: sanitizedInputSourceDataVersion,
wantInput: rawToolInput,
},
}
for _, cp := range copies {
for _, ver := range versions {
t.Run(cp.name+"/"+ver.name, func(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()
srcPath := filepath.Join(dir, "old.db")
srcDB := testDBAtPath(t, srcPath, "src")
insertSession(t, srcDB, "sess", "proj")
insertMessages(t, srcDB, userMsg("sess", 0, "clean"))
_, err := srcDB.getWriter().ExecContext(ctx,
`UPDATE messages SET content = ? WHERE session_id = ?`,
rawContent, "sess",
)
require.NoError(t, err, "plant raw content")
var messageID int64
require.NoError(t, srcDB.getWriter().QueryRowContext(ctx,
`SELECT id FROM messages WHERE session_id = ?`, "sess",
).Scan(&messageID), "read message id")
_, err = srcDB.getWriter().ExecContext(ctx,
`INSERT INTO tool_calls (
message_id, session_id, tool_name, category,
tool_use_id, input_json, result_content_length,
result_content, call_index
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
messageID, "sess", "Bash", "execution", "tool-1",
rawToolInput, len(rawToolResult), rawToolResult, 0,
)
require.NoError(t, err, "plant raw tool call")
_, err = srcDB.getWriter().ExecContext(ctx, fmt.Sprintf(
"PRAGMA user_version = %d", ver.sourceVersion,
))
require.NoError(t, err, "set source data version")
if cp.trash {
require.NoError(t, srcDB.SoftDeleteSession("sess"),
"soft delete source session")
}
require.NoError(t, srcDB.Close(), "close source")
dstDB := testDBAtPath(t, filepath.Join(dir, "new.db"), "dst")
defer dstDB.Close()
count, err := cp.copy(dstDB, srcPath)
require.NoError(t, err, "copy from source")
require.Equal(t, 1, count, "copied sessions")
var got string
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT content FROM messages WHERE session_id = ?`,
"sess",
).Scan(&got), "query copied message")
assert.Equal(t, rawContent, got,
"content-sanitized source must copy content verbatim")
var gotInput, gotResult string
require.NoError(t, dstDB.getReader().QueryRowContext(ctx,
`SELECT input_json, result_content
FROM tool_calls WHERE session_id = ?`,
"sess",
).Scan(&gotInput, &gotResult), "query copied tool call")
assert.Equal(t, ver.wantInput, gotInput)
assert.Equal(t, rawToolResult, gotResult,
"tool result must copy verbatim for sanitized sources")
})
}
}
}