diff --git a/charger/ocpp/instance.go b/charger/ocpp/instance.go index 1185988f9..624ad2ad2 100644 --- a/charger/ocpp/instance.go +++ b/charger/ocpp/instance.go @@ -28,9 +28,18 @@ var ( once sync.Once instance *CS port = 8887 + boundPort int externalUrl string ) +// Port returns the TCP port the central system is bound to. With the default +// configuration this equals the configured port; when port 0 is configured +// (as in tests) it is the OS-assigned ephemeral port. It returns 0 while the +// server is not bound. +func Port() int { + return boundPort +} + // GetStatus returns the OCPP runtime status func GetStatus() Status { if instance == nil { @@ -111,6 +120,8 @@ func Instance() *CS { return } } + + boundPort = server.Addr().Port }) return instance diff --git a/charger/ocpp/instance_test.go b/charger/ocpp/instance_test.go index 9f8a62d7d..a476c6db0 100644 --- a/charger/ocpp/instance_test.go +++ b/charger/ocpp/instance_test.go @@ -1,9 +1,18 @@ package ocpp import ( + "os" "testing" ) +func TestMain(m *testing.M) { + // bind the central system to an ephemeral port so this test binary does not + // contend with the charger package test binary for the fixed default port + // when both run in parallel under `go test ./...` + Init(Config{Port: 0}, "") + os.Exit(m.Run()) +} + func TestExternalUrl(t *testing.T) { tests := []struct{ input, expected string }{ {"", ""}, diff --git a/charger/ocpp_test.go b/charger/ocpp_test.go index 55908ee75..64c486689 100644 --- a/charger/ocpp_test.go +++ b/charger/ocpp_test.go @@ -2,6 +2,8 @@ package charger import ( "errors" + "fmt" + "os" "testing" "time" @@ -22,10 +24,20 @@ import ( "github.com/stretchr/testify/suite" ) -const ( - ocppTestUrl = "ws://localhost:8887" - ocppTestConnectTimeout = 10 * time.Second -) +const ocppTestConnectTimeout = 10 * time.Second + +// ocppTestUrl is derived from the actual bound port in SetupSuite: the central +// system binds an ephemeral port to avoid bind failures when the fixed default +// port is already in use on the CI runner. +var ocppTestUrl string + +func TestMain(m *testing.M) { + // bind the OCPP central system to an ephemeral port so this test binary + // does not contend with the charger/ocpp package test binary for the fixed + // default port when both run in parallel under `go test ./...` + ocpp.Init(ocpp.Config{Port: 0}, "") + os.Exit(m.Run()) +} func TestOcpp(t *testing.T) { suite.Run(t, new(ocppTestSuite)) @@ -49,6 +61,9 @@ func (suite *ocppTestSuite) SetupSuite() { suite.logger = &ocppLogger{t: suite.T()} ocppj.SetLogger(suite.logger) + suite.Require().NotZero(ocpp.Port(), "central system did not bind") + ocppTestUrl = fmt.Sprintf("ws://localhost:%d", ocpp.Port()) + suite.clock = clock.NewMock() suite.NotNil(ocpp.Instance()) }