Repository navigation
Expand file tree
/
Copy pathffihost_test.go
More file actions
135 lines (115 loc) · 3.39 KB
/
Copy pathffihost_test.go
File metadata and controls
135 lines (115 loc) · 3.39 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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//go:build copilot_inprocess && (darwin || linux || windows)
package ffihost
import (
"encoding/json"
"sync/atomic"
"testing"
"time"
"unsafe"
)
func TestDisposeUnregistersOutboundTarget(t *testing.T) {
token := uintptr(nextOutboundToken.Add(1))
host := &Host{
recv: newReceiveBuffer(),
callbackToken: token,
}
outboundTargets.Store(token, host)
host.Dispose()
if _, ok := outboundTargets.Load(token); ok {
t.Fatal("Expected disposed host to be removed from outbound callback registry")
}
}
func TestBuildArgvWithoutEntrypointContainsOnlyManagedOptions(t *testing.T) {
host := &Host{
args: []string{"--log-level", "debug", "--remote"},
}
var argv []string
if err := json.Unmarshal(host.buildArgv(), &argv); err != nil {
t.Fatal(err)
}
expected := []string{"--log-level", "debug", "--remote"}
if len(argv) != len(expected) {
t.Fatalf("Expected %d arguments, got %d: %v", len(expected), len(argv), argv)
}
for i := range expected {
if argv[i] != expected[i] {
t.Fatalf("Expected argument %d to be %q, got %q", i, expected[i], argv[i])
}
}
}
func TestBuildArgvPreservesExplicitEntrypoint(t *testing.T) {
host := &Host{cliEntrypoint: "copilot", args: []string{"--remote"}}
var argv []string
if err := json.Unmarshal(host.buildArgv(), &argv); err != nil {
t.Fatal(err)
}
expected := []string{"copilot", "--embedded-host", "--no-auto-update", "--remote"}
if len(argv) != len(expected) {
t.Fatalf("Expected %d arguments, got %d: %v", len(expected), len(argv), argv)
}
for i := range expected {
if argv[i] != expected[i] {
t.Fatalf("Expected argument %d to be %q, got %q", i, expected[i], argv[i])
}
}
}
func TestBuildArgvUsesNodeForExplicitJavaScriptEntrypoint(t *testing.T) {
host := &Host{cliEntrypoint: "copilot.js"}
var argv []string
if err := json.Unmarshal(host.buildArgv(), &argv); err != nil {
t.Fatal(err)
}
expected := []string{"node", "copilot.js", "--embedded-host", "--no-auto-update"}
if len(argv) != len(expected) {
t.Fatalf("Expected %d arguments, got %d: %v", len(expected), len(argv), argv)
}
for i := range expected {
if argv[i] != expected[i] {
t.Fatalf("Expected argument %d to be %q, got %q", i, expected[i], argv[i])
}
}
}
func TestDisposeWaitsForStartBeforeShuttingDown(t *testing.T) {
started := make(chan struct{})
releaseStart := make(chan struct{})
startDone := make(chan error, 1)
disposeDone := make(chan struct{})
var shutdownID atomic.Uint32
host := &Host{
lib: &ffiLibrary{
hostStart: func(_ unsafe.Pointer, _ uintptr, _ unsafe.Pointer, _ uintptr) uint32 {
close(started)
<-releaseStart
return 41
},
hostShutdown: func(serverID uint32) bool {
shutdownID.Store(serverID)
return true
},
connectionOpen: func(_ uint32, _ uintptr, _ uintptr, _ unsafe.Pointer, _ uintptr, _ unsafe.Pointer, _ uintptr, _ unsafe.Pointer, _ uintptr) uint32 {
return 42
},
connectionClose: func(_ uint32) bool { return true },
},
recv: newReceiveBuffer(),
}
go func() { startDone <- host.Start() }()
<-started
go func() {
host.Dispose()
close(disposeDone)
}()
select {
case <-disposeDone:
t.Fatal("Dispose returned before native startup completed")
case <-time.After(20 * time.Millisecond):
}
close(releaseStart)
if err := <-startDone; err != nil {
t.Fatal(err)
}
<-disposeDone
if got := shutdownID.Load(); got != 41 {
t.Fatalf("Expected shutdown of server 41, got %d", got)
}
}