package main import ( "encoding/json" "fmt" "net" "os" "testing" "time" ) func TestWrite(t *testing.T) { // 创建一个配对的连接 conn1, conn2 := net.Pipe() defer conn1.Close() defer conn2.Close() // 要写入的数据 data := map[string]string{"test": "data"} // 在一个goroutine中执行写操作 go func() { err := Write(conn1, data) if err != nil { t.Errorf("Write failed: %v", err) } }() // 读取数据并验证 var received map[string]string err := json.NewDecoder(conn2).Decode(&received) if err != nil { t.Fatalf("Read failed: %v", err) } for k, v := range data { if received[k] != v { t.Errorf("Received data does not match. Expected %v:%v, Got %v:%v", k, v, received[k], received[k]) } } } func TestRead(t *testing.T) { // 创建一个配对的连接 conn1, conn2 := net.Pipe() defer conn1.Close() defer conn2.Close() // 准备要读取的数据 data := map[string]string{"test": "data"} // 在一个goroutine中执行写操作 go func() { encoder := json.NewEncoder(conn1) err := encoder.Encode(data) if err != nil { t.Errorf("Write failed: %v", err) } }() // 读取数据并验证 received, err := Read[map[string]string](conn2) if err != nil { t.Fatalf("Read failed: %v", err) } for k, v := range data { if (*received)[k] != v { t.Errorf("Received data does not match. Expected %v:%v, Got %v:%v", k, v, (*received)[k], (*received)[k]) } } } func TestCmdDaemonListen(t *testing.T) { socketPath := "/tmp/test.sock" daemon := &CmdDaemon{ SocketPath: socketPath, cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 daemon.RegisterCmd("test", &SimpleCmdHandler{}) // 启动守护进程 go func() { err := daemon.Listen() if err != nil { t.Errorf("Listen failed: %v", err) } }() // 等待服务器启动 time.Sleep(1 * time.Second) // 模拟客户端连接 conn, err := net.Dial("unix", socketPath) if err != nil { t.Fatalf("Client connect failed: %v", err) } defer conn.Close() // 发送请求 req := CmdRequest{ Id: "1", Cmd: "test", Args: "arg1", IsDebug: false, } err = Write(conn, req) if err != nil { t.Errorf("Write failed: %v", err) } // 读取响应 resp, err := Read[CmdResponse](conn) if err != nil { t.Fatalf("Read failed: %v", err) } if resp.Data != "Handled test with args: arg1" || resp.Error != "" { t.Errorf("Unexpected response. Data: %v, Error: %v", resp.Data, resp.Error) } } func TestCmdDaemonRun(t *testing.T) { // 这里我们假设有一个正在运行的服务器来处理请求 // 因此我们需要首先启动一个简单的服务器来测试Run方法 socketPath := "/tmp/test_run.sock" daemon := &CmdDaemon{ SocketPath: socketPath, cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 daemon.RegisterCmd("test", &SimpleCmdHandler{}) // 创建一个同步通道来等待守护进程开始监听 listening := make(chan struct{}) // 启动守护进程 go startTestDaemon(daemon, listening) // 等待直到监听开始 // for循环中检查socket文件是否存在,如果存在退出循环,否则sleepeep 1秒 // 使用一个错误channel来传递错误 errChan := make(chan error) go func() { listened := false for { if listened { break } if _, err := os.Stat(socketPath); err == nil { listened = true } time.Sleep(1 * time.Second) } // 设置命令行参数 os.Args = []string{"cmd", "--debug", "test", "arg1"} ndaemon := &CmdDaemon{ SocketPath: socketPath, } // 执行Run方法 err := ndaemon.Run() if err != nil { errChan <- err } else { t.Log("Run completed successfully") close(errChan) } }() err := <-errChan if err != nil { t.Fatal(err) } } // startTestDaemon 启动守护进程并在后台运行 func startTestDaemon(daemon *CmdDaemon, ready chan struct{}) { err := daemon.Listen() if err != nil { panic(fmt.Sprintf("Listen failed: %v", err)) } } // SimpleCmdHandler 是一个简单的CmdHandler实现用于测试 type SimpleCmdHandler struct{} func (h *SimpleCmdHandler) Handle(conn *CmdConn, req *CmdRequest) error { err := conn.End(fmt.Sprintf("Handled %s with args: %s", req.Cmd, req.Args)) return err } func (h *SimpleCmdHandler) Description() string { return "Simple command handler for testing" } func (h *SimpleCmdHandler) Usage() string { return "Usage: test [args]" } // EmptyCmdHandler 是一个简单的CmdHandler实现用于测试空输入 type EmptyCmdHandler struct{} func (h *EmptyCmdHandler) Handle(conn *CmdConn, req *CmdRequest) error { // 返回一个空响应 err := conn.End("") return err } func (h *EmptyCmdHandler) Description() string { return "Simple command handler for testing empty input" } func (h *EmptyCmdHandler) Usage() string { return "Usage: empty" } // UnknownCmdHandler 是一个简单的CmdHandler实现用于测试未知命令 // 它会返回一个错误响应 type UnknownCmdHandler struct{} func (h *UnknownCmdHandler) Handle(conn *CmdConn, req *CmdRequest) error { // 返回一个错误响应 err := conn.WriteError(fmt.Errorf("unknown command"), false) return err } func (h *UnknownCmdHandler) Description() string { return "Simple command handler for testing unknown commands" } func (h *UnknownCmdHandler) Usage() string { return "Usage: unknown" } func TestEmptyCommand(t *testing.T) { socketPath := "/tmp/test_empty.sock" daemon := &CmdDaemon{ SocketPath: socketPath, cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 daemon.RegisterCmd("empty", &EmptyCmdHandler{}) // 创建一个同步通道来等待守护进程开始监听 listening := make(chan struct{}) // 启动守护进程 go startTestDaemon(daemon, listening) // 等待直到监听开始 // for循环中检查socket文件是否存在,如果存在退出循环,否则sleepeep 1秒 // 使用一个错误channel来传递错误 errChan := make(chan error) go func() { listened := false for { if listened { break } if _, err := os.Stat(socketPath); err == nil { listened = true } time.Sleep(1 * time.Second) } // 设置命令行参数 os.Args = []string{"cmd", "empty"} ndaemon := &CmdDaemon{ SocketPath: socketPath, } // 执行Run方法 err := ndaemon.Run() if err != nil { errChan <- err } else { t.Log("Run completed successfully") close(errChan) } }() err := <-errChan if err != nil { t.Fatal(err) } } func TestUnknownCommand(t *testing.T) { socketPath := "/tmp/test_unknown.sock" daemon := &CmdDaemon{ SocketPath: socketPath, cmds: make(map[string]CmdHandler), } // 注册一个简单的命令处理程序 daemon.RegisterCmd("unknown", &UnknownCmdHandler{}) // 启动守护进程 go func() { err := daemon.Listen() if err != nil { panic(fmt.Sprintf("Listen failed: %v", err)) } }() // 等待 socket 文件创建 waitForSocket(t, socketPath) // 设置命令行参数 os.Args = []string{"cmd", "unknown"} ndaemon := &CmdDaemon{ SocketPath: socketPath, } // 执行Run方法 err := ndaemon.Run() if err != nil { t.Fatalf("Run failed: %v", err) } } // waitForSocket 等待直到指定路径的 socket 文件被创建 func waitForSocket(t *testing.T, path string) { timeout := time.After(5 * time.Second) ticker := time.Tick(500 * time.Millisecond) for { select { case <-timeout: t.Fatal("Timed out waiting for socket") case <-ticker: if _, err := os.Stat(path); err == nil { return } } } }