Skip to content

Commit 8b9f85f

Browse files
committed
Add support for disabling automatic message validation
Signed-off-by: Lorenzo <[email protected]>
1 parent 410c8f3 commit 8b9f85f

File tree

6 files changed

+99
-31
lines changed

6 files changed

+99
-31
lines changed

ocppj/central_system_test.go

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,20 @@ func (suite *OcppJTestSuite) TestCentralSystemSendInvalidRequest() {
7878
assert.NotNil(suite.T(), err)
7979
}
8080

81+
func (suite *OcppJTestSuite) TestCentralSystemSendRequestNoValidation() {
82+
mockChargePointId := "1234"
83+
suite.mockServer.On("Start", mock.AnythingOfType("int"), mock.AnythingOfType("string")).Return(nil)
84+
suite.mockServer.On("Write", mockChargePointId, mock.Anything).Return(nil)
85+
suite.centralSystem.Start(8887, "/{ws}")
86+
suite.serverDispatcher.CreateClient(mockChargePointId)
87+
mockRequest := newMockRequest("")
88+
// Temporarily disable message validation
89+
ocppj.SetMessageValidation(false)
90+
defer ocppj.SetMessageValidation(true)
91+
err := suite.centralSystem.SendRequest(mockChargePointId, mockRequest)
92+
assert.Nil(suite.T(), err)
93+
}
94+
8195
func (suite *OcppJTestSuite) TestServerSendInvalidJsonRequest() {
8296
mockChargePointId := "1234"
8397
suite.mockServer.On("Start", mock.AnythingOfType("int"), mock.AnythingOfType("string")).Return(nil)
@@ -161,6 +175,23 @@ func (suite *OcppJTestSuite) TestCentralSystemSendInvalidConfirmation() {
161175
assert.NotNil(t, err)
162176
}
163177

178+
func (suite *OcppJTestSuite) TestCentralSystemSendConfirmationNoValidation() {
179+
t := suite.T()
180+
mockChargePointId := "0101"
181+
mockUniqueId := "6789"
182+
suite.mockServer.On("Start", mock.AnythingOfType("int"), mock.AnythingOfType("string")).Return(nil)
183+
suite.mockServer.On("Write", mock.AnythingOfType("string"), mock.Anything).Return(nil)
184+
suite.centralSystem.Start(8887, "/{ws}")
185+
suite.serverDispatcher.CreateClient(mockChargePointId)
186+
mockConfirmation := newMockConfirmation("")
187+
// Temporarily disable message validation
188+
ocppj.SetMessageValidation(false)
189+
defer ocppj.SetMessageValidation(true)
190+
// This is allowed. Endpoint doesn't keep track of incoming requests, but only outgoing ones
191+
err := suite.centralSystem.SendResponse(mockChargePointId, mockUniqueId, mockConfirmation)
192+
assert.Nil(t, err)
193+
}
194+
164195
func (suite *OcppJTestSuite) TestCentralSystemSendConfirmationFailed() {
165196
t := suite.T()
166197
mockChargePointId := "0101"
@@ -535,7 +566,8 @@ func (suite *OcppJTestSuite) TestServerRequestFlow() {
535566
require.Nil(t, err)
536567
} else {
537568
// Send CallError
538-
res := suite.centralSystem.CreateCallError(call.GetUniqueId(), ocppj.GenericError, fmt.Sprintf("error-%v", req.MockValue), nil)
569+
res, err := suite.centralSystem.CreateCallError(call.GetUniqueId(), ocppj.GenericError, fmt.Sprintf("error-%v", req.MockValue), nil)
570+
require.Nil(t, err)
539571
data, err = res.MarshalJSON()
540572
require.Nil(t, err)
541573
}

ocppj/charge_point_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,18 @@ func (suite *OcppJTestSuite) TestChargePointSendInvalidRequest() {
8787
assert.NotNil(suite.T(), err)
8888
}
8989

90+
func (suite *OcppJTestSuite) TestChargePointSendRequestNoValidation() {
91+
suite.mockClient.On("Write", mock.Anything).Return(nil)
92+
suite.mockClient.On("Start", mock.AnythingOfType("string")).Return(nil)
93+
_ = suite.chargePoint.Start("someUrl")
94+
mockRequest := newMockRequest("")
95+
// Temporarily disable message validation
96+
ocppj.SetMessageValidation(false)
97+
defer ocppj.SetMessageValidation(true)
98+
err := suite.chargePoint.SendRequest(mockRequest)
99+
assert.Nil(suite.T(), err)
100+
}
101+
90102
func (suite *OcppJTestSuite) TestChargePointSendInvalidJsonRequest() {
91103
suite.mockClient.On("Write", mock.Anything).Return(nil)
92104
suite.mockClient.On("Start", mock.AnythingOfType("string")).Return(nil)
@@ -146,6 +158,20 @@ func (suite *OcppJTestSuite) TestChargePointSendConfirmation() {
146158
assert.Nil(t, err)
147159
}
148160

161+
func (suite *OcppJTestSuite) TestChargePointSendConfirmationNoValidation() {
162+
mockUniqueId := "6789"
163+
suite.mockClient.On("Write", mock.Anything).Return(nil)
164+
suite.mockClient.On("Start", mock.AnythingOfType("string")).Return(nil)
165+
_ = suite.chargePoint.Start("someUrl")
166+
mockConfirmation := newMockConfirmation("")
167+
// Temporarily disable message validation
168+
ocppj.SetMessageValidation(false)
169+
defer ocppj.SetMessageValidation(true)
170+
// This is allowed. Endpoint doesn't keep track of incoming requests, but only outgoing ones
171+
err := suite.chargePoint.SendResponse(mockUniqueId, mockConfirmation)
172+
assert.Nil(suite.T(), err)
173+
}
174+
149175
func (suite *OcppJTestSuite) TestChargePointSendInvalidConfirmation() {
150176
t := suite.T()
151177
mockUniqueId := "6789"
@@ -419,7 +445,8 @@ func (suite *OcppJTestSuite) TestClientRequestFlow() {
419445
require.Nil(t, err)
420446
} else {
421447
// Send CallError
422-
res := suite.chargePoint.CreateCallError(call.GetUniqueId(), ocppj.GenericError, fmt.Sprintf("error-%v", req.MockValue), nil)
448+
res, err := suite.chargePoint.CreateCallError(call.GetUniqueId(), ocppj.GenericError, fmt.Sprintf("error-%v", req.MockValue), nil)
449+
require.Nil(t, err)
423450
data, err = res.MarshalJSON()
424451
require.Nil(t, err)
425452
}

ocppj/client.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,6 @@ func (c *Client) SendRequest(request ocpp.Request) error {
129129
if !c.dispatcher.IsRunning() {
130130
return fmt.Errorf("ocppj client is not started, couldn't send request")
131131
}
132-
err := Validate.Struct(request)
133-
if err != nil {
134-
return err
135-
}
136132
call, err := c.CreateCall(request)
137133
if err != nil {
138134
return err
@@ -161,10 +157,6 @@ func (c *Client) SendRequest(request ocpp.Request) error {
161157
//
162158
// - a network error occurred
163159
func (c *Client) SendResponse(requestId string, response ocpp.Response) error {
164-
err := Validate.Struct(response)
165-
if err != nil {
166-
return err
167-
}
168160
callResult, err := c.CreateCallResult(response, requestId)
169161
if err != nil {
170162
return err
@@ -190,8 +182,7 @@ func (c *Client) SendResponse(requestId string, response ocpp.Response) error {
190182
//
191183
// - a network error occurred
192184
func (c *Client) SendError(requestId string, errorCode ocpp.ErrorCode, description string, details interface{}) error {
193-
callError := c.CreateCallError(requestId, errorCode, description, details)
194-
err := Validate.Struct(callError)
185+
callError, err := c.CreateCallError(requestId, errorCode, description, details)
195186
if err != nil {
196187
return err
197188
}

ocppj/ocppj.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@ import (
1717
// The validator, used for validating incoming/outgoing OCPP messages.
1818
var Validate = validator.New()
1919

20+
// The internal validation settings. Enabled by default.
21+
var validationEnabled bool
22+
2023
// The internal verbose logger
2124
var log logging.Logger
2225

2326
func init() {
2427
_ = Validate.RegisterValidation("errorCode", IsErrorCodeValid)
2528
log = &logging.VoidLogger{}
29+
validationEnabled = true
2630
}
2731

2832
// Sets a custom Logger implementation, allowing the ocpp-j package to log events.
@@ -36,6 +40,18 @@ func SetLogger(logger logging.Logger) {
3640
log = logger
3741
}
3842

43+
// Allows to enable/disable automatic validation for OCPP messages
44+
// (this includes the field constraints defined for every request/response).
45+
// The feature may be useful when working with OCPP implementations that don't fully comply to the specs.
46+
//
47+
// Validation is enabled by default.
48+
//
49+
// ⚠️ Use at your own risk! When disabled, outgoing and incoming OCPP messages will not be validated anymore,
50+
// potentially leading to errors.
51+
func SetMessageValidation(enabled bool) {
52+
validationEnabled = enabled
53+
}
54+
3955
// MessageType identifies the type of message exchanged between two OCPP endpoints.
4056
type MessageType int
4157

@@ -445,9 +461,11 @@ func (endpoint *Endpoint) CreateCall(request ocpp.Request) (*Call, error) {
445461
Action: action,
446462
Payload: request,
447463
}
448-
err := Validate.Struct(call)
449-
if err != nil {
450-
return nil, err
464+
if validationEnabled {
465+
err := Validate.Struct(call)
466+
if err != nil {
467+
return nil, err
468+
}
451469
}
452470
return &call, nil
453471
}
@@ -466,21 +484,29 @@ func (endpoint *Endpoint) CreateCallResult(confirmation ocpp.Response, uniqueId
466484
UniqueId: uniqueId,
467485
Payload: confirmation,
468486
}
469-
err := Validate.Struct(callResult)
470-
if err != nil {
471-
return nil, err
487+
if validationEnabled {
488+
err := Validate.Struct(callResult)
489+
if err != nil {
490+
return nil, err
491+
}
472492
}
473493
return &callResult, nil
474494
}
475495

476496
// Creates a CallError message, given the message's unique ID and the error.
477-
func (endpoint *Endpoint) CreateCallError(uniqueId string, code ocpp.ErrorCode, description string, details interface{}) *CallError {
497+
func (endpoint *Endpoint) CreateCallError(uniqueId string, code ocpp.ErrorCode, description string, details interface{}) (*CallError, error) {
478498
callError := CallError{
479499
MessageTypeId: CALL_ERROR,
480500
UniqueId: uniqueId,
481501
ErrorCode: code,
482502
ErrorDescription: description,
483503
ErrorDetails: details,
484504
}
485-
return &callError
505+
if validationEnabled {
506+
err := Validate.Struct(callError)
507+
if err != nil {
508+
return nil, err
509+
}
510+
}
511+
return &callError, nil
486512
}

ocppj/ocppj_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,8 @@ func (suite *OcppJTestSuite) TestCreateCallError() {
492492
DetailString string
493493
}
494494
mockDetails := MockDetails{DetailString: mockDetailString}
495-
callError := suite.chargePoint.CreateCallError(mockUniqueId, ocppj.GenericError, mockDescription, mockDetails)
495+
callError, err := suite.chargePoint.CreateCallError(mockUniqueId, ocppj.GenericError, mockDescription, mockDetails)
496+
assert.Nil(t, err)
496497
assert.NotNil(t, callError)
497498
CheckCallError(t, callError, mockUniqueId, ocppj.GenericError, mockDescription, mockDetails)
498499
}

ocppj/server.go

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,6 @@ func (s *Server) SendRequest(clientID string, request ocpp.Request) error {
129129
if !s.dispatcher.IsRunning() {
130130
return fmt.Errorf("ocppj server is not started, couldn't send request")
131131
}
132-
err := Validate.Struct(request)
133-
if err != nil {
134-
return err
135-
}
136132
call, err := s.CreateCall(request.(ocpp.Request))
137133
if err != nil {
138134
return err
@@ -161,10 +157,6 @@ func (s *Server) SendRequest(clientID string, request ocpp.Request) error {
161157
//
162158
// - a network error occurred
163159
func (s *Server) SendResponse(clientID string, requestId string, response ocpp.Response) error {
164-
err := Validate.Struct(response)
165-
if err != nil {
166-
return err
167-
}
168160
callResult, err := s.CreateCallResult(response, requestId)
169161
if err != nil {
170162
return err
@@ -190,8 +182,7 @@ func (s *Server) SendResponse(clientID string, requestId string, response ocpp.R
190182
//
191183
// - a network error occurred
192184
func (s *Server) SendError(clientID string, requestId string, errorCode ocpp.ErrorCode, description string, details interface{}) error {
193-
callError := s.CreateCallError(requestId, errorCode, description, details)
194-
err := Validate.Struct(callError)
185+
callError, err := s.CreateCallError(requestId, errorCode, description, details)
195186
if err != nil {
196187
return err
197188
}

0 commit comments

Comments
 (0)