Skip to content

Commit 1c2149e

Browse files
authored
Add Unit tests for Logs, Resolve, Rules and Sigs Packages (#56)
* added log-resolve-rules-sigs tests Signed-off-by: amanycodes <amanycodes@gmail.com> * added cli-test mock comments Signed-off-by: amanycodes <amanycodes@gmail.com> --------- Signed-off-by: amanycodes <amanycodes@gmail.com>
1 parent 12da462 commit 1c2149e

6 files changed

Lines changed: 440 additions & 1 deletion

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# preq
2-
![Coverage](https://img.shields.io/badge/Coverage-39.8%25-red)
2+
![Coverage](https://img.shields.io/badge/Coverage-45.2%25-orange)
33
[![Unit Tests](https://github.com/prequel-dev/cre/actions/workflows/build.yml/badge.svg)](https://github.com/prequel-dev/cre/actions/workflows/build.yml)
44
[![Unit Tests](https://github.com/prequel-dev/preq/actions/workflows/build.yml/badge.svg)](https://github.com/prequel-dev/preq/actions/workflows/build.yml)
55
[![Unit Tests](https://github.com/prequel-dev/prequel-compiler/actions/workflows/build.yml/badge.svg)](https://github.com/prequel-dev/prequel-compiler/actions/workflows/build.yml)

internal/pkg/cli/cli.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ var (
4141
ruleUpdateFile = filepath.Join(defaultConfigDir, ".ruleupdate")
4242
)
4343

44+
// Package-level variables to allow mocking in tests.
4445
var (
4546
getRulesFunc = func(ctx context.Context, conf *config.Config, configDir, cmdLineRules, token, ruleUpdateFile, baseAddr string, tlsPort, udpPort int) ([]utils.RulePathT, error) {
4647
return rules.GetRules(ctx, conf, configDir, cmdLineRules, token, ruleUpdateFile, baseAddr, tlsPort, udpPort)
@@ -114,6 +115,7 @@ func InitAndExecute(ctx context.Context) error {
114115
}
115116

116117
// Log in for community rule updates
118+
// Mockable function variable to allow for testing without real network calls
117119
if token, err = loginUserFunc(ctx, baseAddr, ruleToken); err != nil {
118120
log.Error().Err(err).Msg("Failed to login")
119121

@@ -137,6 +139,7 @@ func InitAndExecute(ctx context.Context) error {
137139
c.Skip = timez.DefaultSkip
138140
}
139141

142+
// Mockable function variable to allow for testing without real network calls
140143
rulesPaths, err = getRulesFunc(ctx, c, defaultConfigDir, Options.Rules, token, ruleUpdateFile, baseAddr, tlsPort, udpPort)
141144
if err != nil {
142145
log.Error().Err(err).Msg("Failed to get rules")

internal/pkg/logs/logs_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package logs
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
"time"
8+
9+
"github.com/rs/zerolog"
10+
)
11+
12+
func TestShortenCaller(t *testing.T) {
13+
testCases := []struct {
14+
name string
15+
file string
16+
line int
17+
expected string
18+
}{
19+
{
20+
name: "long unix path",
21+
file: "/home/user/go/src/github.com/prequel-dev/preq/internal/pkg/cli/cli.go",
22+
line: 42,
23+
expected: "cli.go:42",
24+
},
25+
{
26+
name: "long windows path",
27+
file: `C:\Users\user\go\src\github.com\prequel-dev\preq\internal\pkg\cli\cli.go`,
28+
line: 101,
29+
expected: `C:\Users\user\go\src\github.com\prequel-dev\preq\internal\pkg\cli\cli.go:101`,
30+
},
31+
}
32+
33+
for _, tc := range testCases {
34+
t.Run(tc.name, func(t *testing.T) {
35+
result := shortenCaller(0, tc.file, tc.line)
36+
if result != tc.expected {
37+
t.Errorf("Expected '%s', but got '%s'", tc.expected, result)
38+
}
39+
})
40+
}
41+
}
42+
43+
func TestMkTimestampFormatter(t *testing.T) {
44+
const testTimeFormat = time.RFC1123
45+
46+
var buf bytes.Buffer
47+
48+
writer := zerolog.ConsoleWriter{
49+
Out: &buf,
50+
FormatTimestamp: mkTimestampFormatter(testTimeFormat, 37),
51+
NoColor: true,
52+
}
53+
54+
logger := zerolog.New(writer).With().Timestamp().Logger()
55+
56+
logTime := time.Date(2023, 10, 28, 10, 30, 0, 0, time.UTC)
57+
expectedTimeString := logTime.Local().Format(testTimeFormat)
58+
59+
zerolog.TimestampFunc = func() time.Time {
60+
return logTime
61+
}
62+
t.Cleanup(func() {
63+
zerolog.TimestampFunc = time.Now
64+
})
65+
66+
logger.Info().Msg("hello world")
67+
68+
output := buf.String()
69+
70+
if !strings.Contains(output, expectedTimeString) {
71+
t.Errorf("Expected log output to contain timestamp '%s', but it was not found in '%s'", expectedTimeString, output)
72+
}
73+
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package resolve
2+
3+
import (
4+
"compress/gzip"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
"testing"
9+
10+
"github.com/prequel-dev/prequel-compiler/pkg/datasrc"
11+
)
12+
13+
func createTestFile(t *testing.T, dir, name, content string, useGzip bool) string {
14+
t.Helper()
15+
path := filepath.Join(dir, name)
16+
17+
f, err := os.Create(path)
18+
if err != nil {
19+
t.Fatalf("Failed to create test file: %v", err)
20+
}
21+
22+
var fileContent strings.Builder
23+
fileContent.WriteString(content + "\n")
24+
for fileContent.Len() < detectSampleSize+100 {
25+
fileContent.WriteString("This is a filler line to make the file large enough.\n")
26+
}
27+
28+
finalBytes := []byte(fileContent.String())
29+
30+
if useGzip {
31+
gz := gzip.NewWriter(f)
32+
if _, err := gz.Write(finalBytes); err != nil {
33+
t.Fatalf("Failed to write gzipped content: %v", err)
34+
}
35+
gz.Close()
36+
} else {
37+
if _, err := f.Write(finalBytes); err != nil {
38+
t.Fatalf("Failed to write plain content: %v", err)
39+
}
40+
}
41+
f.Close()
42+
return path
43+
}
44+
45+
func TestNewLogSrc(t *testing.T) {
46+
tempDir := t.TempDir()
47+
logContent := "2023-10-28T10:30:00Z This is a test log line."
48+
49+
t.Run("with plain text file", func(t *testing.T) {
50+
path := createTestFile(t, tempDir, "test.log", logContent, false)
51+
52+
src, err := newLogSrc(path)
53+
if err != nil {
54+
t.Fatalf("newLogSrc failed for plain file: %v", err)
55+
}
56+
defer src.Close()
57+
58+
info, _ := os.Stat(path)
59+
if src.Size() != info.Size() {
60+
t.Errorf("Expected size %d, got %d", info.Size(), src.Size())
61+
}
62+
})
63+
64+
t.Run("with gzipped file", func(t *testing.T) {
65+
path := createTestFile(t, tempDir, "test.log.gz", logContent, true)
66+
67+
src, err := newLogSrc(path)
68+
if err != nil {
69+
t.Fatalf("newLogSrc failed for gzipped file: %v", err)
70+
}
71+
defer src.Close()
72+
73+
if src.Size() != -1 {
74+
t.Errorf("Expected size -1 for gzip, got %d", src.Size())
75+
}
76+
})
77+
78+
t.Run("with window option", func(t *testing.T) {
79+
path := createTestFile(t, tempDir, "window.log", logContent, false)
80+
expectedWindow := int64(30)
81+
82+
src, err := newLogSrc(path, WithWindow(expectedWindow))
83+
if err != nil {
84+
t.Fatalf("newLogSrc failed: %v", err)
85+
}
86+
defer src.Close()
87+
88+
if src.Window() != expectedWindow {
89+
t.Errorf("Expected window %d, got %d", expectedWindow, src.Window())
90+
}
91+
})
92+
93+
t.Run("with non-existent file", func(t *testing.T) {
94+
_, err := newLogSrc(filepath.Join(tempDir, "not-real.log"))
95+
if err == nil {
96+
t.Fatal("Expected an error for a non-existent file, but got nil")
97+
}
98+
})
99+
}
100+
101+
func TestResolveSource(t *testing.T) {
102+
tempDir := t.TempDir()
103+
logContent := "2023-10-28T10:40:00Z some log content"
104+
logPath := createTestFile(t, tempDir, "app.log", logContent, false)
105+
106+
t.Run("with valid source", func(t *testing.T) {
107+
dss := &datasrc.DataSources{
108+
Sources: []datasrc.Source{
109+
{
110+
Name: "my-app",
111+
Type: "log",
112+
Locations: []datasrc.Location{{Path: logPath}},
113+
},
114+
},
115+
}
116+
117+
results := Resolve(dss)
118+
if len(results) != 1 {
119+
t.Fatalf("Expected 1 resolved source, got %d", len(results))
120+
}
121+
if results[0].Name() != "my-app" {
122+
t.Errorf("Expected resolved source name to be 'my-app', got '%s'", results[0].Name())
123+
}
124+
})
125+
}
126+
127+
func TestPipeStdin(t *testing.T) {
128+
var b strings.Builder
129+
b.WriteString("2023-10-28T11:00:00Z Piped log content\n")
130+
for b.Len() < detectSampleSize+100 {
131+
b.WriteString("Filler line for stdin test.\n")
132+
}
133+
logContent := b.String()
134+
135+
r, w, err := os.Pipe()
136+
if err != nil {
137+
t.Fatalf("os.Pipe failed: %v", err)
138+
}
139+
140+
originalStdin := os.Stdin
141+
os.Stdin = r
142+
t.Cleanup(func() {
143+
os.Stdin = originalStdin
144+
})
145+
146+
go func() {
147+
defer w.Close()
148+
w.Write([]byte(logContent))
149+
}()
150+
151+
results, err := PipeStdin()
152+
if err != nil {
153+
t.Fatalf("PipeStdin returned an unexpected error: %v", err)
154+
}
155+
156+
if len(results) != 1 {
157+
t.Fatalf("Expected PipeStdin to return 1 LogData source, but got %d", len(results))
158+
}
159+
}

0 commit comments

Comments
 (0)