mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
A Build handed Options.Home still put three storage roots under the process's home: isolated and best-of-n worktrees, browser profiles, and the missing-reasoning recovery state. Each now resolves through the build's config.Roots, which is the process binding whenever no home is stated, as in every production frontend. The new process-input repolint rule ratchets direct reads of the process environment, working directory and user directories below internal/frontend, so later slices can only move that count down. 40 boot tests now state their home and workspace instead of mutating the process, and run in parallel. The isolation effect test runs two sessions with different homes side by side and fails without the binding fix. The provider registry now holds a read-write lock: parallel Builds register and resolve kinds concurrently, which -race reported as a race and could crash with a concurrent map write. Refs #12531 Refs #12521
108 lines
3.1 KiB
Go
108 lines
3.1 KiB
Go
package boot
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"reasonix/internal/base/testenv"
|
|
"reasonix/internal/contract/event"
|
|
"reasonix/internal/contract/provider"
|
|
"reasonix/internal/session/control"
|
|
)
|
|
|
|
type pathLeaseProvider struct {
|
|
path string
|
|
written chan struct{}
|
|
resume chan struct{}
|
|
once sync.Once
|
|
}
|
|
|
|
func (*pathLeaseProvider) Name() string { return "path-lease-effect" }
|
|
|
|
func (p *pathLeaseProvider) Stream(ctx context.Context, req provider.Request) (<-chan provider.Chunk, error) {
|
|
ch := make(chan provider.Chunk, 2)
|
|
if hasToolResult(req) {
|
|
p.once.Do(func() { close(p.written) })
|
|
select {
|
|
case <-p.resume:
|
|
case <-ctx.Done():
|
|
return nil, ctx.Err()
|
|
}
|
|
ch <- provider.Chunk{Type: provider.ChunkText, Text: "done"}
|
|
} else {
|
|
args, _ := json.Marshal(map[string]string{"path": p.path, "content": "fixture\n"})
|
|
ch <- provider.Chunk{Type: provider.ChunkToolCall, ToolCall: &provider.ToolCall{ID: "write", Name: "write_file", Arguments: string(args)}}
|
|
}
|
|
ch <- provider.Chunk{Type: provider.ChunkDone}
|
|
close(ch)
|
|
return ch, nil
|
|
}
|
|
|
|
func TestEffectTwoControllersWriteDisjointPathsInOneWorkspace(t *testing.T) {
|
|
t.Parallel()
|
|
home := statedBootHome(t)
|
|
root := testenv.TempDir(t)
|
|
if err := os.Mkdir(filepath.Join(root, ".git"), 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
writeFile(t, root, "reasonix.toml", `
|
|
default_model = "test-model"
|
|
[codegraph]
|
|
enabled = false
|
|
[[providers]]
|
|
name = "test-model"
|
|
kind = "path-lease-effect"
|
|
model = "x"
|
|
`)
|
|
approveWorkspaceAt(t, home, root)
|
|
first := &pathLeaseProvider{path: "first.txt", written: make(chan struct{}), resume: make(chan struct{})}
|
|
second := &pathLeaseProvider{path: "second.txt", written: make(chan struct{}), resume: make(chan struct{})}
|
|
current := first
|
|
provider.Register("path-lease-effect", func(provider.Config) (provider.Provider, error) { return current, nil })
|
|
build := func() *control.Controller {
|
|
c, err := Build(context.Background(), Options{Home: home, WorkspaceRoot: root, Sink: event.Discard})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c.SetToolApprovalMode(control.ToolApprovalYolo)
|
|
t.Cleanup(func() { c.Close() })
|
|
return c
|
|
}
|
|
a := build()
|
|
current = second
|
|
b := build()
|
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
|
defer cancel()
|
|
doneA, doneB := make(chan struct{}), make(chan struct{})
|
|
defer func() { cancel(); close(first.resume); close(second.resume); <-doneA; <-doneB }()
|
|
go func() { defer close(doneA); _ = a.Run(ctx, "create first.txt") }()
|
|
go func() {
|
|
defer close(doneB)
|
|
select {
|
|
case <-first.written:
|
|
case <-ctx.Done():
|
|
return
|
|
}
|
|
_ = b.Run(ctx, "create second.txt")
|
|
}()
|
|
select {
|
|
case <-second.written:
|
|
case <-ctx.Done():
|
|
t.Fatal("second controller could not write while first turn remained active")
|
|
}
|
|
if !a.WorkspaceLeaseState().Acquired || !b.WorkspaceLeaseState().Acquired {
|
|
t.Fatal("both controllers must retain their independent write leases")
|
|
}
|
|
for _, name := range []string{"first.txt", "second.txt"} {
|
|
data, err := os.ReadFile(filepath.Join(root, name))
|
|
if err != nil || string(data) != "fixture\n" {
|
|
t.Fatalf("%s: %q, %v", name, data, err)
|
|
}
|
|
}
|
|
}
|