Skip to content

Commit fee0ed5

Browse files
committed
Use dynamic OccurrenceConstraintViolation error for v16 and v2
Signed-off-by: Lorenzo <[email protected]>
1 parent 1884a51 commit fee0ed5

File tree

8 files changed

+52
-34
lines changed

8 files changed

+52
-34
lines changed

ocpp1.6_test/proto_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (suite *OcppV16TestSuite) TestChargePointSendResponseError() {
5151
{
5252
name: "ocurrence validation",
5353
confirmData: CustomData{Field1: "", Field2: 42},
54-
expectedErr: &ocpp.Error{Code: ocppj.OccurrenceConstraintViolation, Description: "Field CallResult.Payload.Data.Field1 required but not found for feature DataTransfer"},
54+
expectedErr: &ocpp.Error{Code: ocppj.OccurrenceConstraintViolationV16, Description: "Field CallResult.Payload.Data.Field1 required but not found for feature DataTransfer"},
5555
},
5656
{
5757
name: "marshaling error",
@@ -130,7 +130,7 @@ func (suite *OcppV16TestSuite) TestCentralSystemSendResponseError() {
130130
require.Error(t, err)
131131
require.IsType(t, &ocpp.Error{}, err)
132132
ocppErr = err.(*ocpp.Error)
133-
assert.Equal(t, ocppj.OccurrenceConstraintViolation, ocppErr.Code)
133+
assert.Equal(t, ocppj.OccurrenceConstraintViolationV16, ocppErr.Code)
134134
assert.Equal(t, "Field CallResult.Payload.Data.Field1 required but not found for feature DataTransfer", ocppErr.Description)
135135
// Test 2: marshaling error
136136
dataTransferConfirmation = core.NewDataTransferConfirmation(core.DataTransferStatusAccepted)
@@ -158,4 +158,5 @@ func (suite *OcppV16TestSuite) TestCentralSystemSendResponseError() {
158158

159159
func (suite *OcppV16TestSuite) TestErrorCodes() {
160160
suite.Equal(ocppj.FormatViolationV16, ocppj.FormatErrorType(suite.ocppjCentralSystem))
161+
suite.Equal(ocppj.OccurrenceConstraintViolationV16, ocppj.OccurrenceConstraintErrorType(suite.ocppjCentralSystem))
161162
}

ocpp2.0.1_test/proto_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (suite *OcppV2TestSuite) TestChargePointSendResponseError() {
5757
result := <-resultChannel
5858
require.IsType(t, &ocpp.Error{}, result)
5959
ocppErr = result.(*ocpp.Error)
60-
assert.Equal(t, ocppj.OccurrenceConstraintViolation, ocppErr.Code)
60+
assert.Equal(t, ocppj.OccurrenceConstraintViolationV2, ocppErr.Code)
6161
assert.Equal(t, "Field CallResult.Payload.Data.Field1 required but not found for feature DataTransfer", ocppErr.Description)
6262
// Test 2: marshaling error
6363
dataTransferResponse = data.NewDataTransferResponse(data.DataTransferStatusAccepted)
@@ -132,7 +132,7 @@ func (suite *OcppV2TestSuite) TestCentralSystemSendResponseError() {
132132
require.Error(t, err)
133133
require.IsType(t, &ocpp.Error{}, err)
134134
ocppErr = err.(*ocpp.Error)
135-
assert.Equal(t, ocppj.OccurrenceConstraintViolation, ocppErr.Code)
135+
assert.Equal(t, ocppj.OccurrenceConstraintViolationV2, ocppErr.Code)
136136
assert.Equal(t, "Field CallResult.Payload.Data.Field1 required but not found for feature DataTransfer", ocppErr.Description)
137137
// Test 2: marshaling error
138138
dataTransferResponse = data.NewDataTransferResponse(data.DataTransferStatusAccepted)
@@ -160,4 +160,5 @@ func (suite *OcppV2TestSuite) TestCentralSystemSendResponseError() {
160160

161161
func (suite *OcppV2TestSuite) TestErrorCodes() {
162162
suite.Equal(ocppj.FormatViolationV2, ocppj.FormatErrorType(suite.ocppjServer))
163+
suite.Equal(ocppj.OccurrenceConstraintViolationV2, ocppj.OccurrenceConstraintErrorType(suite.ocppjServer))
163164
}

ocppj/central_system_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,7 @@ func (suite *OcppJTestSuite) TestCentralSystemHandleFailedResponse() {
332332
require.Nil(t, callResult)
333333
suite.centralSystem.HandleFailedResponseError(mockChargePointID, mockUniqueID, err, mockResponse.GetFeatureName())
334334
rawResponse := <-msgC
335-
expectedErr := fmt.Sprintf(`[4,"%v","%v","Field %s required but not found for feature %s",{}]`, mockUniqueID, ocppj.OccurrenceConstraintViolation, mockField, mockResponse.GetFeatureName())
335+
expectedErr := fmt.Sprintf(`[4,"%v","%v","Field %s required but not found for feature %s",{}]`, mockUniqueID, ocppj.OccurrenceConstraintErrorType(suite.centralSystem), mockField, mockResponse.GetFeatureName())
336336
assert.Equal(t, expectedErr, string(rawResponse))
337337
// 2. property constraint validation error
338338
val := "len4"

ocppj/charge_point_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ func (suite *OcppJTestSuite) TestChargePointHandleFailedResponse() {
306306
require.Nil(t, callResult)
307307
suite.chargePoint.HandleFailedResponseError(mockUniqueID, err, mockResponse.GetFeatureName())
308308
rawResponse := <-msgC
309-
expectedErr := fmt.Sprintf(`[4,"%v","%v","Field %s required but not found for feature %s",{}]`, mockUniqueID, ocppj.OccurrenceConstraintViolation, mockField, mockResponse.GetFeatureName())
309+
expectedErr := fmt.Sprintf(`[4,"%v","%v","Field %s required but not found for feature %s",{}]`, mockUniqueID, ocppj.OccurrenceConstraintErrorType(suite.chargePoint), mockField, mockResponse.GetFeatureName())
310310
assert.Equal(t, expectedErr, string(rawResponse))
311311
// 2. property constraint validation error
312312
val := "len4"

ocppj/client.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ocppj
22

33
import (
4+
"errors"
45
"fmt"
56

67
"gopkg.in/go-playground/validator.v9"
@@ -331,11 +332,12 @@ func (c *Client) HandleFailedResponseError(requestID string, err error, featureN
331332
switch err.(type) {
332333
case validator.ValidationErrors:
333334
// Validation error
334-
validationErr := err.(validator.ValidationErrors)
335-
responseErr = errorFromValidation(validationErr, requestID, featureName)
335+
var validationErr validator.ValidationErrors
336+
errors.As(err, &validationErr)
337+
responseErr = errorFromValidation(c, validationErr, requestID, featureName)
336338
case *ocpp.Error:
337339
// Internal OCPP error
338-
responseErr = err.(*ocpp.Error)
340+
errors.As(err, &responseErr)
339341
case error:
340342
// Unknown error
341343
responseErr = ocpp.NewError(GenericError, err.Error(), requestID)

ocppj/ocppj.go

+32-20
Original file line numberDiff line numberDiff line change
@@ -184,18 +184,19 @@ func (callError *CallError) MarshalJSON() ([]byte, error) {
184184
}
185185

186186
const (
187-
NotImplemented ocpp.ErrorCode = "NotImplemented" // Requested Action is not known by receiver.
188-
NotSupported ocpp.ErrorCode = "NotSupported" // Requested Action is recognized but not supported by the receiver.
189-
InternalError ocpp.ErrorCode = "InternalError" // An internal error occurred and the receiver was not able to process the requested Action successfully.
190-
MessageTypeNotSupported ocpp.ErrorCode = "MessageTypeNotSupported" // A message with an Message Type Number received that is not supported by this implementation.
191-
ProtocolError ocpp.ErrorCode = "ProtocolError" // Payload for Action is incomplete.
192-
SecurityError ocpp.ErrorCode = "SecurityError" // During the processing of Action a security issue occurred preventing receiver from completing the Action successfully.
193-
PropertyConstraintViolation ocpp.ErrorCode = "PropertyConstraintViolation" // Payload is syntactically correct but at least one field contains an invalid value.
194-
OccurrenceConstraintViolation ocpp.ErrorCode = "OccurrenceConstraintViolation" // Payload for Action is syntactically correct but at least one of the fields violates occurrence constraints.
195-
TypeConstraintViolation ocpp.ErrorCode = "TypeConstraintViolation" // Payload for Action is syntactically correct but at least one of the fields violates data type constraints (e.g. “somestring”: 12).
196-
GenericError ocpp.ErrorCode = "GenericError" // Any other error not covered by the previous ones.
197-
FormatViolationV2 ocpp.ErrorCode = "FormatViolation" // Payload for Action is syntactically incorrect. This is only valid for OCPP 2.0.1
198-
FormatViolationV16 ocpp.ErrorCode = "FormationViolation" // Payload for Action is syntactically incorrect or not conform the PDU structure for Action. This is only valid for OCPP 1.6
187+
NotImplemented ocpp.ErrorCode = "NotImplemented" // Requested Action is not known by receiver.
188+
NotSupported ocpp.ErrorCode = "NotSupported" // Requested Action is recognized but not supported by the receiver.
189+
InternalError ocpp.ErrorCode = "InternalError" // An internal error occurred and the receiver was not able to process the requested Action successfully.
190+
MessageTypeNotSupported ocpp.ErrorCode = "MessageTypeNotSupported" // A message with a Message Type Number received that is not supported by this implementation.
191+
ProtocolError ocpp.ErrorCode = "ProtocolError" // Payload for Action is incomplete.
192+
SecurityError ocpp.ErrorCode = "SecurityError" // During the processing of Action a security issue occurred preventing receiver from completing the Action successfully.
193+
PropertyConstraintViolation ocpp.ErrorCode = "PropertyConstraintViolation" // Payload is syntactically correct but at least one field contains an invalid value.
194+
OccurrenceConstraintViolationV2 ocpp.ErrorCode = "OccurrenceConstraintViolation" // Payload for Action is syntactically correct but at least one of the fields violates occurrence constraints.
195+
OccurrenceConstraintViolationV16 ocpp.ErrorCode = "OccurenceConstraintViolation" // Payload for Action is syntactically correct but at least one of the fields violates occurrence constraints. Contains a typo in OCPP 1.6
196+
TypeConstraintViolation ocpp.ErrorCode = "TypeConstraintViolation" // Payload for Action is syntactically correct but at least one of the fields violates data type constraints (e.g. “somestring”: 12).
197+
GenericError ocpp.ErrorCode = "GenericError" // Any other error not covered by the previous ones.
198+
FormatViolationV2 ocpp.ErrorCode = "FormatViolation" // Payload for Action is syntactically incorrect. This is only valid for OCPP 2.0.1
199+
FormatViolationV16 ocpp.ErrorCode = "FormationViolation" // Payload for Action is syntactically incorrect or not conform the PDU structure for Action. This is only valid for OCPP 1.6
199200
)
200201

201202
type dialector interface {
@@ -213,10 +214,21 @@ func FormatErrorType(d dialector) ocpp.ErrorCode {
213214
}
214215
}
215216

217+
func OccurrenceConstraintErrorType(d dialector) ocpp.ErrorCode {
218+
switch d.Dialect() {
219+
case ocpp.V16:
220+
return OccurrenceConstraintViolationV16
221+
case ocpp.V2:
222+
return OccurrenceConstraintViolationV2
223+
default:
224+
panic(fmt.Sprintf("invalid dialect: %v", d))
225+
}
226+
}
227+
216228
func IsErrorCodeValid(fl validator.FieldLevel) bool {
217229
code := ocpp.ErrorCode(fl.Field().String())
218230
switch code {
219-
case NotImplemented, NotSupported, InternalError, MessageTypeNotSupported, ProtocolError, SecurityError, FormatViolationV16, FormatViolationV2, PropertyConstraintViolation, OccurrenceConstraintViolation, TypeConstraintViolation, GenericError:
231+
case NotImplemented, NotSupported, InternalError, MessageTypeNotSupported, ProtocolError, SecurityError, FormatViolationV16, FormatViolationV2, PropertyConstraintViolation, OccurrenceConstraintViolationV16, OccurrenceConstraintViolationV2, TypeConstraintViolation, GenericError:
220232
return true
221233
}
222234
return false
@@ -263,12 +275,12 @@ func getValueLength(value interface{}) int {
263275
}
264276
}
265277

266-
func occurenceViolation(fieldError validator.FieldError, messageId, feature string) *ocpp.Error {
278+
func occurrenceViolation(d dialector, fieldError validator.FieldError, messageId, feature string) *ocpp.Error {
267279
description := fmt.Sprintf("Field %s required but not found", fieldError.Namespace())
268280
if feature != "" {
269281
description = fmt.Sprintf("%s for feature %s", description, feature)
270282
}
271-
return ocpp.NewError(OccurrenceConstraintViolation, description, messageId)
283+
return ocpp.NewError(OccurrenceConstraintErrorType(d), description, messageId)
272284
}
273285

274286
func propertyConstraintViolation(fieldError validator.FieldError, details, messageId, feature string) *ocpp.Error {
@@ -283,11 +295,11 @@ func propertyConstraintViolation(fieldError validator.FieldError, details, messa
283295
)
284296
}
285297

286-
func errorFromValidation(validationErrors validator.ValidationErrors, messageId string, feature string) *ocpp.Error {
298+
func errorFromValidation(d dialector, validationErrors validator.ValidationErrors, messageId, feature string) *ocpp.Error {
287299
for _, el := range validationErrors {
288300
switch el.ActualTag() {
289301
case "required":
290-
return occurenceViolation(el, messageId, feature)
302+
return occurrenceViolation(d, el, messageId, feature)
291303
case "max":
292304
return propertyConstraintViolation(el, "maximum", messageId, feature)
293305
case "min":
@@ -440,7 +452,7 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
440452
}
441453
err = Validate.Struct(call)
442454
if err != nil {
443-
return nil, errorFromValidation(err.(validator.ValidationErrors), uniqueId, action)
455+
return nil, errorFromValidation(endpoint, err.(validator.ValidationErrors), uniqueId, action)
444456
}
445457
return &call, nil
446458
} else if typeId == CALL_RESULT {
@@ -461,7 +473,7 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
461473
}
462474
err = Validate.Struct(callResult)
463475
if err != nil {
464-
return nil, errorFromValidation(err.(validator.ValidationErrors), uniqueId, request.GetFeatureName())
476+
return nil, errorFromValidation(endpoint, err.(validator.ValidationErrors), uniqueId, request.GetFeatureName())
465477
}
466478
return &callResult, nil
467479
} else if typeId == CALL_ERROR {
@@ -495,7 +507,7 @@ func (endpoint *Endpoint) ParseMessage(arr []interface{}, pendingRequestState Cl
495507
}
496508
err := Validate.Struct(callError)
497509
if err != nil {
498-
return nil, errorFromValidation(err.(validator.ValidationErrors), uniqueId, "")
510+
return nil, errorFromValidation(endpoint, err.(validator.ValidationErrors), uniqueId, "")
499511
}
500512
return &callError, nil
501513
} else {

ocppj/ocppj_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,7 @@ func (suite *OcppJTestSuite) TestParseMessageInvalidRequest() {
740740
protoErr := err.(*ocpp.Error)
741741
require.NotNil(t, protoErr)
742742
assert.Equal(t, messageId, protoErr.MessageId)
743-
assert.Equal(t, ocppj.OccurrenceConstraintViolation, protoErr.Code)
743+
assert.Equal(t, ocppj.OccurrenceConstraintErrorType(suite.chargePoint), protoErr.Code)
744744
// Test invalid request -> max constraint wrong
745745
mockRequest.MockValue = "somelongvalue"
746746
message, err = suite.chargePoint.ParseMessage(mockMessage, suite.chargePoint.RequestState)
@@ -769,7 +769,7 @@ func (suite *OcppJTestSuite) TestParseMessageInvalidConfirmation() {
769769
protoErr := err.(*ocpp.Error)
770770
require.NotNil(t, protoErr)
771771
assert.Equal(t, messageId, protoErr.MessageId)
772-
assert.Equal(t, ocppj.OccurrenceConstraintViolation, protoErr.Code)
772+
assert.Equal(t, ocppj.OccurrenceConstraintErrorType(suite.chargePoint), protoErr.Code)
773773
// Test invalid request -> max constraint wrong
774774
mockConfirmation.MockValue = "min"
775775
suite.chargePoint.RequestState.AddPendingRequest(messageId, pendingRequest) // Manually add a pending request, so that responses are not rejected

ocppj/server.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ocppj
22

33
import (
4+
"errors"
45
"fmt"
56

67
"gopkg.in/go-playground/validator.v9"
@@ -304,11 +305,12 @@ func (s *Server) HandleFailedResponseError(clientID string, requestID string, er
304305
switch err.(type) {
305306
case validator.ValidationErrors:
306307
// Validation error
307-
validationErr := err.(validator.ValidationErrors)
308-
responseErr = errorFromValidation(validationErr, requestID, featureName)
308+
var validationErr validator.ValidationErrors
309+
errors.As(err, &validationErr)
310+
responseErr = errorFromValidation(s, validationErr, requestID, featureName)
309311
case *ocpp.Error:
310312
// Internal OCPP error
311-
responseErr = err.(*ocpp.Error)
313+
errors.As(err, &responseErr)
312314
case error:
313315
// Unknown error
314316
responseErr = ocpp.NewError(GenericError, err.Error(), requestID)

0 commit comments

Comments
 (0)