Repository navigation
Expand file tree
/
Copy pathapp_binary_cache_test.go
More file actions
101 lines (87 loc) · 2.92 KB
/
Copy pathapp_binary_cache_test.go
File metadata and controls
101 lines (87 loc) · 2.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main
import (
"sync"
"testing"
"time"
)
// The path, env and timestamp were three App fields cleared by hand at every
// call site that changed the binary. invalidate has to clear all three, or a
// newly installed binary keeps running with the old provider's environment.
func TestBinaryCacheInvalidateClearsEverything(t *testing.T) {
var c binaryCache
c.seed("/usr/local/bin/officecli", []string{"OFFICECLI_LLM_PROVIDER=anthropic"}, time.Now())
c.invalidate()
path, env, at := c.load()
if path != "" || len(env) != 0 || !at.IsZero() {
t.Fatalf("after invalidate: path=%q env=%#v at=%v, want all empty", path, env, at)
}
}
// A resolution costs a filesystem stat and runs on every RPC, so it must happen
// once per settings change and not once per caller.
func TestBinaryCacheResolvesOnceUntilInvalidated(t *testing.T) {
var c binaryCache
var calls int
resolve := func() (string, []string) {
calls++
return "/usr/local/bin/officecli", []string{"OFFICE_CLI_RUNTIME_MODE=hosted"}
}
for i := 0; i < 5; i++ {
if path, _ := c.ensure(resolve); path != "/usr/local/bin/officecli" {
t.Fatalf("ensure returned %q", path)
}
}
if calls != 1 {
t.Fatalf("resolved %d times, want 1", calls)
}
c.invalidate()
c.ensure(resolve)
if calls != 2 {
t.Fatalf("resolved %d times after invalidate, want 2", calls)
}
}
// Concurrent callers should stat the filesystem once between them, not once
// each -- ensureBridge and runCommandOptions can both arrive on a cold cache.
func TestBinaryCacheResolvesOnceUnderConcurrentCallers(t *testing.T) {
var c binaryCache
var mu sync.Mutex
calls := 0
resolve := func() (string, []string) {
mu.Lock()
calls++
mu.Unlock()
return "/usr/local/bin/officecli", nil
}
var wg sync.WaitGroup
for i := 0; i < 20; i++ {
wg.Add(1)
go func() { defer wg.Done(); c.ensure(resolve) }()
}
wg.Wait()
if calls != 1 {
t.Fatalf("resolved %d times concurrently, want 1", calls)
}
}
// EnvApplied in the runtime snapshot distinguishes "resolved with no env" from
// "never resolved", which is what the timestamp is for.
func TestBinaryCacheZeroTimestampMeansNeverResolved(t *testing.T) {
var c binaryCache
if _, _, at := c.load(); !at.IsZero() {
t.Fatal("a fresh cache should report a zero resolved-at")
}
c.store("/usr/local/bin/officecli", nil)
if _, _, at := c.load(); at.IsZero() {
t.Fatal("storing a resolution with an empty env should still stamp the time")
}
}
// Handing out the stored slice let a caller mutate another caller's env.
func TestBinaryCacheDoesNotShareItsEnvSlice(t *testing.T) {
var c binaryCache
original := []string{"OFFICECLI_LLM_MODEL=claude-sonnet-4-6"}
c.store("/usr/local/bin/officecli", original)
_, env, _ := c.load()
env[0] = "OFFICECLI_LLM_API_KEY=leaked"
original[0] = "OFFICECLI_LLM_MODEL=tampered"
if _, env, _ := c.load(); env[0] != "OFFICECLI_LLM_MODEL=claude-sonnet-4-6" {
t.Fatalf("cached env was mutated through a shared slice: %q", env[0])
}
}