summaryrefslogtreecommitdiff
path: root/integrationtests
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-02 21:23:00 +0300
committerPaul Buetow <paul@buetow.org>2025-07-02 21:23:00 +0300
commit17ee5e62c2b1037c21cb36f2677d2c538e2542cb (patch)
tree8fbed16de9d7ae13307216551cbdafcd34127bf9 /integrationtests
parente7a64c7e338e0d8818425e67650e673240d9b853 (diff)
feat: add server info message for literal grep mode
- Add IsLiteral() and Pattern() methods to regex.Regex struct - Log info message when grep uses optimized literal string matching - Fix bug where grep commands were processed as cat commands - Add comprehensive integration tests to verify literal mode messages This gives users visibility when the performance-optimized literal string matching is being used instead of regex matching. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'integrationtests')
-rw-r--r--integrationtests/dgrep_literal_info_test.go191
1 files changed, 191 insertions, 0 deletions
diff --git a/integrationtests/dgrep_literal_info_test.go b/integrationtests/dgrep_literal_info_test.go
new file mode 100644
index 0000000..c007263
--- /dev/null
+++ b/integrationtests/dgrep_literal_info_test.go
@@ -0,0 +1,191 @@
+package integrationtests
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+
+ "github.com/mimecast/dtail/internal/config"
+)
+
+// TestDGrepLiteralModeInfo verifies that the server logs info message when using literal mode
+func TestDGrepLiteralModeInfo(t *testing.T) {
+ if !config.Env("DTAIL_INTEGRATION_TEST_RUN_MODE") {
+ t.Log("Skipping")
+ return
+ }
+
+ cleanupTmpFiles(t)
+ testLogger := NewTestLogger("TestDGrepLiteralModeInfo")
+ defer testLogger.WriteLogFile()
+
+ // Create test data
+ testData := `ERROR test line 1
+WARNING test line 2
+ERROR test line 3
+INFO test line 4
+ERROR test line 5
+`
+ testFile := "literal_info_test.log.tmp"
+ if err := os.WriteFile(testFile, []byte(testData), 0644); err != nil {
+ t.Fatal("Failed to create test file:", err)
+ }
+ defer os.Remove(testFile)
+
+ // Test patterns - both literal and regex
+ tests := []struct {
+ name string
+ pattern string
+ expectLiteral bool
+ expectedCount int
+ }{
+ {
+ name: "SimpleLiteral",
+ pattern: "ERROR",
+ expectLiteral: true,
+ expectedCount: 3,
+ },
+ {
+ name: "LiteralWithSpace",
+ pattern: "ERROR test",
+ expectLiteral: true,
+ expectedCount: 3,
+ },
+ {
+ name: "RegexPattern",
+ pattern: "ERROR.*line [0-9]",
+ expectLiteral: false,
+ expectedCount: 3,
+ },
+ {
+ name: "RegexAlternation",
+ pattern: "(ERROR|WARNING)",
+ expectLiteral: false,
+ expectedCount: 4,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ port := getUniquePortNumber()
+ bindAddress := "localhost"
+
+ ctx, cancel := context.WithCancel(context.Background())
+ ctx = WithTestLogger(ctx, testLogger)
+ defer cancel()
+
+ // Start dserver with info log level to capture our message
+ stdoutCh, stderrCh, _, err := startCommand(ctx, t,
+ "", "../dserver",
+ "--cfg", "none",
+ "--logger", "stdout",
+ "--logLevel", "info", // Changed from error to info
+ "--bindAddress", bindAddress,
+ "--port", fmt.Sprintf("%d", port),
+ )
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ // Capture server output
+ var serverOutput strings.Builder
+ var outputMutex sync.Mutex
+ outputDone := make(chan struct{})
+
+ go func() {
+ defer close(outputDone)
+ for {
+ select {
+ case line := <-stdoutCh:
+ outputMutex.Lock()
+ serverOutput.WriteString(line)
+ serverOutput.WriteString("\n")
+ outputMutex.Unlock()
+ case line := <-stderrCh:
+ outputMutex.Lock()
+ serverOutput.WriteString(line)
+ serverOutput.WriteString("\n")
+ outputMutex.Unlock()
+ case <-ctx.Done():
+ return
+ }
+ }
+ }()
+
+ // Give server time to start
+ time.Sleep(500 * time.Millisecond)
+
+ // Run dgrep
+ outFile := fmt.Sprintf("dgrep_info_%s.stdout.tmp", test.name)
+ defer os.Remove(outFile)
+
+ _, err = runCommand(ctx, t, outFile,
+ "../dgrep",
+ "--plain",
+ "--cfg", "none",
+ "--grep", test.pattern,
+ "--servers", fmt.Sprintf("%s:%d", bindAddress, port),
+ "--trustAllHosts",
+ "--noColor",
+ "--files", testFile)
+
+ if err != nil {
+ t.Errorf("Failed to run dgrep with pattern '%s': %v", test.pattern, err)
+ return
+ }
+
+ // Give time for server output to be captured
+ time.Sleep(500 * time.Millisecond)
+
+ // Stop server
+ cancel()
+
+ // Wait for output capture goroutine to finish
+ select {
+ case <-outputDone:
+ case <-time.After(2 * time.Second):
+ t.Log("Warning: output capture goroutine did not finish in time")
+ }
+
+ // Check grep output for correctness
+ content, err := os.ReadFile(outFile)
+ if err != nil {
+ t.Errorf("Failed to read output file: %v", err)
+ return
+ }
+
+ lines := strings.Split(strings.TrimSpace(string(content)), "\n")
+ actualCount := 0
+ for _, line := range lines {
+ if line != "" {
+ actualCount++
+ }
+ }
+
+ if actualCount != test.expectedCount {
+ t.Errorf("Pattern '%s': expected %d matches, got %d", test.pattern, test.expectedCount, actualCount)
+ }
+
+ // Check server output for literal mode message
+ outputMutex.Lock()
+ serverLog := serverOutput.String()
+ outputMutex.Unlock()
+ // The server uses structured logging, so the message appears as "pattern:|<pattern>"
+ literalMsg := fmt.Sprintf("Using optimized literal string matching for pattern:|%s", test.pattern)
+ containsLiteralMsg := strings.Contains(serverLog, literalMsg)
+
+ if test.expectLiteral && !containsLiteralMsg {
+ t.Errorf("Expected literal mode info message for pattern '%s' but didn't find it", test.pattern)
+ t.Logf("Server output:\n%s", serverLog)
+ } else if !test.expectLiteral && containsLiteralMsg {
+ t.Errorf("Did not expect literal mode info message for pattern '%s' but found it", test.pattern)
+ t.Logf("Server output:\n%s", serverLog)
+ }
+ })
+ }
+} \ No newline at end of file