gocmdDaemon/cmd_daemon_test.go

328 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package gocmdDaemon
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) {
pipePath := "/tmp/test.pipe"
daemon := &CmdDaemon{
PipePath: pipePath,
cmds: make(map[string]CmdHandler),
}
// 注册一个简单的命令处理程序
daemon.RegisterCmd("test", &SimpleCmdHandler{})
// 启动守护进程
go func() {
err := daemon.Listen()
if err != nil {
t.Errorf("Listen failed: %v", err)
}
}()
// 等待管道文件创建
waitForPipe(t, pipePath)
// 打开命名管道进行写入
pipe, err := os.OpenFile(pipePath, os.O_RDWR, 0)
if err != nil {
t.Fatalf("Failed to open pipe for writing: %v", err)
}
defer pipe.Close()
// 将文件转换为io.ReadWriter接口以便与现有的Read/Write函数兼容
pipeConn := &pipeConnection{pipe}
// 发送请求
req := CmdRequest{
Id: "1",
Cmd: "test",
Args: "arg1",
IsDebug: false,
}
err = Write(pipeConn, req)
if err != nil {
t.Errorf("Write failed: %v", err)
}
// 读取响应
resp, err := Read[CmdResponse](pipeConn)
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方法
pipePath := "/tmp/test_run.pipe"
daemon := &CmdDaemon{
PipePath: pipePath,
cmds: make(map[string]CmdHandler),
}
// 注册一个简单的命令处理程序
daemon.RegisterCmd("test", &SimpleCmdHandler{})
// 创建一个同步通道来等待守护进程开始监听
listening := make(chan struct{})
// 启动守护进程
go startTestDaemon(daemon, listening)
// 等待直到监听开始
// 使用一个错误channel来传递错误
errChan := make(chan error)
go func() {
// 等待管道文件创建
waitForPipe(t, pipePath)
// 设置命令行参数
os.Args = []string{"cmd", "--debug", "test", "arg1"}
ndaemon := &CmdDaemon{
PipePath: pipePath,
}
// 执行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) {
pipePath := "/tmp/test_empty.pipe"
daemon := &CmdDaemon{
PipePath: pipePath,
cmds: make(map[string]CmdHandler),
}
// 注册一个简单的命令处理程序
daemon.RegisterCmd("empty", &EmptyCmdHandler{})
// 创建一个同步通道来等待守护进程开始监听
listening := make(chan struct{})
// 启动守护进程
go startTestDaemon(daemon, listening)
// 使用一个错误channel来传递错误
errChan := make(chan error)
go func() {
// 等待管道文件创建
waitForPipe(t, pipePath)
// 设置命令行参数
os.Args = []string{"cmd", "empty"}
ndaemon := &CmdDaemon{
PipePath: pipePath,
}
// 执行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) {
pipePath := "/tmp/test_unknown.pipe"
daemon := &CmdDaemon{
PipePath: pipePath,
cmds: make(map[string]CmdHandler),
}
// 注册一个简单的命令处理程序
daemon.RegisterCmd("unknown", &UnknownCmdHandler{})
// 启动守护进程
go func() {
err := daemon.Listen()
if err != nil {
panic(fmt.Sprintf("Listen failed: %v", err))
}
}()
// 等待管道文件创建
waitForPipe(t, pipePath)
// 设置命令行参数
os.Args = []string{"cmd", "unknown"}
ndaemon := &CmdDaemon{
PipePath: pipePath,
}
// 执行Run方法
err := ndaemon.Run()
if err != nil {
t.Fatalf("Run failed: %v", err)
}
}
// waitForPipe 等待直到指定路径的命名管道文件被创建
func waitForPipe(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 pipe")
case <-ticker:
if _, err := os.Stat(path); err == nil {
return
}
}
}
}