Something went wrong. Try again.
sloproxy
Something went wrong. Try again.
7.1 kB · 231 lines
Go
at commit e8e39526
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232//go:build windows
package pluginhost
import ( "context" "crypto/sha256" "encoding/hex" "fmt" "os" "path/filepath" "strings" "syscall" "testing" "unsafe"
"golang.org/x/sys/windows")
var testReentrantHostCallback uintptr
func TestDynamicLibraryClientCallSurvivesReentrantCallbackStackGrowth(t *testing.T) { testReentrantHostCallback = syscall.NewCallback(testGrowHostCallbackStack) client := newGuardedPluginClient(&dynamicLibraryClient{api: windowsPluginAPI{ call: syscall.NewCallback(testReentrantPluginCall), freeBuffer: syscall.NewCallback(testReentrantPluginFree), }}) t.Cleanup(client.Shutdown)
got, errCall := client.Call(context.Background(), "model.route", []byte(`{}`)) if errCall != nil { t.Fatalf("Call() error = %v", errCall) } want := `{"ok":true,"result":{"Handled":true}}` if string(got) != want { t.Fatalf("Call() response = %q, want %q", got, want) }}
func testReentrantPluginCall(_, _, _, responsePtr uintptr) uintptr { if testReentrantHostCallback == 0 || responsePtr == 0 { return 1 } _, _, _ = syscall.SyscallN(testReentrantHostCallback)
raw := []byte(`{"ok":true,"result":{"Handled":true}}`) mem, errAlloc := windows.LocalAlloc(windows.LMEM_FIXED, uint32(len(raw))) if errAlloc != nil || mem == 0 { return 1 } copy(unsafe.Slice((*byte)(unsafe.Pointer(mem)), len(raw)), raw) response := (*windowsBuffer)(unsafe.Pointer(responsePtr)) response.ptr = mem response.len = uintptr(len(raw)) return 0}
func testReentrantPluginFree(ptr, _ uintptr) uintptr { if ptr != 0 { _, _ = windows.LocalFree(windows.Handle(ptr)) } return 0}
func testGrowHostCallbackStack() uintptr { return uintptr(testGrowStack(64))}
//go:noinlinefunc testGrowStack(depth int) int { var padding [1024]byte for index := range padding { padding[index] = byte(index + depth) } if depth == 0 { return int(padding[0]) } return testGrowStack(depth-1) + int(padding[depth%len(padding)])}
func TestShadowPluginDirIsProcessScoped(t *testing.T) { dir, errDir := shadowPluginDir() if errDir != nil { t.Fatalf("shadowPluginDir() error = %v", errDir) } want := filepath.Join(os.TempDir(), "cliproxy-pluginhost", fmt.Sprintf("pid-%d", os.Getpid())) if dir != want { t.Fatalf("shadowPluginDir() = %q, want %q", dir, want) }}
func TestShadowCopyPluginReusesContentAddressedShadow(t *testing.T) { dir := t.TempDir() source := filepath.Join(t.TempDir(), "alpha.dll") content := []byte("plugin-v1") if errWrite := os.WriteFile(source, content, 0o644); errWrite != nil { t.Fatalf("WriteFile() error = %v", errWrite) } file := pluginFile{ID: "alpha", Path: source}
first, errFirst := shadowCopyPluginToDir(file, dir) if errFirst != nil { t.Fatalf("shadowCopyPluginToDir() first error = %v", errFirst) } second, errSecond := shadowCopyPluginToDir(file, dir) if errSecond != nil { t.Fatalf("shadowCopyPluginToDir() second error = %v", errSecond) }
if second != first { t.Fatalf("second shadow path = %q, want reused path %q", second, first) } gotContent, errRead := os.ReadFile(first) if errRead != nil { t.Fatalf("ReadFile(%s) error = %v", first, errRead) } if string(gotContent) != string(content) { t.Fatalf("shadow content = %q, want %q", gotContent, content) } digest := sha256.Sum256(content) wantDigest := hex.EncodeToString(digest[:])[:shadowPluginDigestLength] name := filepath.Base(first) if !strings.HasPrefix(name, shadowPluginPrefix+"alpha-") || !strings.Contains(name, wantDigest) { t.Fatalf("shadow file name = %q, want alpha content digest %s", name, wantDigest) } if count := countShadowPluginFiles(t, dir); count != 1 { t.Fatalf("shadow file count = %d, want 1", count) }}
func TestShadowCopyPluginCreatesNewPathForChangedContent(t *testing.T) { dir := t.TempDir() source := filepath.Join(t.TempDir(), "alpha.dll") file := pluginFile{ID: "alpha", Path: source} if errWrite := os.WriteFile(source, []byte("plugin-v1"), 0o644); errWrite != nil { t.Fatalf("WriteFile() v1 error = %v", errWrite) } first, errFirst := shadowCopyPluginToDir(file, dir) if errFirst != nil { t.Fatalf("shadowCopyPluginToDir() v1 error = %v", errFirst) }
if errWrite := os.WriteFile(source, []byte("plugin-v2"), 0o644); errWrite != nil { t.Fatalf("WriteFile() v2 error = %v", errWrite) } second, errSecond := shadowCopyPluginToDir(file, dir) if errSecond != nil { t.Fatalf("shadowCopyPluginToDir() v2 error = %v", errSecond) }
if second == first { t.Fatalf("second shadow path reused %q after content changed", second) } if count := countShadowPluginFiles(t, dir); count != 2 { t.Fatalf("shadow file count = %d, want 2 versions", count) }}
func TestShadowCopyPluginReplacesCorruptSameSizeShadow(t *testing.T) { dir := t.TempDir() source := filepath.Join(t.TempDir(), "alpha.dll") content := []byte("plugin-v1") if errWrite := os.WriteFile(source, content, 0o644); errWrite != nil { t.Fatalf("WriteFile() source error = %v", errWrite) } digest := sha256.Sum256(content) target := shadowPluginPath(dir, "alpha", hex.EncodeToString(digest[:]), ".dll") if errWrite := os.WriteFile(target, []byte("corrupt!!"), 0o644); errWrite != nil { t.Fatalf("WriteFile() corrupt shadow error = %v", errWrite) }
gotPath, errCopy := shadowCopyPluginToDir(pluginFile{ID: "alpha", Path: source}, dir) if errCopy != nil { t.Fatalf("shadowCopyPluginToDir() error = %v", errCopy) }
if gotPath != target { t.Fatalf("shadow path = %q, want %q", gotPath, target) } gotContent, errRead := os.ReadFile(target) if errRead != nil { t.Fatalf("ReadFile(%s) error = %v", target, errRead) } if string(gotContent) != string(content) { t.Fatalf("shadow content = %q, want %q", gotContent, content) } if count := countShadowPluginFiles(t, dir); count != 1 { t.Fatalf("shadow file count = %d, want 1", count) }}
func TestRemoveStaleShadowPluginsOnlyRemovesShadowFiles(t *testing.T) { dir := t.TempDir() stale := filepath.Join(dir, shadowPluginPrefix+"alpha-deadbeef.dll") temp := filepath.Join(dir, shadowPluginTempPrefix+"alpha-temp.dll") keep := filepath.Join(dir, "keep.dll") for _, path := range []string{stale, temp, keep} { if errWrite := os.WriteFile(path, []byte("x"), 0o644); errWrite != nil { t.Fatalf("WriteFile(%s) error = %v", path, errWrite) } }
removeStaleShadowPlugins(dir)
for _, path := range []string{stale, temp} { if _, errStat := os.Stat(path); !os.IsNotExist(errStat) { t.Fatalf("Stat(%s) error = %v, want not exist", path, errStat) } } if _, errStat := os.Stat(keep); errStat != nil { t.Fatalf("Stat(%s) error = %v, want kept", keep, errStat) }}
func countShadowPluginFiles(t *testing.T, dir string) int { t.Helper() entries, errRead := os.ReadDir(dir) if errRead != nil { t.Fatalf("ReadDir(%s) error = %v", dir, errRead) } count := 0 for _, entry := range entries { if strings.HasPrefix(entry.Name(), shadowPluginPrefix) { count++ } if strings.HasPrefix(entry.Name(), shadowPluginTempPrefix) { t.Fatalf("temporary shadow file was not cleaned up: %s", entry.Name()) } } return count}