package main import ( "bufio" "encoding/json" "fmt" "io" "net" "os" "testing" "time" ) func TestAutomaticLoginWaitsForSuccessAndPreservesBufferedData(t *testing.T) { for _, accepted := range []bool{true, false} { t.Run(fmt.Sprint(accepted), func(t *testing.T) { client, server := net.Pipe() defer client.Close() defer server.Close() done := make(chan error, 1) go func() { r := bufio.NewReader(server) fmt.Fprint(server, "DebTik login: ") user, err := r.ReadString('\n') if err != nil { done <- err return } fmt.Fprint(server, "Password: ") password, err := r.ReadString('\n') if err != nil { done <- err return } if user != "admin\n" || password != "test-password\n" { done <- fmt.Errorf("wrong credentials sent") return } if accepted { _, err = fmt.Fprint(server, "Welcome\n[admin@router] > buffered") } else { _, err = fmt.Fprint(server, "Login failed: invalid credentials\n") } done <- err }() r := bufio.NewReader(client) err := autoLogin(client, r, "admin", "test-password", io.Discard) if (err == nil) != accepted { t.Fatalf("accepted=%v err=%v", accepted, err) } if accepted { buffered := make([]byte, 8) if _, err := r.Read(buffered); err != nil || string(buffered) != "buffered" { t.Fatal("buffered data was lost") } } if err := <-done; err != nil { t.Fatal(err) } }) } } func TestOneShotReportsCommandFailure(t *testing.T) { for _, status := range []string{"0", "1", "missing"} { t.Run(status, func(t *testing.T) { client, server := net.Pipe() defer client.Close() go func() { defer server.Close() r := bufio.NewReader(server) fmt.Fprint(server, "login:") r.ReadString('\n') fmt.Fprint(server, "password:") r.ReadString('\n') fmt.Fprint(server, "[user@router] > ") r.ReadString('\n') if status != "missing" { fmt.Fprintf(server, "DEBTIK-EXEC-BEGIN\nresult\nDEBTIK-EXEC-STATUS:%s\n", status) } }() err := runOneShot(client, "user", "password", "invalid", time.Second, false) if (err == nil) != (status == "0") { t.Fatalf("status %s: %v", status, err) } }) } } func TestOneShotJSONEnvelope(t *testing.T) { client, server := net.Pipe() defer client.Close() go func() { defer server.Close() r := bufio.NewReader(server) fmt.Fprint(server, "login:") r.ReadString('\n') fmt.Fprint(server, "password:") r.ReadString('\n') fmt.Fprint(server, "[user@router] > ") r.ReadString('\n') fmt.Fprint(server, "echoed command\r\nDEBTIK-EXEC-BEGIN\r\nresult\r\nDEBTIK-EXEC-STATUS:1\r\n") }() original := os.Stdout read, write, err := os.Pipe() if err != nil { t.Fatal(err) } os.Stdout = write defer func() { os.Stdout = original; read.Close() }() err = runOneShot(client, "user", "password", "invalid", time.Second, true) write.Close() if err == nil { t.Fatal("expected failure") } var got struct { Output string `json:"output"` Status int `json:"status"` OK bool `json:"ok"` } if err := json.NewDecoder(read).Decode(&got); err != nil { t.Fatal(err) } if got.OK || got.Status != 1 || got.Output != "result\r\n" { t.Fatalf("unexpected envelope: %+v", got) } }