Skip to content

Commit

Permalink
Added security extension tests and mocks
Browse files Browse the repository at this point in the history
  • Loading branch information
xBlaz3kx committed Nov 10, 2024
1 parent b4dec4e commit ed47ce6
Show file tree
Hide file tree
Showing 36 changed files with 5,706 additions and 108 deletions.
139 changes: 139 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
with-expecter: true
dir: "{{.InterfaceDir}}/mocks"
outpkg: mocks
filename: "mock_{{.InterfaceName}}.go"
mockname: "Mock{{.InterfaceName}}"
all: true

packages:
github.com/lorenzodonini/ocpp-go/ocpp1.6/core:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_core_{{.InterfaceName|snakecase}}.go"
mockname: "MockCore{{.InterfaceName}}"
interfaces:
CentralSystemHandler:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/certificates:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_certificates_{{.InterfaceName|snakecase}}.go"
mockname: "MockCertificates{{.InterfaceName}}"

interfaces:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/logging:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_logging_{{.InterfaceName|snakecase}}.go"
mockname: "MockLog{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/extendedtriggermessage:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_extended_trigger_message_{{.InterfaceName|snakecase}}.go"
mockname: "MockExtendedTriggerMessage{{.InterfaceName}}"

interfaces:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/firmware:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_firmware_{{.InterfaceName|snakecase}}.go"
mockname: "MockFirmware{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/localauth:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_local_auth_list_{{.InterfaceName|snakecase}}.go"
mockname: "MockLocalAuthList{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:


github.com/lorenzodonini/ocpp-go/ocpp1.6/remotetrigger:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_remote_trigger_{{.InterfaceName|snakecase}}.go"
mockname: "MockRemoteTrigger{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/reservation:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_reservation_{{.InterfaceName|snakecase}}.go"
mockname: "MockReservation{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:

github.com/lorenzodonini/ocpp-go/ocpp1.6/securefirmware:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_secure_firmware_{{.InterfaceName}}.go"
mockname: "MockSecureFirmware{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:


github.com/lorenzodonini/ocpp-go/ocpp1.6/security:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_security_{{.InterfaceName|snakecase}}.go"
mockname: "MockSecurity{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:


github.com/lorenzodonini/ocpp-go/ocpp1.6/smartcharging:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_smart_charging_{{.InterfaceName|snakecase}}.go"
mockname: "MockSmartCharging{{.InterfaceName}}"

interfaces:
CentralSystemHandler:
ChargePointHandler:


github.com/lorenzodonini/ocpp-go/ocpp1.6:
config:
dir: "ocpp1.6_test/mocks"
filename: "mock_ocpp16.go"

interfaces:
ChargePointConnection:
ChargePoint:
CentralSystem:

github.com/lorenzodonini/ocpp-go/ocppj:
interfaces:
ServerQueueMap:
RequestQueue:

github.com/lorenzodonini/ocpp-go/ws:
interfaces:
WsClient:
WsServer:
Channel:
2 changes: 1 addition & 1 deletion ocpp1.6/securefirmware/signed_update_firmware.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func isValidUpdateFirmwareStatus(fl validator.FieldLevel) bool {
}
}

