diff --git a/go/internal/ocpp/auth_test.go b/go/internal/ocpp/auth_test.go index cb1f79371..c92c6f8b0 100644 --- a/go/internal/ocpp/auth_test.go +++ b/go/internal/ocpp/auth_test.go @@ -288,7 +288,7 @@ func TestPerChargerCredentialOverTheWire(t *testing.T) { cp := ocpp16.NewChargePoint(id, nil, client) err := cp.Start(fmt.Sprintf("ws://127.0.0.1:%d", port)) if err == nil { - t.Cleanup(cp.Stop) + stopAfterServer(t, srv, cp.Stop) } return err } diff --git a/go/internal/ocpp/charging_needs_test.go b/go/internal/ocpp/charging_needs_test.go index 97d8d4c82..259b2ebab 100644 --- a/go/internal/ocpp/charging_needs_test.go +++ b/go/internal/ocpp/charging_needs_test.go @@ -33,7 +33,7 @@ func connectStationForNeeds(t *testing.T, srv *Server, port int, id string) ocpp t.Fatalf("charging station connect: %v", err) } var once sync.Once - t.Cleanup(func() { once.Do(cs.Stop) }) + stopAfterServer(t, srv, func() { once.Do(cs.Stop) }) if _, err := cs.BootNotification(provisioning.BootReasonPowerUp, "Dawn", "Charge Amps"); err != nil { t.Fatalf("boot: %v", err) diff --git a/go/internal/ocpp/control_test.go b/go/internal/ocpp/control_test.go index 03d746e4f..574a431a3 100644 --- a/go/internal/ocpp/control_test.go +++ b/go/internal/ocpp/control_test.go @@ -114,7 +114,7 @@ func connectCharger(t *testing.T, srv *Server, port int, id string) (ocpp16.Char } var once sync.Once stop := func() { once.Do(cp.Stop) } - t.Cleanup(stop) + stopAfterServer(t, srv, stop) if _, err := cp.BootNotification("Dawn", "Charge Amps"); err != nil { t.Fatalf("boot: %v", err) diff --git a/go/internal/ocpp/control_v201_test.go b/go/internal/ocpp/control_v201_test.go index 1b0887b9f..38d175c61 100644 --- a/go/internal/ocpp/control_v201_test.go +++ b/go/internal/ocpp/control_v201_test.go @@ -121,7 +121,7 @@ func connectStationV201(t *testing.T, srv *Server, port int, id string) (*fakeSt } var once sync.Once stop := func() { once.Do(cs.Stop) } - t.Cleanup(stop) + stopAfterServer(t, srv, stop) station := provisioning.ChargingStationType{Model: "Dawn", VendorName: "Charge Amps"} if _, err := cs.BootNotification(provisioning.BootReasonPowerUp, station.Model, station.VendorName); err != nil { diff --git a/go/internal/ocpp/identity_test.go b/go/internal/ocpp/identity_test.go index d20c459ad..a7fc610d3 100644 --- a/go/internal/ocpp/identity_test.go +++ b/go/internal/ocpp/identity_test.go @@ -121,7 +121,7 @@ func TestBootNotificationTakesEitherSerialField(t *testing.T) { if err := cp.Start(fmt.Sprintf("ws://127.0.0.1:%d", port)); err != nil { t.Fatalf("connect: %v", err) } - t.Cleanup(cp.Stop) + stopAfterServer(t, srv, cp.Stop) if _, err := cp.BootNotification("Halo", "Charge Amps", tc.props...); err != nil { t.Fatalf("boot: %v", err) diff --git a/go/internal/ocpp/server_test.go b/go/internal/ocpp/server_test.go index c5c385ed9..4422b4ee9 100644 --- a/go/internal/ocpp/server_test.go +++ b/go/internal/ocpp/server_test.go @@ -55,6 +55,19 @@ func startServer(t *testing.T, tel *telemetry.Store, approved ...string) (int, * return 0, nil } +// stopAfterServer stops a test charger at cleanup, after the server. Core +// probes each charger it accepts, and ocpp-go v0.19.0's ws.Client.Write checks +// the connection, then sends without its lock: a probe answered while the +// charger closes can send on the closed queue and panic (#1712). Server.Stop +// is idempotent. +func stopAfterServer(t *testing.T, srv *Server, stop func()) { + t.Helper() + t.Cleanup(func() { + srv.Stop() + stop() + }) +} + func TestStopIsConcurrentAndIdempotent(t *testing.T) { _, srv := startServer(t, telemetry.NewStore()) @@ -80,7 +93,7 @@ func TestBootAndMeterValuesPushDerEV(t *testing.T) { if err := cp.Start(url); err != nil { t.Fatalf("client connect: %v", err) } - defer cp.Stop() + stopAfterServer(t, srv, cp.Stop) if _, err := cp.BootNotification("EaseeHome", "Easee"); err != nil { t.Fatalf("boot: %v", err) @@ -149,7 +162,7 @@ func TestStartStopTransactionTracksSession(t *testing.T) { if err := cp.Start(fmt.Sprintf("ws://127.0.0.1:%d", port)); err != nil { t.Fatalf("connect: %v", err) } - defer cp.Stop() + stopAfterServer(t, srv, cp.Stop) if _, err := cp.BootNotification("Home", "Easee"); err != nil { t.Fatalf("boot: %v", err) @@ -200,7 +213,7 @@ func TestPendingChargerIsQuarantinedFromTelemetry(t *testing.T) { if err := cp.Start(fmt.Sprintf("ws://127.0.0.1:%d", port)); err != nil { t.Fatalf("connect: %v", err) } - defer cp.Stop() + stopAfterServer(t, srv, cp.Stop) if _, err := cp.BootNotification("EvilCo", "FakeCharger"); err != nil { t.Fatalf("boot: %v", err)