Skip to content

Commit 5d297d0

Browse files
test(backend, logger): complete test of errors and remove pull record
1 parent 95e850b commit 5d297d0

2 files changed

Lines changed: 271 additions & 24 deletions

File tree

backend/pkg/logger/logger.go

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,12 @@ type Logger struct {
2626
trace zerolog.Logger
2727
}
2828

29+
/**************
30+
* HandlerLogger *
31+
***************/
2932
var _ abstraction.Logger = &Logger{}
3033

34+
// Used on subloggers to get the current timestamp for folder or file names
3135
var Timestamp = time.Now()
3236

3337
func (Logger) HandlerName() string { return HandlerName }
@@ -68,7 +72,12 @@ func (logger *Logger) Start() error {
6872
for name, sublogger := range logger.subloggers {
6973
err := sublogger.Start()
7074
if err != nil {
71-
logger.trace.Error().Stack().Err(err).Str("subLogger", string(name)).Msg("start sublogger")
75+
logger.trace.
76+
Error().
77+
Stack().
78+
Err(err).
79+
Str("subLogger", string(name)).
80+
Msg("start sublogger")
7281
return err
7382
}
7483
}
@@ -79,25 +88,44 @@ func (logger *Logger) Start() error {
7988

8089
// PushRecord works as a proxy for the PushRecord method of the subloggers
8190
func (logger *Logger) PushRecord(record abstraction.LoggerRecord) error {
91+
8292
logger.trace.Trace().Type("record", record).Msg("push")
8393
sublogger, ok := logger.subloggers[record.Name()]
8494
if !ok {
85-
logger.trace.Warn().Type("record", record).Str("name", string(record.Name())).Msg("no sublogger found for record")
95+
logger.trace.
96+
Warn().
97+
Type("record", record).
98+
Str("name", string(record.Name())).
99+
Msg("no sublogger found for record")
100+
86101
return ErrLoggerNotFound{record.Name()}
87102
}
88103

89104
return sublogger.PushRecord(record)
90105
}
91106

92-
// PullRecord works as a proxy for the PullRecord method of the subloggers
107+
// ! This method should not be used because any of the subloggers has PullRecord implemented
108+
// // PullRecord works as a proxy for the PullRecord method of the subloggers
93109
func (logger *Logger) PullRecord(request abstraction.LoggerRequest) (abstraction.LoggerRecord, error) {
94-
logger.trace.Trace().Type("request", request).Msg("request")
95-
loggerChecked, ok := logger.subloggers[request.Name()]
96-
if !ok {
97-
logger.trace.Warn().Type("request", request).Str("name", string(request.Name())).Msg("no subloggger found for request")
98-
return nil, ErrLoggerNotFound{request.Name()}
99-
}
100-
return loggerChecked.PullRecord(request)
110+
111+
panic("PullRecord")
112+
113+
// logger.trace.
114+
// Trace().
115+
// Type("request", request).
116+
// Msg("request")
117+
118+
// loggerChecked, ok := logger.subloggers[request.Name()]
119+
// if !ok {
120+
// logger.trace.
121+
// Warn().
122+
// Type("request", request).
123+
// Str("name", string(request.Name())).
124+
// Msg("no subloggger found for request")
125+
126+
// return nil, ErrLoggerNotFound{request.Name()}
127+
// }
128+
// return loggerChecked.PullRecord(request)
101129
}
102130

103131
func (logger *Logger) Stop() error {

backend/pkg/logger/logger_test.go

Lines changed: 233 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,258 @@
11
package logger_test
22

33
import (
4+
"bufio"
5+
"path/filepath"
6+
"strings"
47
"testing"
8+
"time"
59

610
"os"
711

812
"github.com/HyperloopUPV-H8/h9-backend/pkg/abstraction"
913
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger"
1014
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger/data"
1115
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger/order"
12-
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger/protection"
13-
"github.com/HyperloopUPV-H8/h9-backend/pkg/logger/state"
1416
"github.com/rs/zerolog"
17+
18+
dataPacketer "github.com/HyperloopUPV-H8/h9-backend/pkg/transport/packet/data"
1519
)
1620

21+
func generatLoggerGroup() *logger.Logger {
22+
23+
return logger.NewLogger(
24+
map[abstraction.LoggerName]abstraction.Logger{
25+
data.Name: data.NewLogger(),
26+
order.Name: order.NewLogger(),
27+
},
28+
29+
zerolog.
30+
New(os.Stdout).
31+
With().
32+
Timestamp().
33+
Logger())
34+
}
35+
36+
/**
37+
*
38+
**/
39+
40+
// mockSublogger minimally implements abstraction.Logger for testing error propagation.
41+
type mockSublogger struct {
42+
startErr error
43+
}
44+
45+
func (m *mockSublogger) Start() error {
46+
return m.startErr
47+
}
48+
func (m *mockSublogger) Stop() error {
49+
return nil
50+
}
51+
func (m *mockSublogger) PushRecord(_ abstraction.LoggerRecord) error {
52+
return nil
53+
}
54+
func (m *mockSublogger) PullRecord(_ abstraction.LoggerRequest) (abstraction.LoggerRecord, error) {
55+
return nil, nil
56+
}
57+
func (m *mockSublogger) HandlerName() string { return "mock" }
58+
59+
// mockRecord minimally implements Name() required by logger's PushRecord.
60+
type mockRecord struct {
61+
n abstraction.LoggerName
62+
}
63+
64+
func (r *mockRecord) Name() abstraction.LoggerName { return r.n }
65+
1766
func TestCreateLoggerGroup(t *testing.T) {
1867

1968
// logger handler
2069
var loggerHandler *logger.Logger
2170

2271
// Generate logger group
2372
t.Run("Create logger group", func(t *testing.T) {
24-
protectionSublogger := protection.NewLogger(map[abstraction.BoardId]string{
25-
0: "test",
26-
})
27-
loggerHandler = logger.NewLogger(map[abstraction.LoggerName]abstraction.Logger{
28-
data.Name: data.NewLogger(),
29-
order.Name: order.NewLogger(),
30-
protection.Name: protectionSublogger,
31-
state.Name: state.NewLogger(),
32-
}, zerolog.New(os.Stdout).With().Timestamp().Logger())
33-
34-
if err := loggerHandler.Start(); err != nil {
35-
t.Error(err)
73+
74+
loggerHandler = generatLoggerGroup()
75+
76+
if loggerHandler == nil {
77+
t.Errorf("Failed to create logger group")
3678
}
79+
3780
})
3881

82+
t.Run(" Check Name", func(t *testing.T) {
83+
84+
if loggerHandler.HandlerName() != "logger" {
85+
t.Errorf("Logger HandlerName() incorrect, got: %s, want: %s", loggerHandler.HandlerName(), "logger")
86+
}
87+
})
88+
89+
}
90+
91+
func TestLoggerGroup_Errors(t *testing.T) {
92+
// Logger with empty map → PushRecord should return error (no sublogger)
93+
lEmpty := logger.NewLogger(map[abstraction.LoggerName]abstraction.Logger{}, zerolog.New(os.Stdout))
94+
err := lEmpty.PushRecord(&mockRecord{n: abstraction.LoggerName("missing")})
95+
if err == nil {
96+
t.Fatalf("expected error when PushRecord to non-existent sublogger, got nil")
97+
}
98+
99+
// Logger whose sublogger returns error on Start → Start should propagate the error
100+
wantErr := os.ErrPermission
101+
badMap := map[abstraction.LoggerName]abstraction.Logger{
102+
abstraction.LoggerName("bad"): &mockSublogger{startErr: wantErr},
103+
}
104+
lBad := logger.NewLogger(badMap, zerolog.New(os.Stdout))
105+
if err := lBad.Start(); err != wantErr {
106+
t.Fatalf("Start did not propagate the expected error. Got: %v, Want: %v", err, wantErr)
107+
}
108+
}
109+
110+
func TestStartAndStopLoggerGroup(t *testing.T) {
111+
112+
// logger handler
113+
loggerHandler := generatLoggerGroup()
114+
115+
t.Run("Start logger group", func(t *testing.T) {
116+
err := loggerHandler.Start()
117+
if err != nil {
118+
t.Errorf("Failed to start logger group: %s", err)
119+
}
120+
})
121+
122+
// previous line
123+
124+
var previousLine string
125+
126+
// Try to write a log to check if the logger is running
127+
128+
t.Run("Push Record to logger group", func(t *testing.T) {
129+
130+
// Data
131+
dataPacket := dataPacketer.NewPacketWithValues(
132+
0,
133+
map[dataPacketer.ValueName]dataPacketer.Value{
134+
"test": dataPacketer.NewBooleanValue(true),
135+
},
136+
map[dataPacketer.ValueName]bool{
137+
"test": true,
138+
})
139+
dataPacketTime := time.Now()
140+
dataRecord := &data.Record{
141+
Packet: dataPacket,
142+
From: "test",
143+
To: "test",
144+
Timestamp: dataPacketTime,
145+
}
146+
loggerHandler.PushRecord(dataRecord)
147+
148+
// Read file to ensure it was successfully written
149+
150+
filePath := filepath.Join("logger", logger.Timestamp.Format(logger.TimestampFormat), "data", "TEST", "test.csv")
151+
152+
time.Sleep(2 * time.Second) // small wait to stabilize
153+
154+
_, err := os.Stat(filePath)
155+
if os.IsNotExist(err) {
156+
t.Errorf("Failed to write log to file: %s", err)
157+
}
158+
159+
// Look last line of the file
160+
file, err := os.Open(filePath)
161+
if err != nil {
162+
t.Errorf("Failed to open log file: %s", err)
163+
}
164+
defer file.Close()
165+
166+
var lastLine string
167+
scanner := bufio.NewScanner(file)
168+
for scanner.Scan() {
169+
lastLine = scanner.Text()
170+
}
171+
172+
line := strings.TrimSpace(string(lastLine))
173+
if line == "" {
174+
t.Fatalf("file %s is empty", filePath)
175+
}
176+
177+
// split the line by commas
178+
fields := strings.Split(line, ",")
179+
if len(fields) < 3 {
180+
t.Fatalf("CSV line has fewer than 3 fields: %s", line)
181+
}
182+
183+
// check content
184+
if fields[1] != "test" {
185+
t.Errorf("Incorrect Packet ID, got: %s, want: %s", fields[1], "test")
186+
}
187+
188+
if fields[2] != "test" {
189+
t.Errorf("Incorrect Packet ID, got: %s, want: %s", fields[2], "test")
190+
}
191+
192+
if fields[3] != "true" {
193+
t.Errorf("Incorrect Packet Value for 'test', got: %s, want: %s", fields[3], "true")
194+
}
195+
196+
previousLine = line
197+
198+
})
199+
200+
t.Run("Stop logger group", func(t *testing.T) {
201+
err := loggerHandler.Stop()
202+
if err != nil {
203+
t.Errorf("Failed to stop logger group: %s", err)
204+
}
205+
})
206+
207+
t.Run("Push Record when stopped", func(t *testing.T) {
208+
209+
// Data
210+
dataPacket := dataPacketer.NewPacketWithValues(
211+
0,
212+
map[dataPacketer.ValueName]dataPacketer.Value{
213+
"test": dataPacketer.NewBooleanValue(true),
214+
},
215+
map[dataPacketer.ValueName]bool{
216+
"test": true,
217+
})
218+
dataPacketTime := time.Now()
219+
dataRecord := &data.Record{
220+
Packet: dataPacket,
221+
From: "test",
222+
To: "test",
223+
Timestamp: dataPacketTime,
224+
}
225+
loggerHandler.PushRecord(dataRecord)
226+
227+
// Read file to ensure it was successfully written
228+
229+
filePath := filepath.Join("logger", logger.Timestamp.Format(logger.TimestampFormat), "data", "TEST", "test.csv")
230+
231+
time.Sleep(2 * time.Second) // small wait to stabilize
232+
233+
_, err := os.Stat(filePath)
234+
if os.IsNotExist(err) {
235+
t.Errorf("Failed to write log to file: %s", err)
236+
}
237+
238+
// Look last line of the file
239+
file, err := os.Open(filePath)
240+
if err != nil {
241+
t.Errorf("Failed to open log file: %s", err)
242+
}
243+
defer file.Close()
244+
245+
var lastLine string
246+
scanner := bufio.NewScanner(file)
247+
for scanner.Scan() {
248+
lastLine = scanner.Text()
249+
}
250+
251+
line := strings.TrimSpace(string(lastLine))
252+
253+
if line != previousLine {
254+
t.Errorf("Logger wrote a log when stopped, got: %s, want: %s", line, previousLine)
255+
}
256+
257+
})
39258
}

0 commit comments

Comments
 (0)