// The field definition of the LogStatusNotification request payload sent by a Charging Station to the CSMS.
// The field definition of the SignedUpdateFirmwareRequest request payload sent by a Charging Station to the CSMS.
type SignedUpdateFirmwareRequest struct {
Retries *int `json:"retries,omitempty" validate:"omitempty,gte=0"` // This specifies how many times Charging Station must try to download the firmware before giving up. If this field is not present, it is left to Charging Station to decide how many times it wants to retry.
RetryInterval *int `json:"retryInterval,omitempty" validate:"omitempty,gte=0"` // The interval in seconds after which a retry may be attempted. If this field is not present, it is left to Charging Station to decide how long to wait between attempts.
Expand Down
84 changes: 84 additions & 0 deletions ocpp1.6_test/certificate_signed_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package ocpp16_test

import (
"fmt"

"github.com/lorenzodonini/ocpp-go/ocpp1.6/security"
"github.com/lorenzodonini/ocpp-go/ocpp1.6_test/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

func (suite *OcppV16TestSuite) TestCertificateSignedRequestValidation() {
t := suite.T()
var testTable = []GenericTestEntry{
{security.CertificateSignedRequest{CertificateChain: "sampleCert"}, true},
{security.CertificateSignedRequest{CertificateChain: ""}, false},
{security.CertificateSignedRequest{}, false},
{security.CertificateSignedRequest{CertificateChain: newLongString(100001)}, false},
}
ExecuteGenericTestTable(t, testTable)
}

func (suite *OcppV16TestSuite) TestCertificateSignedConfirmationValidation() {
t := suite.T()
var testTable = []GenericTestEntry{
{security.CertificateSignedResponse{Status: security.CertificateSignedStatusAccepted}, true},
{security.CertificateSignedResponse{Status: security.CertificateSignedStatusAccepted}, true},
{security.CertificateSignedResponse{Status: security.CertificateSignedStatusRejected}, true},
{security.CertificateSignedResponse{Status: "invalidCertificateSignedStatus"}, false},
{security.CertificateSignedResponse{}, false},
}
ExecuteGenericTestTable(t, testTable)
}

// Test
func (suite *OcppV16TestSuite) TestCertificateSignedE2EMocked() {
t := suite.T()
wsId := "test_id"
messageId := defaultMessageId
wsUrl := "someUrl"
certificateChain := "someX509CertificateChain"
status := security.CertificateSignedStatusAccepted
requestJson := fmt.Sprintf(`[2,"%v","%v",{"certificateChain":"%v"}]`, messageId, security.CertificateSignedFeatureName, certificateChain)
responseJson := fmt.Sprintf(`[3,"%v",{"status":"%v"}]`, messageId, status)
certificateSignedConfirmation := security.NewCertificateSignedResponse(status)
channel := NewMockWebSocket(wsId)

// Setting handlers
handler := mocks.NewMockSecurityChargePointHandler(t)
handler.EXPECT().OnCertificateSigned(mock.Anything).RunAndReturn(func(request *security.CertificateSignedRequest) (*security.CertificateSignedResponse, error) {
assert.Equal(t, certificateChain, request.CertificateChain)
return certificateSignedConfirmation, nil
})

setupDefaultCentralSystemHandlers(suite, nil, expectedCentralSystemOptions{clientId: wsId, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true})
setupDefaultChargePointHandlers(suite, nil, expectedChargePointOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true})

// Run Test
suite.centralSystem.Start(8887, "somePath")
suite.chargePoint.SetSecurityHandler(handler)
err := suite.chargePoint.Start(wsUrl)
require.Nil(t, err)
resultChannel := make(chan bool, 1)
err = suite.centralSystem.CertificateSigned(wsId, func(confirmation *security.CertificateSignedResponse, err error) {
require.Nil(t, err)
require.NotNil(t, confirmation)
assert.Equal(t, status, confirmation.Status)
resultChannel <- true
}, certificateChain, func(request *security.CertificateSignedRequest) {
request.CertificateChain = certificateChain
})
require.Nil(t, err)
result := <-resultChannel
assert.True(t, result)
}

func (suite *OcppV16TestSuite) TestCertificateSignedInvalidEndpoint() {
messageId := defaultMessageId
certificateChain := "someX509CertificateChain"
certificateSignedRequest := security.NewCertificateSignedRequest(certificateChain)
requestJson := fmt.Sprintf(`[2,"%v","%v",{"certificateChain":"%v"}]`, messageId, security.CertificateSignedFeatureName, certificateChain)
testUnsupportedRequestFromChargePoint(suite, certificateSignedRequest, requestJson, messageId)
}
88 changes: 88 additions & 0 deletions ocpp1.6_test/delete_certificate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package ocpp16_test

import (
"fmt"

"github.com/lorenzodonini/ocpp-go/ocpp1.6/certificates"
"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
"github.com/lorenzodonini/ocpp-go/ocpp1.6_test/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)

// Test
func (suite *OcppV16TestSuite) TestDeleteCertificateRequestValidation() {
t := suite.T()
var requestTable = []GenericTestEntry{
{certificates.DeleteCertificateRequest{CertificateHashData: types.CertificateHashData{HashAlgorithm: types.SHA256, IssuerNameHash: "hash00", IssuerKeyHash: "hash01", SerialNumber: "serial0"}}, true},
{certificates.DeleteCertificateRequest{}, false},
{certificates.DeleteCertificateRequest{CertificateHashData: types.CertificateHashData{HashAlgorithm: "invalidHashAlgorithm", IssuerNameHash: "hash00", IssuerKeyHash: "hash01", SerialNumber: "serial0"}}, false},
}
ExecuteGenericTestTable(t, requestTable)
}

func (suite *OcppV16TestSuite) TestDeleteCertificateConfirmationValidation() {
t := suite.T()
var confirmationTable = []GenericTestEntry{
{certificates.DeleteCertificateResponse{Status: certificates.DeleteCertificateStatusAccepted}, true},
{certificates.DeleteCertificateResponse{Status: certificates.DeleteCertificateStatusFailed}, true},
{certificates.DeleteCertificateResponse{Status: certificates.DeleteCertificateStatusNotFound}, true},
{certificates.DeleteCertificateResponse{Status: "invalidDeleteCertificateStatus"}, false},
{certificates.DeleteCertificateResponse{}, false},
}
ExecuteGenericTestTable(t, confirmationTable)
}

func (suite *OcppV16TestSuite) TestDeleteCertificateE2EMocked() {
t := suite.T()
wsId := "test_id"
messageId := defaultMessageId
wsUrl := "someUrl"
certificateHashData := types.CertificateHashData{HashAlgorithm: types.SHA256, IssuerNameHash: "hash00", IssuerKeyHash: "hash01", SerialNumber: "serial0"}
status := certificates.DeleteCertificateStatusAccepted
requestJson := fmt.Sprintf(`[2,"%v","%v",{"certificateHashData":{"hashAlgorithm":"%v","issuerNameHash":"%v","issuerKeyHash":"%v","serialNumber":"%v"}}]`,
messageId, certificates.DeleteCertificateFeatureName, certificateHashData.HashAlgorithm, certificateHashData.IssuerNameHash, certificateHashData.IssuerKeyHash, certificateHashData.SerialNumber)
responseJson := fmt.Sprintf(`[3,"%v",{"status":"%v"}]`, messageId, status)
deleteCertificateConfirmation := certificates.NewDeleteCertificateResponse(status)
channel := NewMockWebSocket(wsId)

handler := mocks.NewMockCertificatesChargePointHandler(t)
handler.EXPECT().OnDeleteCertificate(mock.Anything).RunAndReturn(func(request *certificates.DeleteCertificateRequest) (*certificates.DeleteCertificateResponse, error) {
assert.Equal(t, certificateHashData.HashAlgorithm, request.CertificateHashData.HashAlgorithm)
assert.Equal(t, certificateHashData.IssuerNameHash, request.CertificateHashData.IssuerNameHash)
assert.Equal(t, certificateHashData.IssuerKeyHash, request.CertificateHashData.IssuerKeyHash)
assert.Equal(t, certificateHashData.SerialNumber, request.CertificateHashData.SerialNumber)
return deleteCertificateConfirmation, nil
})

setupDefaultCentralSystemHandlers(suite, nil, expectedCentralSystemOptions{clientId: wsId, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true})
setupDefaultChargePointHandlers(suite, nil, expectedChargePointOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true})
suite.chargePoint.SetCertificateHandler(handler)

// Run Test
suite.centralSystem.Start(8887, "somePath")
err := suite.chargePoint.Start(wsUrl)
require.Nil(t, err)

resultChannel := make(chan bool, 1)
err = suite.centralSystem.DeleteCertificate(wsId, func(confirmation *certificates.DeleteCertificateResponse, err error) {
require.Nil(t, err)
require.NotNil(t, confirmation)
assert.Equal(t, status, confirmation.Status)
resultChannel <- true
}, certificateHashData)
require.Nil(t, err)

result := <-resultChannel
assert.True(t, result)
}

func (suite *OcppV16TestSuite) TestDeleteCertificateInvalidEndpoint() {
messageId := defaultMessageId
certificateHashData := types.CertificateHashData{HashAlgorithm: types.SHA256, IssuerNameHash: "hash00", IssuerKeyHash: "hash01", SerialNumber: "serial0"}
deleteCertificateRequest := certificates.NewDeleteCertificateRequest(certificateHashData)
requestJson := fmt.Sprintf(`[2,"%v","%v",{"certificateHashData":{"hashAlgorithm":"%v","issuerNameHash":"%v","issuerKeyHash":"%v","serialNumber":"%v"}}]`,
messageId, certificates.DeleteCertificateFeatureName, certificateHashData.HashAlgorithm, certificateHashData.IssuerNameHash, certificateHashData.IssuerKeyHash, certificateHashData.SerialNumber)
testUnsupportedRequestFromChargePoint(suite, deleteCertificateRequest, requestJson, messageId)
}
Loading

0 comments on commit ed47ce6

Please sign in to comment.