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

591 lines
22 KiB
Go

package parser
import (
"context"
"database/sql"
"os"
"path/filepath"
"testing"
"time"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestKiroProviderSourceMethods(t *testing.T) {
root := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "sqlite-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
seedKiroSQLiteSession(
t, db, "/home/user/code/shadowed", "shadowed-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012040000,
)
legacyPath := filepath.Join(root, "legacy-session.jsonl")
writeSourceFile(t, legacyPath, kiroProviderJSONLFixture("Legacy question"))
writeSourceFile(t, filepath.Join(root, "legacy-session.json"),
kiroProviderMetaFixture("legacy-session", "/home/user/code/legacy"))
shadowedPath := filepath.Join(root, "shadowed-session.jsonl")
writeSourceFile(t, shadowedPath, kiroProviderJSONLFixture("Shadowed question"))
writeSourceFile(t, filepath.Join(root, "notes", "nested.jsonl"), "{}\n")
provider, ok := NewProvider(AgentKiro, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
plan, err := provider.WatchPlan(context.Background())
require.NoError(t, err)
require.Len(t, plan.Roots, 1)
assert.Equal(t, root, plan.Roots[0].Path)
assert.False(t, plan.Roots[0].Recursive)
assert.Contains(t, plan.Roots[0].IncludeGlobs, "*.jsonl")
assert.Contains(t, plan.Roots[0].IncludeGlobs, kiroSQLiteDBName)
assert.Contains(t, plan.Roots[0].IncludeGlobs, kiroSQLiteDBName+"-*")
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 2)
assert.Equal(t, dbPath, discovered[0].DisplayPath)
assert.Equal(t, legacyPath, discovered[1].DisplayPath)
foundSQLite, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
FullSessionID: "host~kiro:sqlite-session",
})
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, KiroSQLiteVirtualPath(dbPath, "sqlite-session"), foundSQLite.DisplayPath)
assert.Equal(t, foundSQLite.DisplayPath, foundSQLite.FingerprintKey)
foundLegacy, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
RawSessionID: "legacy-session",
})
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, legacyPath, foundLegacy.DisplayPath)
changed, err := provider.SourcesForChangedPath(
context.Background(),
ChangedPathRequest{Path: dbPath + "-wal", EventKind: "write", WatchRoot: root},
)
require.NoError(t, err)
require.Len(t, changed, 1)
assert.Equal(t, dbPath, changed[0].DisplayPath)
}
func TestKiroProviderParsePhysicalVirtualAndLegacySources(t *testing.T) {
root := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "sqlite-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
legacyPath := filepath.Join(root, "legacy-session.jsonl")
writeSourceFile(t, legacyPath, kiroProviderJSONLFixture("Legacy question"))
provider, ok := NewProvider(AgentKiro, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
sources, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, sources, 2)
allOutcome, err := provider.Parse(context.Background(), ParseRequest{Source: sources[0]})
require.NoError(t, err)
require.True(t, allOutcome.ResultSetComplete)
require.True(t, allOutcome.ForceReplace)
require.Len(t, allOutcome.Results, 1)
assert.Equal(t, "kiro:sqlite-session", allOutcome.Results[0].Result.Session.ID)
virtualSource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
RawSessionID: "sqlite-session",
})
require.NoError(t, err)
require.True(t, ok)
oneOutcome, err := provider.Parse(context.Background(), ParseRequest{Source: virtualSource})
require.NoError(t, err)
require.True(t, oneOutcome.ResultSetComplete)
require.True(t, oneOutcome.ForceReplace)
require.Len(t, oneOutcome.Results, 1)
assert.Equal(t, "devbox", oneOutcome.Results[0].Result.Session.Machine)
legacySource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: legacyPath,
})
require.NoError(t, err)
require.True(t, ok)
legacyOutcome, err := provider.Parse(context.Background(), ParseRequest{
Source: legacySource,
Fingerprint: SourceFingerprint{Hash: "legacy-hash"},
})
require.NoError(t, err)
require.True(t, legacyOutcome.ResultSetComplete)
require.False(t, legacyOutcome.ForceReplace)
require.Len(t, legacyOutcome.Results, 1)
assert.Equal(t, "kiro:legacy-session", legacyOutcome.Results[0].Result.Session.ID)
assert.Equal(t, "legacy-hash", legacyOutcome.Results[0].Result.Session.File.Hash)
// Close the setup handle before deleting; Windows will not unlink a file
// this process still holds open.
require.NoError(t, db.Close())
require.NoError(t, os.Remove(dbPath))
missingOutcome, err := provider.Parse(context.Background(), ParseRequest{Source: sources[0]})
require.NoError(t, err)
assert.True(t, missingOutcome.ResultSetComplete)
// The backing DB file was deleted; preserve the stored sessions by not
// force-replacing, which would delete them from the archive.
assert.False(t, missingOutcome.ForceReplace)
assert.Equal(t, SkipNoSession, missingOutcome.SkipReason)
}
func TestKiroProviderSkipsShadowedLegacySource(t *testing.T) {
root := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/shadowed", "shadowed-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
shadowedPath := filepath.Join(root, "shadowed-session.jsonl")
writeSourceFile(t, shadowedPath, kiroProviderJSONLFixture("Shadowed question"))
provider, ok := NewProvider(AgentKiro, ProviderConfig{Roots: []string{root}})
require.True(t, ok)
source, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: shadowedPath,
})
require.NoError(t, err)
require.True(t, ok)
outcome, err := provider.Parse(context.Background(), ParseRequest{Source: source})
require.NoError(t, err)
assert.True(t, outcome.ResultSetComplete)
assert.Equal(t, SkipNoSession, outcome.SkipReason)
assert.Empty(t, outcome.Results)
source, ok, err = provider.FindSource(context.Background(), FindSourceRequest{
FullSessionID: "host~kiro:shadowed-session",
StoredFilePath: shadowedPath,
})
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, KiroSQLiteVirtualPath(dbPath, "shadowed-session"), source.DisplayPath)
}
func TestKiroProviderShadowsLegacyAcrossAllRoots(t *testing.T) {
sqliteRoot := t.TempDir()
legacyRoot := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, sqliteRoot)
seedKiroSQLiteSession(
t, db, "/home/user/code/current", "shared-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
legacyPath := filepath.Join(legacyRoot, "legacy-storage.jsonl")
writeSourceFile(t, legacyPath, kiroProviderJSONLFixture("Legacy question"))
writeSourceFile(t, filepath.Join(legacyRoot, "legacy-storage.json"),
kiroProviderMetaFixture("shared-session", "/home/user/code/legacy"))
provider, ok := NewProvider(AgentKiro, ProviderConfig{
Roots: []string{sqliteRoot, legacyRoot},
})
require.True(t, ok)
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 1)
assert.Equal(t, dbPath, discovered[0].DisplayPath)
legacySource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: legacyPath,
})
require.NoError(t, err)
require.True(t, ok)
outcome, err := provider.Parse(context.Background(), ParseRequest{
Source: legacySource,
})
require.NoError(t, err)
assert.True(t, outcome.ResultSetComplete)
assert.Equal(t, SkipNoSession, outcome.SkipReason)
assert.Empty(t, outcome.Results)
}
func TestKiroProviderFingerprintsSQLiteAndLegacySources(t *testing.T) {
root := t.TempDir()
payload := readKiroFixture(t, "standard_payload.json")
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "sqlite-session",
payload,
1779012000000, 1779012030000,
)
legacyPath := filepath.Join(root, "legacy-session.jsonl")
writeSourceFile(t, legacyPath, kiroProviderJSONLFixture("Legacy question"))
provider, ok := NewProvider(AgentKiro, ProviderConfig{Roots: []string{root}})
require.True(t, ok)
virtualSource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
RawSessionID: "sqlite-session",
})
require.NoError(t, err)
require.True(t, ok)
virtualFingerprint, err := provider.Fingerprint(context.Background(), virtualSource)
require.NoError(t, err)
assert.Equal(t, KiroSQLiteVirtualPath(dbPath, "sqlite-session"), virtualFingerprint.Key)
assert.Equal(t, int64(len(payload)), virtualFingerprint.Size)
assert.Equal(t, int64(1779012030000)*1_000_000, virtualFingerprint.MTimeNS)
sources, err := provider.Discover(context.Background())
require.NoError(t, err)
require.NotEmpty(t, sources)
sqliteSource := sources[0]
require.Equal(t, dbPath, sqliteSource.DisplayPath)
beforePhysical, err := provider.Fingerprint(context.Background(), sqliteSource)
require.NoError(t, err)
walPath := dbPath + "-wal"
writeSourceFile(t, walPath, "wal")
walTime := time.Unix(0, beforePhysical.MTimeNS+int64(time.Second))
require.NoError(t, os.Chtimes(walPath, walTime, walTime))
afterPhysical, err := provider.Fingerprint(context.Background(), sqliteSource)
require.NoError(t, err)
assert.Greater(t, afterPhysical.MTimeNS, beforePhysical.MTimeNS)
legacySource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: legacyPath,
})
require.NoError(t, err)
require.True(t, ok)
legacyFingerprint, err := provider.Fingerprint(context.Background(), legacySource)
require.NoError(t, err)
assert.Equal(t, legacyPath, legacyFingerprint.Key)
assert.NotEmpty(t, legacyFingerprint.Hash)
}
func TestKiroProviderMissingSQLiteSourcesCanReachParse(t *testing.T) {
root := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "sqlite-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
provider, ok := NewProvider(AgentKiro, ProviderConfig{Roots: []string{root}})
require.True(t, ok)
sources, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, sources, 1)
physicalSource := sources[0]
virtualSource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
RawSessionID: "sqlite-session",
})
require.NoError(t, err)
require.True(t, ok)
_, err = db.Exec(`DELETE FROM conversations_v2 WHERE conversation_id = ?`, "sqlite-session")
require.NoError(t, err)
_, ok, err = provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: virtualSource.DisplayPath,
RequireFreshSource: true,
})
require.NoError(t, err)
assert.False(t, ok, "fresh lookup must reject a deleted SQLite row")
staleVirtualSource, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: virtualSource.DisplayPath,
})
require.NoError(t, err)
require.True(t, ok, "non-fresh lookup keeps virtual tombstone identity")
assert.Equal(t, virtualSource.DisplayPath, staleVirtualSource.DisplayPath)
virtualFingerprint, err := provider.Fingerprint(context.Background(), virtualSource)
require.NoError(t, err)
assert.Equal(t, virtualSource.FingerprintKey, virtualFingerprint.Key)
virtualOutcome, err := provider.Parse(context.Background(), ParseRequest{
Source: virtualSource,
Fingerprint: virtualFingerprint,
})
require.NoError(t, err)
assert.True(t, virtualOutcome.ResultSetComplete)
assert.True(t, virtualOutcome.ForceReplace)
assert.Equal(t, SkipNoSession, virtualOutcome.SkipReason)
require.NoError(t, db.Close())
require.NoError(t, os.Remove(dbPath))
_, ok, err = provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: physicalSource.DisplayPath,
RequireFreshSource: true,
})
require.NoError(t, err)
assert.False(t, ok, "fresh lookup must reject a deleted SQLite DB")
physicalFingerprint, err := provider.Fingerprint(context.Background(), physicalSource)
require.NoError(t, err)
assert.Equal(t, physicalSource.FingerprintKey, physicalFingerprint.Key)
physicalOutcome, err := provider.Parse(context.Background(), ParseRequest{
Source: physicalSource,
Fingerprint: physicalFingerprint,
})
require.NoError(t, err)
assert.True(t, physicalOutcome.ResultSetComplete)
// The whole DB file was removed: preserve the stored sessions by not
// force-replacing. (The virtual case above keeps ForceReplace because the
// DB file is still present and only the row was deleted.)
assert.False(t, physicalOutcome.ForceReplace)
assert.Equal(t, SkipNoSession, physicalOutcome.SkipReason)
}
// TestKiroProviderChangedPathTombstonesDeletedRow verifies the changed-path
// classifier emits a per-session tombstone for a stored Kiro SQLite member
// whose row was deleted from a still-present database, so the engine can
// force-replace it out of the archive. The surviving member is left to the
// whole-DB fan-out, and a vanished database emits no tombstone (the stored
// sessions are preserved per the persistent-archive rule).
func TestKiroProviderChangedPathTombstonesDeletedRow(t *testing.T) {
root := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "surviving",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "deleted",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012040000,
)
provider, ok := NewProvider(AgentKiro, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
survivingPath := KiroSQLiteVirtualPath(dbPath, "surviving")
deletedPath := KiroSQLiteVirtualPath(dbPath, "deleted")
// Delete one row while the database file stays present.
_, err := db.Exec(`DELETE FROM conversations_v2 WHERE conversation_id = ?`, "deleted")
require.NoError(t, err)
changed, err := provider.SourcesForChangedPath(
context.Background(),
ChangedPathRequest{
Path: dbPath,
EventKind: "write",
WatchRoot: root,
StoredSourcePaths: []string{survivingPath, deletedPath},
},
)
require.NoError(t, err)
gotPaths := make([]string, len(changed))
for i, src := range changed {
gotPaths[i] = src.DisplayPath
}
assert.ElementsMatch(t, []string{dbPath, deletedPath}, gotPaths,
"whole-DB source plus a tombstone for the deleted row only")
var tombstone SourceRef
for _, src := range changed {
if src.DisplayPath == deletedPath {
tombstone = src
}
}
require.NotEmpty(t, tombstone.DisplayPath, "deleted-row tombstone source")
fingerprint, err := provider.Fingerprint(context.Background(), tombstone)
require.NoError(t, err)
outcome, err := provider.Parse(context.Background(), ParseRequest{
Source: tombstone,
Fingerprint: fingerprint,
})
require.NoError(t, err)
assert.True(t, outcome.ResultSetComplete)
assert.True(t, outcome.ForceReplace,
"a row deleted from a present DB is force-replaced out of the archive")
assert.Equal(t, SkipNoSession, outcome.SkipReason)
assert.Empty(t, outcome.Results)
// When the whole database file is gone, no tombstone is emitted so the
// stored sessions are preserved.
require.NoError(t, db.Close())
require.NoError(t, os.Remove(dbPath))
gone, err := provider.SourcesForChangedPath(
context.Background(),
ChangedPathRequest{
Path: dbPath,
EventKind: "remove",
WatchRoot: root,
StoredSourcePaths: []string{survivingPath, deletedPath},
},
)
require.NoError(t, err)
for _, src := range gone {
assert.NotEqual(t, deletedPath, src.DisplayPath,
"a vanished database must not tombstone stored sessions")
assert.NotEqual(t, survivingPath, src.DisplayPath)
}
}
func TestKiroProviderRejectsInvalidStoredSQLitePaths(t *testing.T) {
root := t.TempDir()
dbPath, db := newKiroProviderSQLiteDBAt(t, root)
seedKiroSQLiteSession(
t, db, "/home/user/code/kiro-app", "sqlite-session",
readKiroFixture(t, "standard_payload.json"),
1779012000000, 1779012030000,
)
provider, ok := NewProvider(AgentKiro, ProviderConfig{Roots: []string{root}})
require.True(t, ok)
for _, path := range []string{
dbPath + "#",
filepath.Join(root, "data-copy.sqlite3") + "#sqlite-session",
filepath.Join(root, "nested", kiroSQLiteDBName) + "#sqlite-session",
} {
_, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
StoredFilePath: path,
RequireFreshSource: true,
})
require.NoError(t, err)
assert.False(t, ok, "stored path %q", path)
}
}
func TestKiroIDEProviderSourceMethods(t *testing.T) {
root := t.TempDir()
oldWSHash := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
oldFileHash := "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
oldPath := filepath.Join(root, oldWSHash, oldFileHash+".chat")
writeSourceFile(t, oldPath, kiroIDEProviderOldFixture("Old IDE question"))
newPath := filepath.Join(root, "workspace-sessions", "encoded-workspace", "new-session.json")
writeSourceFile(t, newPath, kiroIDEProviderNewFixture("New IDE question"))
writeSourceFile(t, filepath.Join(root, "workspace-sessions", "encoded-workspace", "sessions.json"), "[]\n")
writeSourceFile(t, filepath.Join(root, "default", "ignored.chat"), kiroIDEProviderOldFixture("Ignored"))
provider, ok := NewProvider(AgentKiroIDE, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
plan, err := provider.WatchPlan(context.Background())
require.NoError(t, err)
require.Len(t, plan.Roots, 1)
assert.Equal(t, root, plan.Roots[0].Path)
assert.True(t, plan.Roots[0].Recursive)
assert.Contains(t, plan.Roots[0].IncludeGlobs, "*.chat")
assert.Contains(t, plan.Roots[0].IncludeGlobs, "*.json")
discovered, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, discovered, 2)
assert.Equal(t, oldPath, discovered[0].DisplayPath)
assert.Equal(t, newPath, discovered[1].DisplayPath)
foundOld, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
RawSessionID: oldWSHash + ":" + oldFileHash,
})
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, oldPath, foundOld.DisplayPath)
foundNew, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
FullSessionID: "host~kiro-ide:new-session",
})
require.NoError(t, err)
require.True(t, ok)
assert.Equal(t, newPath, foundNew.DisplayPath)
}
func TestKiroIDEProviderParsesOldAndNewSources(t *testing.T) {
root := t.TempDir()
oldWSHash := "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
oldFileHash := "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
oldPath := filepath.Join(root, oldWSHash, oldFileHash+".chat")
writeSourceFile(t, oldPath, kiroIDEProviderOldFixture("Old IDE question"))
newPath := filepath.Join(root, "workspace-sessions", "encoded-workspace", "new-session.json")
writeSourceFile(t, newPath, kiroIDEProviderNewFixture("New IDE question"))
provider, ok := NewProvider(AgentKiroIDE, ProviderConfig{
Roots: []string{root},
Machine: "devbox",
})
require.True(t, ok)
sources, err := provider.Discover(context.Background())
require.NoError(t, err)
require.Len(t, sources, 2)
oldOutcome, err := provider.Parse(context.Background(), ParseRequest{Source: sources[0]})
require.NoError(t, err)
require.True(t, oldOutcome.ResultSetComplete)
require.Len(t, oldOutcome.Results, 1)
assert.Equal(t, "kiro-ide:"+oldWSHash+":"+oldFileHash, oldOutcome.Results[0].Result.Session.ID)
assert.Equal(t, "devbox", oldOutcome.Results[0].Result.Session.Machine)
newOutcome, err := provider.Parse(context.Background(), ParseRequest{
Source: sources[1],
Fingerprint: SourceFingerprint{Hash: "new-hash"},
})
require.NoError(t, err)
require.True(t, newOutcome.ResultSetComplete)
require.Len(t, newOutcome.Results, 1)
assert.Equal(t, "kiro-ide:new-session", newOutcome.Results[0].Result.Session.ID)
assert.Equal(t, "new-hash", newOutcome.Results[0].Result.Session.File.Hash)
}
func TestKiroIDEProviderFingerprintsSessionContent(t *testing.T) {
root := t.TempDir()
path := filepath.Join(root, "workspace-sessions", "encoded-workspace", "new-session.json")
writeSourceFile(t, path, kiroIDEProviderNewFixture("New IDE question"))
provider, ok := NewProvider(AgentKiroIDE, ProviderConfig{Roots: []string{root}})
require.True(t, ok)
source, ok, err := provider.FindSource(context.Background(), FindSourceRequest{
RawSessionID: "new-session",
})
require.NoError(t, err)
require.True(t, ok)
before, err := provider.Fingerprint(context.Background(), source)
require.NoError(t, err)
writeSourceFile(t, path, kiroIDEProviderNewFixture("Changed IDE question"))
after, err := provider.Fingerprint(context.Background(), source)
require.NoError(t, err)
assert.NotEqual(t, before.Hash, after.Hash)
}
func newKiroProviderSQLiteDBAt(t *testing.T, root string) (string, *sql.DB) {
t.Helper()
dbPath := filepath.Join(root, kiroSQLiteDBName)
db, err := sql.Open("sqlite3", dbPath)
require.NoError(t, err, "open kiro provider sqlite db")
t.Cleanup(func() { _ = db.Close() })
_, err = db.Exec(kiroSQLiteSchema)
require.NoError(t, err, "create kiro sqlite schema")
return dbPath, db
}
func kiroProviderJSONLFixture(question string) string {
return `{"kind":"Prompt","data":{"content":[{"kind":"text","data":"` + question + `"}]}}` + "\n" +
`{"kind":"AssistantMessage","data":{"content":[{"kind":"text","data":"Kiro answer"}]}}` + "\n"
}
func kiroProviderMetaFixture(sessionID, cwd string) string {
return `{"session_id":"` + sessionID + `","cwd":"` + cwd + `","title":"` + sessionID + `","created_at":"2026-06-01T10:00:00Z","updated_at":"2026-06-01T10:01:00Z"}` + "\n"
}
func kiroIDEProviderOldFixture(question string) string {
return `{"executionId":"exec-old","actionId":"act-old","chat":[{"role":"human","content":"` + question + `"},{"role":"bot","content":"Old IDE answer"}],"metadata":{"modelId":"claude-sonnet-4-6","startTime":1779012000000,"endTime":1779012030000}}` + "\n"
}
func kiroIDEProviderNewFixture(question string) string {
return `{"sessionId":"new-session","title":"New title","workspaceDirectory":"/home/user/dev/new-app","history":[{"message":{"role":"user","content":"` + question + `","id":"m1"}},{"message":{"role":"assistant","content":"New IDE answer","id":"m2"}}]}` + "\n"
}