Skip to content

Commit dbb3bb7

Browse files
MSeveyManav-Aggarwaltzdybal
authored
FileLogger for Testing (#1067)
<!-- Please read and fill out this form before submitting your PR. Please make sure you have reviewed our contributors guide before submitting your first PR. --> ## Overview Something I have found incredibly changing when debugging tests is the inability to use the verbose flag for doing some basic println debugging since the stdout is flooding with the logs of the node. To address this, I introduced a filelogger that can be used in testing to put the logs in a temp file and keep the stdout free for debugging. The tempfile can then still be used to investigate the logs if needed. This will also make debugging on github action easier since we can use the verbose flag for helpful errors and download the logfiles if needed. I'm probably missing some updates, but I did these when trying to help debug a test for Manav and so wanted to share. Closes #1079 <!-- Please provide an explanation of the PR, including the appropriate context, background, goal, and rationale. If there is an issue with this information, please provide a tl;dr and link the issue. --> ## Checklist <!-- Please complete the checklist to ensure that the PR is ready to be reviewed. IMPORTANT: PRs should be left in Draft until the below checklist is completed. --> - [ ] New and updated code has appropriate documentation - [ ] New and updated code has new and/or updated testing - [ ] Required CI checks are passing - [ ] Visual proof for any user facing features like CLI or documentation updates - [ ] Linked issues closed with keywords --------- Co-authored-by: Manav Aggarwal <manavaggarwal1234@gmail.com> Co-authored-by: Tomasz Zdybał <tomek@zdybal.lap.pl>
1 parent 06e9b98 commit dbb3bb7

11 files changed

Lines changed: 156 additions & 71 deletions

File tree

.github/workflows/test.yml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,13 @@ jobs:
3232
with:
3333
go-version: ${{ inputs.GO_VERSION }}
3434
- name: Run unit test
35-
run: make test-unit
35+
run: make test
3636
- name: upload coverage report
3737
uses: codecov/codecov-action@v3.1.4
3838
with:
3939
token: ${{ secrets.CODECOV_TOKEN }}
4040
file: ./coverage.txt
4141

42-
unit_race_test:
43-
name: Run Unit Tests with Race Detector
44-
runs-on: ubuntu-latest
45-
steps:
46-
- uses: actions/checkout@v3
47-
- name: set up go
48-
uses: actions/setup-go@v4
49-
with:
50-
go-version: ${{ inputs.GO_VERSION }}
51-
- name: execute test run
52-
run: make test-unit-race
53-
5442
integration_test:
5543
name: Run Integration Tests
5644
runs-on: ubuntu-latest

Makefile

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
DOCKER := $(shell which docker)
22
DOCKER_BUF := $(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace bufbuild/buf
33

4+
# Define pkgs, run, and cover vairables for test so that we can override them in
5+
# the terminal more easily.
6+
pkgs := $(shell go list ./...)
7+
run := .
8+
count := 1
9+
410
## help: Show this help message
511
help: Makefile
612
@echo " Choose a command run in "$(PROJECTNAME)":"
@@ -17,11 +23,19 @@ clean:
1723
cover:
1824
@echo "--> Generating Code Coverage"
1925
@go install github.com/ory/go-acc@latest
20-
@go-acc -o coverage.txt `go list ./...`
26+
@go-acc -o coverage.txt $(pkgs)
2127
.PHONY: cover
2228

29+
## deps: Install dependencies
30+
deps:
31+
@echo "--> Installing dependencies"
32+
@go mod download
33+
@make proto-gen
34+
@go mod tidy
35+
.PHONY: deps
36+
2337
## lint: Run linters golangci-lint and markdownlint.
24-
lint:
38+
lint: vet
2539
@echo "--> Running golangci-lint"
2640
@golangci-lint run
2741
@echo "--> Running markdownlint"
@@ -39,23 +53,17 @@ fmt:
3953
@markdownlint --config .markdownlint.yaml '**/*.md' -f
4054
.PHONY: fmt
4155

42-
## test-unit: Running unit tests
43-
test-unit:
44-
@echo "--> Running unit tests"
45-
@go test -covermode=atomic -coverprofile=coverage.txt `go list ./...`
46-
.PHONY: test-unit
56+
## vet: Run go vet
57+
vet:
58+
@echo "--> Running go vet"
59+
@go vet $(pkgs)
60+
.PHONY: vet
4761

48-
## test-unit-race: Running unit tests with data race detector
49-
test-unit-race:
50-
@echo "--> Running unit tests with data race detector"
51-
@go test -race -count=1 `go list ./...`
52-
.PHONY: test-unit-race
53-
54-
## test-all: Run tests with and without data race
55-
test-all:
56-
@$(MAKE) test-unit
57-
@$(MAKE) test-unit-race
58-
.PHONY: test-all
62+
## test: Running unit tests
63+
test: vet
64+
@echo "--> Running unit tests"
65+
@go test -v -race -covermode=atomic -coverprofile=coverage.txt $(pkgs) -run $(run) -count=$(count)
66+
.PHONY: test
5967

6068
## proto-gen: Generate protobuf files. Requires docker.
6169
proto-gen:

README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,13 +72,7 @@ The Rollkit v0.9.0 release is compatible with [Arabica](https://docs.celestia.or
7272

7373
```sh
7474
# Run unit tests
75-
make test-unit
76-
77-
# Run unit tests with the data race detector
78-
make test-unit-race
79-
80-
# Run tests with and without the data race detector
81-
make test-all
75+
make test
8276

8377
# Generate protobuf files (requires Docker)
8478
make proto-gen

block/manager.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ func (m *Manager) RetrieveLoop(ctx context.Context) {
358358
select {
359359
case <-waitCh:
360360
for {
361+
select {
362+
case <-ctx.Done():
363+
return
364+
default:
365+
}
361366
daHeight := atomic.LoadUint64(&m.daHeight)
362367
m.logger.Debug("retrieve", "daHeight", daHeight)
363368
err := m.processNextDABlock(ctx)
@@ -382,10 +387,7 @@ func (m *Manager) processNextDABlock(ctx context.Context) error {
382387
m.logger.Debug("trying to retrieve block from DA", "daHeight", daHeight)
383388
for r := 0; r < maxRetries; r++ {
384389
blockResp, fetchErr := m.fetchBlock(ctx, daHeight)
385-
if fetchErr != nil {
386-
err = multierr.Append(err, fetchErr)
387-
time.Sleep(100 * time.Millisecond)
388-
} else {
390+
if fetchErr == nil {
389391
if blockResp.Code == da.StatusNotFound {
390392
m.logger.Debug("no block found", "daHeight", daHeight, "reason", blockResp.Message)
391393
return nil
@@ -396,6 +398,15 @@ func (m *Manager) processNextDABlock(ctx context.Context) error {
396398
}
397399
return nil
398400
}
401+
402+
// Track the error
403+
err = multierr.Append(err, fetchErr)
404+
// Delay before retrying
405+
select {
406+
case <-ctx.Done():
407+
return err
408+
case <-time.After(100 * time.Millisecond):
409+
}
399410
}
400411
return err
401412
}

block/manager_test.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/rollkit/rollkit/config"
1616
"github.com/rollkit/rollkit/da"
1717
mockda "github.com/rollkit/rollkit/da/mock"
18+
"github.com/rollkit/rollkit/log/test"
1819
"github.com/rollkit/rollkit/store"
1920
"github.com/rollkit/rollkit/types"
2021
)
@@ -52,15 +53,15 @@ func TestInitialState(t *testing.T) {
5253
expectedChainID string
5354
}{
5455
{
55-
name: "empty store",
56+
name: "empty_store",
5657
store: emptyStore,
5758
genesis: genesis,
5859
expectedInitialHeight: genesis.InitialHeight,
5960
expectedLastBlockHeight: 0,
6061
expectedChainID: genesis.ChainID,
6162
},
6263
{
63-
name: "state in store",
64+
name: "state_in_store",
6465
store: fullStore,
6566
genesis: genesis,
6667
expectedInitialHeight: sampleState.InitialHeight,
@@ -78,7 +79,7 @@ func TestInitialState(t *testing.T) {
7879
for _, c := range cases {
7980
t.Run(c.name, func(t *testing.T) {
8081
assert := assert.New(t)
81-
logger := log.TestingLogger()
82+
logger := test.NewFileLoggerCustom(t, test.TempLogFileName(t, c.name))
8283
dalc := getMockDALC(logger)
8384
defer func() {
8485
require.NoError(t, dalc.Stop())

da/test/da_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func doTestLifecycle(t *testing.T, dalc da.DataAvailabilityLayerClient) {
7777
if _, ok := dalc.(*celestia.DataAvailabilityLayerClient); ok {
7878
conf, _ = json.Marshal(testConfig)
7979
}
80-
err := dalc.Init(testNamespaceID, conf, nil, test.NewLogger(t))
80+
err := dalc.Init(testNamespaceID, conf, nil, test.NewFileLoggerCustom(t, test.TempLogFileName(t, "dalc")))
8181
require.NoError(err)
8282

8383
err = dalc.Start()
@@ -147,7 +147,7 @@ func doTestRetrieve(t *testing.T, dalc da.DataAvailabilityLayerClient) {
147147
conf, _ = json.Marshal(testConfig)
148148
}
149149
kvStore, _ := store.NewDefaultInMemoryKVStore()
150-
err := dalc.Init(testNamespaceID, conf, kvStore, test.NewLogger(t))
150+
err := dalc.Init(testNamespaceID, conf, kvStore, test.NewFileLoggerCustom(t, test.TempLogFileName(t, "dalc")))
151151
require.NoError(err)
152152

153153
err = dalc.Start()

log/test/loggers.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,103 @@ package test
22

33
import (
44
"fmt"
5+
"os"
6+
"strings"
57
"sync"
68
"testing"
9+
10+
"github.com/cometbft/cometbft/libs/log"
711
)
812

913
// TODO(tzdybal): move to some common place
1014

15+
// FileLogger is a simple, thread-safe logger that logs to a tempFile and is
16+
// intended for use in testing.
17+
type FileLogger struct {
18+
kv []interface{}
19+
logFile *os.File
20+
T *testing.T
21+
mtx *sync.Mutex
22+
}
23+
24+
// TempLogFileName returns a filename for a log file that is unique to the test.
25+
func TempLogFileName(t *testing.T, suffix string) string {
26+
return strings.ReplaceAll(t.Name(), "/", "_") + suffix + ".log"
27+
}
28+
29+
// NewLogger create a Logger using the name of the test as the filename.
30+
func NewFileLogger(t *testing.T) *FileLogger {
31+
// Use the test name but strip out any slashes since they are not
32+
// allowed in filenames.
33+
return NewFileLoggerCustom(t, TempLogFileName(t, ""))
34+
}
35+
36+
// NewLoggerCustom create a Logger using the given filename.
37+
func NewFileLoggerCustom(t *testing.T, fileName string) *FileLogger {
38+
logFile, err := os.CreateTemp("", fileName)
39+
if err != nil {
40+
panic(err)
41+
}
42+
t.Log("Test logs can be found:", logFile.Name())
43+
t.Cleanup(func() {
44+
_ = logFile.Close()
45+
})
46+
return &FileLogger{
47+
kv: []interface{}{},
48+
logFile: logFile,
49+
T: t,
50+
mtx: new(sync.Mutex),
51+
}
52+
}
53+
54+
// Debug prints a debug message.
55+
func (f *FileLogger) Debug(msg string, keyvals ...interface{}) {
56+
f.T.Helper()
57+
f.mtx.Lock()
58+
defer f.mtx.Unlock()
59+
kvs := append(f.kv, keyvals...)
60+
_, err := fmt.Fprintln(f.logFile, append([]interface{}{"DEBUG: " + msg}, kvs...)...)
61+
if err != nil {
62+
panic(err)
63+
}
64+
}
65+
66+
// Info prints an info message.
67+
func (f *FileLogger) Info(msg string, keyvals ...interface{}) {
68+
f.T.Helper()
69+
f.mtx.Lock()
70+
defer f.mtx.Unlock()
71+
kvs := append(f.kv, keyvals...)
72+
_, err := fmt.Fprintln(f.logFile, append([]interface{}{"INFO: " + msg}, kvs...)...)
73+
if err != nil {
74+
panic(err)
75+
}
76+
}
77+
78+
// Error prints an error message.
79+
func (f *FileLogger) Error(msg string, keyvals ...interface{}) {
80+
f.T.Helper()
81+
f.mtx.Lock()
82+
defer f.mtx.Unlock()
83+
kvs := append(f.kv, keyvals...)
84+
_, err := fmt.Fprintln(f.logFile, append([]interface{}{"ERROR: " + msg}, kvs...)...)
85+
if err != nil {
86+
panic(err)
87+
}
88+
}
89+
90+
// With returns a new Logger with the given keyvals added.
91+
func (f *FileLogger) With(keyvals ...interface{}) log.Logger {
92+
f.mtx.Lock()
93+
defer f.mtx.Unlock()
94+
return &FileLogger{
95+
kv: append(f.kv, keyvals...),
96+
logFile: f.logFile,
97+
T: f.T,
98+
mtx: new(sync.Mutex),
99+
}
100+
}
101+
11102
// Logger is a simple, yet thread-safe, logger intended for use in unit tests.
12103
type Logger struct {
13104
mtx *sync.Mutex

node/full_node_integration_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/rollkit/rollkit/config"
2626
mockda "github.com/rollkit/rollkit/da/mock"
27+
"github.com/rollkit/rollkit/log/test"
2728
"github.com/rollkit/rollkit/mocks"
2829
"github.com/rollkit/rollkit/p2p"
2930
"github.com/rollkit/rollkit/store"
@@ -444,7 +445,7 @@ func createNodes(aggCtx, ctx context.Context, num int, t *testing.T) ([]*FullNod
444445
apps := make([]*mocks.Application, num)
445446
dalc := &mockda.DataAvailabilityLayerClient{}
446447
ds, _ := store.NewDefaultInMemoryKVStore()
447-
_ = dalc.Init([8]byte{}, nil, ds, log.TestingLogger())
448+
_ = dalc.Init([8]byte{}, nil, ds, test.NewFileLoggerCustom(t, test.TempLogFileName(t, "dalc")))
448449
_ = dalc.Start()
449450
node, app := createNode(aggCtx, 0, true, false, keys, t)
450451
apps[0] = app
@@ -516,7 +517,7 @@ func createNode(ctx context.Context, n int, aggregator bool, isLight bool, keys
516517
signingKey,
517518
proxy.NewLocalClientCreator(app),
518519
genesis,
519-
log.TestingLogger().With("node", n))
520+
test.NewFileLoggerCustom(t, test.TempLogFileName(t, fmt.Sprintf("node%v", n))).With("node", n))
520521
require.NoError(err)
521522
require.NotNil(node)
522523

node/test_helpers.go

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,22 +21,13 @@ type MockTester struct {
2121
t *testing.T
2222
}
2323

24-
func (m MockTester) Fail() {
25-
fmt.Println("Failed")
26-
}
24+
func (m MockTester) Fail() {}
2725

28-
func (m MockTester) FailNow() {
29-
fmt.Println("MockTester FailNow called")
30-
}
26+
func (m MockTester) FailNow() {}
3127

32-
func (m MockTester) Logf(format string, args ...interface{}) {
33-
fmt.Println("MockTester Logf called")
34-
}
28+
func (m MockTester) Logf(format string, args ...interface{}) {}
3529

36-
func (m MockTester) Errorf(format string, args ...interface{}) {
37-
//fmt.Printf(format, args...)
38-
fmt.Println("Errorf called")
39-
}
30+
func (m MockTester) Errorf(format string, args ...interface{}) {}
4031

4132
func waitForFirstBlock(node *FullNode, useBlockExchange bool) error {
4233
return waitForAtLeastNBlocks(node, 1, useBlockExchange)

0 commit comments

Comments
 (0)