105 lines
3.0 KiB
Go
105 lines
3.0 KiB
Go
|
|
package core
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"runtime"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/metacubex/mihomo/constant"
|
||
|
|
)
|
||
|
|
|
||
|
|
func withSpillHome(t *testing.T, threshold int) string {
|
||
|
|
t.Helper()
|
||
|
|
previousHome := constant.Path.HomeDir()
|
||
|
|
previousThreshold := spillThreshold
|
||
|
|
home := t.TempDir()
|
||
|
|
constant.SetHomeDir(home)
|
||
|
|
spillThreshold = threshold
|
||
|
|
t.Cleanup(func() {
|
||
|
|
constant.SetHomeDir(previousHome)
|
||
|
|
spillThreshold = previousThreshold
|
||
|
|
})
|
||
|
|
return home
|
||
|
|
}
|
||
|
|
|
||
|
|
func getConfigCall(t *testing.T, id string) *MethodCall {
|
||
|
|
t.Helper()
|
||
|
|
path := filepath.Join(t.TempDir(), "profile.yaml")
|
||
|
|
if err := os.WriteFile(path, []byte("mode: rule\nrules:\n - MATCH,DIRECT\n"), 0o600); err != nil {
|
||
|
|
t.Fatalf("write profile: %v", err)
|
||
|
|
}
|
||
|
|
arguments, _ := json.Marshal(path)
|
||
|
|
return &MethodCall{ID: id, Method: getConfigMethod, Arguments: arguments}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestHandleMethodCallSpillsALargeResultToAFile(t *testing.T) {
|
||
|
|
home := withSpillHome(t, 64)
|
||
|
|
|
||
|
|
frame := handleMethodCall(getConfigCall(t, "7"))
|
||
|
|
|
||
|
|
var envelope MethodResponse
|
||
|
|
if err := json.Unmarshal(frame, &envelope); err != nil {
|
||
|
|
t.Fatalf("response is not valid JSON: %v", err)
|
||
|
|
}
|
||
|
|
if envelope.ID != "7" || envelope.Result != nil || envelope.Error != nil {
|
||
|
|
t.Fatalf("envelope = %+v, want only the id and the file", envelope)
|
||
|
|
}
|
||
|
|
if filepath.Dir(envelope.File) != filepath.Join(home, spilledResponseDirName) {
|
||
|
|
t.Fatalf("file = %s, want it under the home directory's spill directory", envelope.File)
|
||
|
|
}
|
||
|
|
data, err := os.ReadFile(envelope.File)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("read spilled response: %v", err)
|
||
|
|
}
|
||
|
|
var spilled struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
Result map[string]any `json:"result"`
|
||
|
|
}
|
||
|
|
if err := json.Unmarshal(data, &spilled); err != nil {
|
||
|
|
t.Fatalf("spilled response is not valid JSON: %v", err)
|
||
|
|
}
|
||
|
|
if spilled.ID != "7" || spilled.Result["mode"] != "rule" {
|
||
|
|
t.Errorf("spilled response = %+v, want the full answer to call 7", spilled)
|
||
|
|
}
|
||
|
|
if runtime.GOOS != "windows" {
|
||
|
|
info, _ := os.Stat(envelope.File)
|
||
|
|
if info.Mode().Perm() != 0o644 {
|
||
|
|
t.Errorf("mode = %v, want the host to be able to read it", info.Mode().Perm())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestHandleMethodCallAnswersInlineUnderTheThreshold(t *testing.T) {
|
||
|
|
home := withSpillHome(t, responseSpillThreshold)
|
||
|
|
|
||
|
|
frame := handleMethodCall(getConfigCall(t, "8"))
|
||
|
|
|
||
|
|
var envelope MethodResponse
|
||
|
|
if err := json.Unmarshal(frame, &envelope); err != nil {
|
||
|
|
t.Fatalf("response is not valid JSON: %v", err)
|
||
|
|
}
|
||
|
|
if envelope.File != "" || envelope.Result == nil {
|
||
|
|
t.Errorf("envelope = %+v, want the result inline", envelope)
|
||
|
|
}
|
||
|
|
if _, err := os.Stat(filepath.Join(home, spilledResponseDirName)); !os.IsNotExist(err) {
|
||
|
|
t.Errorf("stat spill directory = %v, want nothing written", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestClearSpilledResponsesKeepsTheDirectory(t *testing.T) {
|
||
|
|
home := withSpillHome(t, 64)
|
||
|
|
handleMethodCall(getConfigCall(t, "9"))
|
||
|
|
|
||
|
|
clearSpilledResponses()
|
||
|
|
|
||
|
|
entries, err := os.ReadDir(filepath.Join(home, spilledResponseDirName))
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("read spill directory: %v", err)
|
||
|
|
}
|
||
|
|
if len(entries) != 0 {
|
||
|
|
t.Errorf("entries = %v, want none left", entries)
|
||
|
|
}
|
||
|
|
}
|