2023-01-30 19:55:55 +01:00
|
|
|
package cmdext
|
|
|
|
|
2023-01-31 22:41:12 +01:00
|
|
|
import (
|
2023-08-09 17:48:06 +02:00
|
|
|
"errors"
|
2023-02-03 00:59:54 +01:00
|
|
|
"fmt"
|
2023-01-31 22:41:12 +01:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
2023-01-30 19:55:55 +01:00
|
|
|
|
|
|
|
func TestStdout(t *testing.T) {
|
|
|
|
|
|
|
|
res1, err := Runner("printf").Arg("hello").Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-01-30 19:55:55 +01:00
|
|
|
if res1.StdErr != "" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "hello" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "hello\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStderr(t *testing.T) {
|
|
|
|
|
|
|
|
res1, err := Runner("python").Arg("-c").Arg("import sys; print(\"error\", file=sys.stderr, end='')").Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-01-30 19:55:55 +01:00
|
|
|
if res1.StdErr != "error" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "error\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStdcombined(t *testing.T) {
|
|
|
|
res1, err := Runner("python").
|
|
|
|
Arg("-c").
|
|
|
|
Arg("import sys; import time; print(\"1\", file=sys.stderr, flush=True); time.sleep(0.1); print(\"2\", file=sys.stdout, flush=True); time.sleep(0.1); print(\"3\", file=sys.stderr, flush=True)").
|
|
|
|
Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-01-30 19:55:55 +01:00
|
|
|
if res1.StdErr != "1\n3\n" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "2\n" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "1\n2\n3\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-01-31 22:41:12 +01:00
|
|
|
|
|
|
|
func TestPartialRead(t *testing.T) {
|
|
|
|
res1, err := Runner("python").
|
|
|
|
Arg("-c").
|
|
|
|
Arg("import sys; import time; print(\"first message\", flush=True); time.sleep(5); print(\"cant see me\", flush=True);").
|
|
|
|
Timeout(100 * time.Millisecond).
|
|
|
|
Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
|
|
|
if !res1.CommandTimedOut {
|
|
|
|
t.Errorf("!CommandTimedOut")
|
|
|
|
}
|
|
|
|
if res1.StdErr != "" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "first message\n" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "first message\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-01-31 23:46:35 +01:00
|
|
|
|
|
|
|
func TestPartialReadStderr(t *testing.T) {
|
|
|
|
res1, err := Runner("python").
|
|
|
|
Arg("-c").
|
|
|
|
Arg("import sys; import time; print(\"first message\", file=sys.stderr, flush=True); time.sleep(5); print(\"cant see me\", file=sys.stderr, flush=True);").
|
|
|
|
Timeout(100 * time.Millisecond).
|
|
|
|
Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
|
|
|
if !res1.CommandTimedOut {
|
|
|
|
t.Errorf("!CommandTimedOut")
|
|
|
|
}
|
|
|
|
if res1.StdErr != "first message\n" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "first message\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadUnflushedStdout(t *testing.T) {
|
|
|
|
|
|
|
|
res1, err := Runner("python").Arg("-c").Arg("import sys; print(\"message101\", file=sys.stdout, end='')").Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-01-31 23:46:35 +01:00
|
|
|
if res1.StdErr != "" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "message101" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "message101\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestReadUnflushedStderr(t *testing.T) {
|
|
|
|
|
|
|
|
res1, err := Runner("python").Arg("-c").Arg("import sys; print(\"message101\", file=sys.stderr, end='')").Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-01-31 23:46:35 +01:00
|
|
|
if res1.StdErr != "message101" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "message101\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPartialReadUnflushed(t *testing.T) {
|
|
|
|
t.SkipNow()
|
|
|
|
|
|
|
|
res1, err := Runner("python").
|
|
|
|
Arg("-c").
|
|
|
|
Arg("import sys; import time; print(\"first message\", end=''); time.sleep(5); print(\"cant see me\", end='');").
|
|
|
|
Timeout(100 * time.Millisecond).
|
|
|
|
Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
|
|
|
if !res1.CommandTimedOut {
|
|
|
|
t.Errorf("!CommandTimedOut")
|
|
|
|
}
|
|
|
|
if res1.StdErr != "" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "first message" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "first message" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPartialReadUnflushedStderr(t *testing.T) {
|
|
|
|
t.SkipNow()
|
|
|
|
|
|
|
|
res1, err := Runner("python").
|
|
|
|
Arg("-c").
|
|
|
|
Arg("import sys; import time; print(\"first message\", file=sys.stderr, end=''); time.sleep(5); print(\"cant see me\", file=sys.stderr, end='');").
|
|
|
|
Timeout(100 * time.Millisecond).
|
|
|
|
Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
|
|
|
if !res1.CommandTimedOut {
|
|
|
|
t.Errorf("!CommandTimedOut")
|
|
|
|
}
|
|
|
|
if res1.StdErr != "first message" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "first message" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-02-03 00:59:54 +01:00
|
|
|
|
|
|
|
func TestListener(t *testing.T) {
|
|
|
|
|
2023-02-09 16:49:33 +01:00
|
|
|
res1, err := Runner("python").
|
2023-02-03 00:59:54 +01:00
|
|
|
Arg("-c").
|
|
|
|
Arg("import sys;" +
|
|
|
|
"import time;" +
|
|
|
|
"print(\"message 1\", flush=True);" +
|
|
|
|
"time.sleep(1);" +
|
|
|
|
"print(\"message 2\", flush=True);" +
|
|
|
|
"time.sleep(1);" +
|
|
|
|
"print(\"message 3\", flush=True);" +
|
|
|
|
"time.sleep(1);" +
|
|
|
|
"print(\"message 4\", file=sys.stderr, flush=True);" +
|
|
|
|
"time.sleep(1);" +
|
|
|
|
"print(\"message 5\", flush=True);" +
|
|
|
|
"time.sleep(1);" +
|
|
|
|
"print(\"final\");").
|
|
|
|
ListenStdout(func(s string) { fmt.Printf("@@STDOUT <<- %v (%v)\n", s, time.Now().Format(time.RFC3339Nano)) }).
|
|
|
|
ListenStderr(func(s string) { fmt.Printf("@@STDERR <<- %v (%v)\n", s, time.Now().Format(time.RFC3339Nano)) }).
|
|
|
|
Timeout(10 * time.Second).
|
|
|
|
Run()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-02-03 00:59:54 +01:00
|
|
|
}
|
2023-02-09 15:01:54 +01:00
|
|
|
|
|
|
|
func TestLongStdout(t *testing.T) {
|
|
|
|
|
|
|
|
res1, err := Runner("python").
|
|
|
|
Arg("-c").
|
2023-02-09 16:49:33 +01:00
|
|
|
Arg("import sys; import time; print(\"X\" * 125001 + \"\\n\"); print(\"Y\" * 125001 + \"\\n\"); print(\"Z\" * 125001 + \"\\n\");").
|
|
|
|
Timeout(5000 * time.Millisecond).
|
2023-02-09 15:01:54 +01:00
|
|
|
Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("%v", err)
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != 0 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
2023-02-09 15:01:54 +01:00
|
|
|
if res1.StdErr != "" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
2023-02-13 01:41:33 +01:00
|
|
|
if len(res1.StdOut) != 375009 {
|
2023-02-09 15:01:54 +01:00
|
|
|
t.Errorf("len(res1.StdOut) == '%v'", len(res1.StdOut))
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2023-02-09 16:49:33 +01:00
|
|
|
|
|
|
|
func TestFailOnTimeout(t *testing.T) {
|
|
|
|
|
|
|
|
_, err := Runner("sleep").Arg("2").Timeout(200 * time.Millisecond).FailOnTimeout().Run()
|
2023-08-09 17:48:06 +02:00
|
|
|
if !errors.Is(err, ErrTimeout) {
|
2023-02-09 16:49:33 +01:00
|
|
|
t.Errorf("wrong err := %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-08-09 17:48:06 +02:00
|
|
|
func TestFailOnStderr(t *testing.T) {
|
|
|
|
|
|
|
|
res1, err := Runner("python").Arg("-c").Arg("import sys; print(\"error\", file=sys.stderr, end='')").FailOnStderr().Run()
|
|
|
|
if err == nil {
|
|
|
|
t.Errorf("no err")
|
|
|
|
}
|
|
|
|
if res1.CommandTimedOut {
|
|
|
|
t.Errorf("Timeout")
|
|
|
|
}
|
|
|
|
if res1.ExitCode != -1 {
|
|
|
|
t.Errorf("res1.ExitCode == %v", res1.ExitCode)
|
|
|
|
}
|
|
|
|
if res1.StdErr != "error" {
|
|
|
|
t.Errorf("res1.StdErr == '%v'", res1.StdErr)
|
|
|
|
}
|
|
|
|
if res1.StdOut != "" {
|
|
|
|
t.Errorf("res1.StdOut == '%v'", res1.StdOut)
|
|
|
|
}
|
|
|
|
if res1.StdCombined != "error\n" {
|
|
|
|
t.Errorf("res1.StdCombined == '%v'", res1.StdCombined)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-02-09 16:49:33 +01:00
|
|
|
func TestFailOnExitcode(t *testing.T) {
|
|
|
|
|
|
|
|
_, err := Runner("false").Timeout(200 * time.Millisecond).FailOnExitCode().Run()
|
2023-08-09 17:48:06 +02:00
|
|
|
if !errors.Is(err, ErrExitCode) {
|
2023-02-09 16:49:33 +01:00
|
|
|
t.Errorf("wrong err := %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEnsureExitcode1(t *testing.T) {
|
|
|
|
|
|
|
|
_, err := Runner("false").Timeout(200 * time.Millisecond).EnsureExitcode(1).Run()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("wrong err := %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEnsureExitcode2(t *testing.T) {
|
|
|
|
|
|
|
|
_, err := Runner("false").Timeout(200*time.Millisecond).EnsureExitcode(0, 2, 3).Run()
|
|
|
|
if err != ErrExitCode {
|
|
|
|
t.Errorf("wrong err := %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|