make tests pass with "go test -count n" with n > 1

by closing initialized resources during tests.
This commit is contained in:
Mechiel Lukkien 2024-06-10 18:18:20 +02:00
parent dde2258f69
commit f56b04805b
No known key found for this signature in database
9 changed files with 50 additions and 40 deletions

View file

@ -48,6 +48,7 @@ func TestCtl(t *testing.T) {
err := queue.Init() err := queue.Init()
tcheck(t, err, "queue init") tcheck(t, err, "queue init")
defer queue.Shutdown()
testctl := func(fn func(clientctl *ctl)) { testctl := func(fn func(clientctl *ctl)) {
t.Helper() t.Helper()
@ -426,10 +427,13 @@ func TestCtl(t *testing.T) {
// "backup", backup account. // "backup", backup account.
err = dmarcdb.Init() err = dmarcdb.Init()
tcheck(t, err, "dmarcdb init") tcheck(t, err, "dmarcdb init")
defer dmarcdb.Close()
err = mtastsdb.Init(false) err = mtastsdb.Init(false)
tcheck(t, err, "mtastsdb init") tcheck(t, err, "mtastsdb init")
defer mtastsdb.Close()
err = tlsrptdb.Init() err = tlsrptdb.Init()
tcheck(t, err, "tlsrptdb init") tcheck(t, err, "tlsrptdb init")
defer tlsrptdb.Close()
testctl(func(ctl *ctl) { testctl(func(ctl *ctl) {
os.RemoveAll("testdata/ctl/data/tmp/backup-data") os.RemoveAll("testdata/ctl/data/tmp/backup-data")
err := os.WriteFile("testdata/ctl/data/receivedid.key", make([]byte, 16), 0600) err := os.WriteFile("testdata/ctl/data/receivedid.key", make([]byte, 16), 0600)

View file

@ -308,7 +308,7 @@ done
- Update features & roadmap in README.md and website. - Update features & roadmap in README.md and website.
- Write release notes, copy from previous. - Write release notes, copy from previous.
- Build and run tests with previous major Go release. - Build and run tests with previous major Go release.
- Run tests, including with race detector, also with TZ= for UTC-behaviour. - Run tests, including with race detector, also with TZ= for UTC-behaviour, and with -count 2.
- Run integration and upgrade tests. - Run integration and upgrade tests.
- Run fuzzing tests for a while. - Run fuzzing tests for a while.
- Deploy to test environment. Test the update instructions. - Deploy to test environment. Test the update instructions.

View file

@ -6,24 +6,17 @@ import (
"net" "net"
"os" "os"
"testing" "testing"
"github.com/prometheus/client_golang/prometheus"
) )
func TestLifecycle(t *testing.T) { func TestLifecycle(t *testing.T) {
Shutdown, ShutdownCancel = context.WithCancel(context.Background()) Shutdown, ShutdownCancel = context.WithCancel(context.Background())
c := &connections{
conns: map[net.Conn]connKind{},
gauges: map[connKind]prometheus.GaugeFunc{},
active: map[connKind]int64{},
}
nc0, nc1 := net.Pipe() nc0, nc1 := net.Pipe()
defer nc0.Close() defer nc0.Close()
defer nc1.Close() defer nc1.Close()
c.Register(nc0, "proto", "listener") Connections.Register(nc0, "proto", "listener")
c.Shutdown() Connections.Shutdown()
done := c.Done() done := Connections.Done()
select { select {
case <-done: case <-done:
t.Fatalf("already done, but still a connection open") t.Fatalf("already done, but still a connection open")
@ -37,7 +30,7 @@ func TestLifecycle(t *testing.T) {
if !errors.Is(err, os.ErrDeadlineExceeded) { if !errors.Is(err, os.ErrDeadlineExceeded) {
t.Fatalf("got %v, expected os.ErrDeadlineExceeded", err) t.Fatalf("got %v, expected os.ErrDeadlineExceeded", err)
} }
c.Unregister(nc0) Connections.Unregister(nc0)
select { select {
case <-done: case <-done:
default: default:

View file

@ -46,6 +46,7 @@ func TestSendReports(t *testing.T) {
err := tlsrptdb.Init() err := tlsrptdb.Init()
tcheckf(t, err, "init database") tcheckf(t, err, "init database")
defer tlsrptdb.Close()
db := tlsrptdb.ResultDB db := tlsrptdb.ResultDB

View file

@ -230,6 +230,7 @@ func TestAccount(t *testing.T) {
err = queue.Init() // For DB. err = queue.Init() // For DB.
tcheck(t, err, "queue init") tcheck(t, err, "queue init")
defer queue.Shutdown()
account, _, _, _ := api.Account(ctx) account, _, _, _ := api.Account(ctx)
@ -250,6 +251,9 @@ func TestAccount(t *testing.T) {
api.AccountSaveFullName(ctx, account.FullName) api.AccountSaveFullName(ctx, account.FullName)
go ImportManage() go ImportManage()
defer func() {
importers.Stop <- struct{}{}
}()
// Import mbox/maildir tgz/zip. // Import mbox/maildir tgz/zip.
testImport := func(filename string, expect int) { testImport := func(filename string, expect int) {

View file

@ -57,11 +57,13 @@ var importers = struct {
Unregister chan *importListener Unregister chan *importListener
Events chan importEvent Events chan importEvent
Abort chan importAbortRequest Abort chan importAbortRequest
Stop chan struct{}
}{ }{
make(chan *importListener, 1), make(chan *importListener, 1),
make(chan *importListener, 1), make(chan *importListener, 1),
make(chan importEvent), make(chan importEvent),
make(chan importAbortRequest), make(chan importAbortRequest),
make(chan struct{}),
} }
// ImportManage should be run as a goroutine, it manages imports of mboxes/maildirs, propagating progress over SSE connections. // ImportManage should be run as a goroutine, it manages imports of mboxes/maildirs, propagating progress over SSE connections.
@ -89,38 +91,38 @@ func ImportManage() {
select { select {
case l := <-importers.Register: case l := <-importers.Register:
// If we have state, send it so the client is up to date. // If we have state, send it so the client is up to date.
if s, ok := imports[l.Token]; ok { s, ok := imports[l.Token]
l.Register <- true l.Register <- ok
s.Listeners[l] = struct{}{} if !ok {
break
}
s.Listeners[l] = struct{}{}
sendEvent := func(kind string, v any) { sendEvent := func(kind string, v any) {
buf, err := json.Marshal(v) buf, err := json.Marshal(v)
if err != nil { if err != nil {
log.Errorx("marshal event", err, slog.String("kind", kind), slog.Any("event", v)) log.Errorx("marshal event", err, slog.String("kind", kind), slog.Any("event", v))
return return
} }
ssemsg := fmt.Sprintf("event: %s\ndata: %s\n\n", kind, buf) ssemsg := fmt.Sprintf("event: %s\ndata: %s\n\n", kind, buf)
select { select {
case l.Events <- importEvent{kind, []byte(ssemsg), nil, nil}: case l.Events <- importEvent{kind, []byte(ssemsg), nil, nil}:
default: default:
log.Debug("dropped initial import event to slow consumer") log.Debug("dropped initial import event to slow consumer")
}
} }
}
for m, c := range s.MailboxCounts { for m, c := range s.MailboxCounts {
sendEvent("count", importCount{m, c}) sendEvent("count", importCount{m, c})
} }
for _, p := range s.Problems { for _, p := range s.Problems {
sendEvent("problem", importProblem{p}) sendEvent("problem", importProblem{p})
} }
if s.Done != nil { if s.Done != nil {
sendEvent("done", importDone{}) sendEvent("done", importDone{})
} else if s.Aborted != nil { } else if s.Aborted != nil {
sendEvent("aborted", importAborted{}) sendEvent("aborted", importAborted{})
}
} else {
l.Register <- false
} }
case l := <-importers.Unregister: case l := <-importers.Unregister:
@ -172,6 +174,9 @@ func ImportManage() {
} }
s.Cancel() s.Cancel()
a.Response <- nil a.Response <- nil
case <-importers.Stop:
return
} }
// Cleanup old state. // Cleanup old state.

View file

@ -220,6 +220,7 @@ func TestAdmin(t *testing.T) {
mox.MustLoadConfig(true, false) mox.MustLoadConfig(true, false)
err := queue.Init() err := queue.Init()
tcheck(t, err, "queue init") tcheck(t, err, "queue init")
defer queue.Shutdown()
api := Admin{} api := Admin{}

View file

@ -65,6 +65,7 @@ func TestServer(t *testing.T) {
defer store.Switchboard()() defer store.Switchboard()()
err := queue.Init() err := queue.Init()
tcheckf(t, err, "queue init") tcheckf(t, err, "queue init")
defer queue.Shutdown()
log := mlog.New("webapisrv", nil) log := mlog.New("webapisrv", nil)
acc, err := store.OpenAccount(log, "mjl") acc, err := store.OpenAccount(log, "mjl")

View file

@ -314,6 +314,7 @@ func TestAPI(t *testing.T) {
queue.Localserve = true // Deliver directly to us instead attempting actual delivery. queue.Localserve = true // Deliver directly to us instead attempting actual delivery.
err = queue.Init() err = queue.Init()
tcheck(t, err, "queue init") tcheck(t, err, "queue init")
defer queue.Shutdown()
api.MessageSubmit(ctx, SubmitMessage{ api.MessageSubmit(ctx, SubmitMessage{
From: "mjl@mox.example", From: "mjl@mox.example",
To: []string{"mjl+to@mox.example", "mjl to2 <mjl+to2@mox.example>"}, To: []string{"mjl+to@mox.example", "mjl to2 <mjl+to2@mox.example>"},