diff --git a/pkg/parser/parser.go b/pkg/parser/parser.go deleted file mode 100644 index de6f5b1..0000000 --- a/pkg/parser/parser.go +++ /dev/null @@ -1,136 +0,0 @@ -package parser - -import ( - "fmt" - - "github.com/spf13/viper" - - "github.com/pkg/errors" - "go.uber.org/zap" - - "github.com/ChargePi/chargeflow/pkg/ocpp" -) - -type Parser struct { - logger *zap.Logger -} - -func NewParser(logger *zap.Logger) *Parser { - return &Parser{ - logger: logger.Named("parser"), - } -} - -func (p *Parser) ParseMessage(data string) (ocpp.Message, *Result, error) { - p.logger.Debug("Parsing message from JSON", zap.String("data", data)) - - result := NewResult() - - message, err := ParseJsonMessage(data) - if err != nil { - result.AddError("cannot parse message") - return nil, result, errors.Wrap(err, "cannot parse message") - } - - p.logger.Debug("Deconstructing the message", zap.Any("message", message)) - - // Validate the message (action, unique ID) - parse, err := p.parse(message, result) - if err != nil { - return nil, result, errors.Wrapf(err, "cannot parse message") - } - - return parse, result, nil -} - -// Parses an OCPP-J message. The function expects an array of elements, as contained in the JSON message. -func (p *Parser) parse(arr []interface{}, result *Result) (ocpp.Message, error) { - // Checking message fields - if len(arr) < 3 { - result.AddError(fmt.Sprintf("Expected at least 3 elements in the message, got %d", len(arr))) - return nil, nil - } - - rawTypeId, ok := arr[0].(float64) - if !ok { - result.AddError("Expected first element to be a number (message type ID)") - } - - typeId := ocpp.MessageType(rawTypeId) - uniqueId, ok := arr[1].(string) - if !ok { - result.AddError("Expected second element to be a string (unique ID)") - } - - switch typeId { - case ocpp.CALL: - p.logger.Debug("Message is of Request type") - - if len(arr) != 4 { - result.AddError(fmt.Sprintf("Expected 4 elements in the message, got %d", len(arr))) - return nil, errors.Errorf("Expected 4 elements in the message, got %d", len(arr)) - } - - action, ok := arr[2].(string) - if !ok { - result.AddError("Expected second element to be a string (action ID)") - return nil, errors.Errorf("Expected second element to be a string (action ID), got %v", arr[2]) - } - - call := ocpp.Call{ - MessageTypeId: ocpp.CALL, - UniqueId: uniqueId, - Action: action, - Payload: arr[3], - } - return &call, nil - case ocpp.CALL_RESULT: - p.logger.Debug("Message is of Response type") - // Temporary workaround: Specify the response type - action := viper.GetString("response-type") - - callResult := ocpp.CallResult{ - MessageTypeId: ocpp.CALL_RESULT, - UniqueId: uniqueId, - Action: action, - Payload: arr[2], - } - return &callResult, nil - case ocpp.CALL_ERROR: - p.logger.Debug("Message is of Error response type") - - if len(arr) < 4 { - result.AddError("Invalid Call Error message. Expected array length >= 4, got " + fmt.Sprintf("%d", len(arr))) - return nil, errors.Errorf("Invalid Call Error message. Expected array length >= 4, got %v", arr[2]) - } - - // todo details validation? - var details interface{} - if len(arr) > 4 { - details = arr[4] - } - - rawErrorCode, ok := arr[2].(string) - if !ok { - result.AddError(fmt.Sprintf("Invalid element %v at 2, expected error code (string)", arr[2])) - } - - errorCode := ocpp.ErrorCode(rawErrorCode) - errorDescription := "" - if v, ok := arr[3].(string); ok { - errorDescription = v - } - callError := ocpp.CallError{ - MessageTypeId: ocpp.CALL_ERROR, - UniqueId: uniqueId, - ErrorCode: errorCode, - ErrorDescription: errorDescription, - ErrorDetails: details, - } - return &callError, nil - default: - p.logger.Error("Unknown message type", zap.String("typeId", fmt.Sprintf("%v", typeId))) - result.AddError("Unknown message type: " + fmt.Sprintf("%v", typeId)) - return nil, errors.Errorf("Unknown message type: %v ", typeId) - } -} diff --git a/pkg/parser/parser_test.go b/pkg/parser/parser_test.go deleted file mode 100644 index dc516e0..0000000 --- a/pkg/parser/parser_test.go +++ /dev/null @@ -1,100 +0,0 @@ -package parser - -import ( - "testing" - - "github.com/pkg/errors" - "go.uber.org/zap" - - "github.com/ChargePi/chargeflow/pkg/ocpp" - - "github.com/stretchr/testify/suite" -) - -type parserTestSuite struct { - suite.Suite -} - -func (s *parserTestSuite) TestParseMessage() { - logger, _ := zap.NewDevelopment() - tests := []struct { - name string - data string - expectedMessage ocpp.Message - expectedResult *Result - expectedError error - }{ - { - name: "Valid Request", - data: `[2,"1234", "BootNotification", {"chargePointVendor": "TestVendor", "chargePointModel": "TestModel"}]`, - expectedMessage: &ocpp.Call{ - MessageTypeId: ocpp.CALL, - UniqueId: "1234", - Payload: map[string]interface{}{"chargePointVendor": "TestVendor", "chargePointModel": "TestModel"}, - Action: "BootNotification", - }, - expectedResult: NewResult(), - expectedError: nil, - }, - { - name: "Valid Response", - data: `[3,"1234", {"status": "Accepted"}]`, - expectedMessage: &ocpp.CallResult{ - MessageTypeId: ocpp.CALL_RESULT, - UniqueId: "1234", - Payload: map[string]interface{}{"status": "Accepted"}, - Action: "", - }, - expectedResult: NewResult(), - expectedError: nil, - }, - { - name: "Valid Error", - data: `[4,"1234", "GenericError", "An error occurred"]`, - expectedMessage: &ocpp.CallError{ - MessageTypeId: ocpp.CALL_ERROR, - UniqueId: "1234", - ErrorCode: "GenericError", - ErrorDescription: "An error occurred", - }, - expectedResult: NewResult(), - expectedError: nil, - }, - { - name: "Invalid Message", - data: `[5,"1234", "InvalidMessage"]`, - expectedMessage: nil, - expectedResult: &Result{ - errors: []string{"Unknown message type: 5"}, - }, - expectedError: errors.New("Unknown message type: 5"), - }, - { - name: "Invalid JSON", - data: `{"invalid": "json"}`, - expectedMessage: nil, - expectedResult: &Result{ - errors: []string{"cannot parse message"}, - }, - expectedError: errors.New("cannot parse message"), - }, - } - - for _, tt := range tests { - s.Run(tt.name, func() { - parser := NewParser(logger) - message, result, err := parser.ParseMessage(tt.data) - if tt.expectedError != nil { - s.ErrorContains(err, tt.expectedError.Error()) - } else { - s.NoError(err) - } - s.Equal(tt.expectedMessage, message) - s.Equal(tt.expectedResult, result) - }) - } -} - -func TestParser(t *testing.T) { - suite.Run(t, new(parserTestSuite)) -}