From 8568e63c9ee8433f9d47f4aca9a3b713f467a5ce Mon Sep 17 00:00:00 2001 From: Piotr Date: Tue, 10 Dec 2024 18:20:50 +0100 Subject: [PATCH] some tests --- tests/follow_test.go | 147 +++++++++++++++++++++++++++++++++++++++++++ tests/stdin_test.go | 104 ++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 tests/follow_test.go create mode 100644 tests/stdin_test.go diff --git a/tests/follow_test.go b/tests/follow_test.go new file mode 100644 index 0000000..9af1158 --- /dev/null +++ b/tests/follow_test.go @@ -0,0 +1,147 @@ +package tests + +import ( + "bufio" + "fmt" + "io" + "os" + "os/exec" + "strings" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func readOutput(t *testing.T, stdout io.ReadCloser, outputChan chan string, followChan chan bool, wg *sync.WaitGroup) { + defer wg.Done() + reader := bufio.NewReader(stdout) + for { + line, err := reader.ReadString('\n') + if err == io.EOF { + return + } + if err != nil { + t.Logf("Error reading stdout: %v", err) + return + } + // Log all lines for debugging + t.Logf("Received line: %s", strings.TrimSpace(line)) + // Signal when we see the "Following file changes" message + if strings.Contains(line, "Following file changes") { + select { + case followChan <- true: + default: + } + } + // Only capture actual test lines, not debug/info messages + if strings.Contains(line, "test line") && !strings.Contains(line, "level=") { + outputChan <- strings.TrimSpace(line) + } + } +} + +func TestLogdyE2E_FollowFullRead(t *testing.T) { + // Create a named pipe + pipeName := "/tmp/logdy-test-pipe-full" + + // Remove existing pipe if it exists + if _, err := os.Stat(pipeName); err == nil { + os.Remove(pipeName) + } + + err := exec.Command("mkfifo", pipeName).Run() + if err != nil { + t.Fatalf("Failed to create pipe: %v", err) + } + defer os.Remove(pipeName) + + t.Logf("Created named pipe: %s", pipeName) + + // Channel to communicate the pipe writer + pipeWriterChan := make(chan *os.File) + + // Open pipe for writing in a goroutine + go func() { + pipeWriter, err := os.OpenFile(pipeName, os.O_WRONLY, 0644) + assert.NoError(t, err) + pipeWriterChan <- pipeWriter // Send the writer to the main goroutine + }() + + // Start logdy process in follow mode with full-read and fallthrough enabled + cmd := exec.Command("go", "run", "../main.go", "follow", "--full-read", "-t", pipeName) + + // Get stdout pipe + stdout, err := cmd.StdoutPipe() + assert.NoError(t, err) + + // Create channels to collect output lines and signal following started + outputChan := make(chan string, 100) // Buffered channel to prevent blocking + followChan := make(chan bool, 1) // Channel to signal when following starts + + // Start the process + err = cmd.Start() + assert.NoError(t, err) + + // Use WaitGroup to manage the goroutine + var wg sync.WaitGroup + wg.Add(1) + go readOutput(t, stdout, outputChan, followChan, &wg) + + // Wait for the pipe writer + var pipeWriter *os.File + select { + case pipeWriter = <-pipeWriterChan: + defer pipeWriter.Close() + case <-time.After(5 * time.Second): + t.Fatal("Timeout waiting for pipe writer") + } + + // Write all test lines to the pipe + allTestLines := []string{ + "test line 1", + "test line 2", + "test line 3", + "test line 4", + } + + for _, line := range allTestLines { + t.Logf("Writing line: %s", line) + _, err := pipeWriter.WriteString(line + "\n") + assert.NoError(t, err) + // Small delay between writes + time.Sleep(1 * time.Millisecond) + } + wg.Done() + + // Collect output with timeout + receivedLines := make([]string, 0) + expectedLines := 4 + timeout := time.After(5 * time.Second) + + for i := 0; i < expectedLines; i++ { + select { + case line := <-outputChan: + t.Logf("Collected line: %s", line) + receivedLines = append(receivedLines, line) + case <-timeout: + t.Fatalf("Timeout waiting for output. Got %d lines, expected %d. Received lines: %v", + len(receivedLines), expectedLines, receivedLines) + } + } + + // Kill the process since we're done testing + if err := cmd.Process.Kill(); err != nil { + t.Errorf("Failed to kill process: %v", err) + } + + // Wait for the output reader goroutine to finish + wg.Wait() + + // Verify output matches expected + assert.Equal(t, expectedLines, len(receivedLines)) + for i, line := range receivedLines { + assert.Equal(t, fmt.Sprintf("test line %d", i+1), line) + } +} diff --git a/tests/stdin_test.go b/tests/stdin_test.go new file mode 100644 index 0000000..800f0ef --- /dev/null +++ b/tests/stdin_test.go @@ -0,0 +1,104 @@ +package tests + +import ( + "bufio" + "io" + "os/exec" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func runCmd(cmds []string, t *testing.T) { + // Start logdy process in stdin mode with fallthrough enabled + // -t enables fallthrough so we can see the output + cmd := exec.Command("go", cmds...) + + // Get stdin pipe + stdin, err := cmd.StdinPipe() + assert.NoError(t, err) + + // Get stdout pipe + stdout, err := cmd.StdoutPipe() + assert.NoError(t, err) + + // Start the process + err = cmd.Start() + assert.NoError(t, err) + + // Create a channel to collect output lines + outputChan := make(chan string) + + // Start goroutine to read stdout + go func() { + reader := bufio.NewReader(stdout) + for { + line, err := reader.ReadString('\n') + if err == io.EOF { + close(outputChan) + return + } + if err != nil { + t.Errorf("Error reading stdout: %v", err) + close(outputChan) + return + } + // Only collect lines that contain our test data + if strings.Contains(line, "test line") { + outputChan <- strings.TrimSpace(line) + } + } + }() + + // Give the process a moment to start up + time.Sleep(1 * time.Second) + + // Write test data to stdin + testLines := []string{ + "test line 1", + "test line 2", + "test line 3", + } + + for _, line := range testLines { + _, err := io.WriteString(stdin, line+"\n") + assert.NoError(t, err) + } + + // Collect output with timeout + receivedLines := make([]string, 0) + timeout := time.After(5 * time.Second) + + for i := 0; i < len(testLines); i++ { + select { + case line, ok := <-outputChan: + if !ok { + t.Fatal("Output channel closed before receiving all expected lines") + } + receivedLines = append(receivedLines, line) + case <-timeout: + t.Fatal("Timeout waiting for output") + } + } + + // Kill the process since we're done testing + if err := cmd.Process.Kill(); err != nil { + t.Errorf("Failed to kill process: %v", err) + } + + // Verify output matches input + assert.Equal(t, len(testLines), len(receivedLines)) + for i, testLine := range testLines { + assert.Contains(t, receivedLines[i], testLine) + } +} + +func TestLogdyE2E_NoCommand(t *testing.T) { + runCmd([]string{"run", "../main.go", "-t"}, t) +} + +func TestLogdyE2E_StdinCommand(t *testing.T) { + runCmd([]string{"run", "../main.go", "stdin", "-t"}, t) +}