2024-10-22 00:12:14 +00:00
|
|
|
package tortoise_test
|
2024-10-21 19:29:17 +00:00
|
|
|
|
|
|
|
import (
|
2024-11-19 06:33:14 +00:00
|
|
|
"context"
|
|
|
|
"os/exec"
|
2024-10-23 20:34:44 +00:00
|
|
|
"sync"
|
2024-10-21 19:29:17 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
2024-10-22 00:12:14 +00:00
|
|
|
"git.iamthefij.com/iamthefij/tortoise"
|
2024-10-21 19:29:17 +00:00
|
|
|
)
|
|
|
|
|
2024-11-19 06:33:14 +00:00
|
|
|
const (
|
|
|
|
TaskStartWait = 10 * time.Millisecond
|
|
|
|
)
|
|
|
|
|
2024-10-21 19:29:17 +00:00
|
|
|
func TestShellRunnerNoCallback(t *testing.T) {
|
2024-10-22 00:12:14 +00:00
|
|
|
t.Parallel()
|
|
|
|
|
2024-10-21 19:29:17 +00:00
|
|
|
cases := []struct {
|
|
|
|
command string
|
|
|
|
output string
|
|
|
|
ReturnCode int
|
|
|
|
}{
|
|
|
|
{"echo hello world", "hello world\n", 0},
|
|
|
|
{"echo hello world && exit 1", "hello world\n", 1},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, c := range cases {
|
|
|
|
c := c
|
|
|
|
t.Run(c.command, func(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-10-22 00:12:14 +00:00
|
|
|
runner := tortoise.NewShellRunner()
|
2024-10-21 19:29:17 +00:00
|
|
|
runner.Start()
|
|
|
|
|
|
|
|
// Test command without callback
|
|
|
|
if err := runner.AddCommand(c.command, nil); err != nil {
|
|
|
|
t.Fatalf("unexpected error adding command: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-11-19 06:33:14 +00:00
|
|
|
// Wait a sec for the worker to pick up the task
|
|
|
|
time.Sleep(TaskStartWait)
|
|
|
|
|
2024-10-21 19:29:17 +00:00
|
|
|
runner.Stop()
|
|
|
|
|
|
|
|
result := runner.GetResults()
|
2024-11-19 06:33:14 +00:00
|
|
|
if result == nil {
|
|
|
|
t.Fatal("expected result, got nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.Output != c.output || result.ReturnCode != c.ReturnCode {
|
2024-10-21 19:29:17 +00:00
|
|
|
t.Fatalf("expected output '%s' and return code %d, got '%s' and %d", c.output, c.ReturnCode, result.Output, result.ReturnCode)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestShellRunnerCallback(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-10-22 00:12:14 +00:00
|
|
|
runner := tortoise.NewShellRunner()
|
2024-10-21 19:29:17 +00:00
|
|
|
runner.Start()
|
|
|
|
|
|
|
|
// Test command with callback
|
2024-10-23 20:34:44 +00:00
|
|
|
outputString := ""
|
|
|
|
callbackWait := sync.WaitGroup{}
|
2024-10-21 19:29:17 +00:00
|
|
|
|
2024-10-23 20:34:44 +00:00
|
|
|
callbackWait.Add(1)
|
2024-10-21 19:29:17 +00:00
|
|
|
|
2024-10-23 20:34:44 +00:00
|
|
|
if err := runner.AddCommand("echo callback a", func(result *tortoise.CommandResult) {
|
|
|
|
if result.Output != "callback a\n" {
|
|
|
|
t.Fatalf("expected 'callback a', got '%s'", result.Output)
|
2024-10-21 19:29:17 +00:00
|
|
|
}
|
2024-10-23 20:34:44 +00:00
|
|
|
outputString = outputString + "a"
|
|
|
|
callbackWait.Done()
|
|
|
|
}); err != nil {
|
|
|
|
t.Fatalf("unexpected error adding command: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-11-19 06:33:14 +00:00
|
|
|
// Wait a sec for the worker to pick up the task
|
|
|
|
time.Sleep(TaskStartWait)
|
|
|
|
|
2024-10-23 20:34:44 +00:00
|
|
|
callbackWait.Add(1)
|
|
|
|
|
|
|
|
if err := runner.AddCommand("echo callback b", func(result *tortoise.CommandResult) {
|
|
|
|
if result.Output != "callback b\n" {
|
|
|
|
t.Fatalf("expected 'callback b', got '%s'", result.Output)
|
|
|
|
}
|
|
|
|
outputString = outputString + "b"
|
|
|
|
callbackWait.Done()
|
2024-10-21 19:29:17 +00:00
|
|
|
}); err != nil {
|
|
|
|
t.Fatalf("unexpected error adding command: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-10-23 20:34:44 +00:00
|
|
|
// Timeout waiting for callbacks
|
|
|
|
done := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
callbackWait.Wait()
|
|
|
|
close(done)
|
|
|
|
}()
|
|
|
|
|
2024-10-21 19:29:17 +00:00
|
|
|
select {
|
|
|
|
case <-done:
|
|
|
|
case <-time.After(2 * time.Second):
|
2024-10-23 20:34:44 +00:00
|
|
|
t.Fatal("callbacks timed out")
|
2024-10-21 19:29:17 +00:00
|
|
|
}
|
|
|
|
|
2024-10-23 20:34:44 +00:00
|
|
|
if outputString != "ab" {
|
2024-11-19 06:33:14 +00:00
|
|
|
t.Fatal("callbacks were not reached in order:", outputString)
|
2024-10-21 19:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
runner.Stop()
|
|
|
|
|
|
|
|
// Make sure stop and kill both exit gracefully after the runner is stopped
|
|
|
|
runner.Stop()
|
2024-10-23 20:34:16 +00:00
|
|
|
runner.Kill()
|
2024-10-21 19:29:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestShellRunnerKillWithTimeout(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
2024-10-22 00:12:14 +00:00
|
|
|
runner := tortoise.NewShellRunner()
|
2024-10-21 19:29:17 +00:00
|
|
|
runner.Start()
|
|
|
|
|
|
|
|
// Test command with callback
|
|
|
|
callbackReached := false
|
|
|
|
|
2024-10-22 00:12:14 +00:00
|
|
|
if err := runner.AddCommand("sleep 10 && echo callback test", func(result *tortoise.CommandResult) {
|
2024-10-21 19:29:17 +00:00
|
|
|
callbackReached = true
|
|
|
|
if result.Output != "callback test\n" {
|
|
|
|
t.Fatalf("expected 'callback test', got '%s'", result.Output)
|
|
|
|
}
|
|
|
|
}); err != nil {
|
|
|
|
t.Fatalf("unexpected error adding command: %v", err)
|
|
|
|
}
|
|
|
|
|
2024-11-19 06:33:14 +00:00
|
|
|
// Wait a sec for the worker to pick up the task
|
|
|
|
time.Sleep(TaskStartWait)
|
2024-10-21 19:29:17 +00:00
|
|
|
|
|
|
|
if err := runner.KillWithTimeout(1 * time.Second); err == nil {
|
|
|
|
t.Fatal("expected error when killing commands, but got none")
|
|
|
|
}
|
|
|
|
|
|
|
|
if callbackReached {
|
|
|
|
t.Fatal("callback was reached before kill")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestStopPreventsNewCommands(t *testing.T) {
|
2024-10-22 00:12:14 +00:00
|
|
|
runner := tortoise.NewShellRunner()
|
2024-10-21 19:29:17 +00:00
|
|
|
runner.Start()
|
|
|
|
|
|
|
|
runner.Stop()
|
|
|
|
|
|
|
|
err := runner.AddCommand("echo should not run", nil)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("expected error when adding command after stop, but got none")
|
|
|
|
}
|
|
|
|
}
|
2024-10-23 20:34:16 +00:00
|
|
|
|
|
|
|
func TestAddingPriorToStart(t *testing.T) {
|
|
|
|
runner := tortoise.NewShellRunner()
|
|
|
|
|
|
|
|
err := runner.AddCommand("echo should not run", nil)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatal("Should have failed to add prior to starting runner")
|
|
|
|
}
|
|
|
|
}
|
2024-11-19 06:33:14 +00:00
|
|
|
|
|
|
|
func TestAddCmdWithTimeout(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
runner := tortoise.NewShellRunner()
|
|
|
|
runner.Start()
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
|
|
|
|
|
|
|
|
cmd := exec.CommandContext(ctx, "sleep", "10")
|
|
|
|
|
|
|
|
err := runner.AddCmd(cmd, nil, cancel)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error adding command: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait a sec for the worker to pick up the task
|
|
|
|
time.Sleep(TaskStartWait)
|
|
|
|
|
|
|
|
runner.Stop()
|
|
|
|
|
|
|
|
result := runner.GetResults()
|
|
|
|
if result == nil {
|
|
|
|
t.Fatal("expected result, got nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.ReturnCode != -1 {
|
|
|
|
t.Fatalf("expected return code -1, got %d", result.ReturnCode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestShellWithTimeout(t *testing.T) {
|
|
|
|
t.Parallel()
|
|
|
|
|
|
|
|
runner := tortoise.NewShellRunner()
|
|
|
|
runner.SetTimeout(1 * time.Second)
|
|
|
|
runner.Start()
|
|
|
|
|
|
|
|
err := runner.AddCommand("sleep 10", nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error adding command: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait a sec for the worker to pick up the task
|
|
|
|
time.Sleep(TaskStartWait)
|
|
|
|
|
|
|
|
runner.Stop()
|
|
|
|
|
|
|
|
result := runner.GetResults()
|
|
|
|
if result == nil {
|
|
|
|
t.Fatal("expected result, got nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
if result.ReturnCode != -1 {
|
|
|
|
t.Fatalf("expected return code -1, got %d", result.ReturnCode)
|
|
|
|
}
|
|
|
|
}
|