Skip to content

Commit

Permalink
Add test for creating a new request
Browse files Browse the repository at this point in the history
  • Loading branch information
magiconair committed Sep 16, 2019
1 parent 1282fe1 commit 6a8e9fe
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 7 deletions.
22 changes: 15 additions & 7 deletions uasc/secure_channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ type SecureChannel struct {
chunks map[uint32][]*MessageChunk

enc *uapolicy.EncryptionAlgorithm

// time returns the current time. When not set it defaults to time.Now().
time func() time.Time
}

func NewSecureChannel(endpoint string, c *uacp.Conn, cfg *Config) (*SecureChannel, error) {
Expand Down Expand Up @@ -91,10 +94,8 @@ func NewSecureChannel(endpoint string, c *uacp.Conn, cfg *Config) (*SecureChanne
c: c,
cfg: cfg,
reqhdr: &ua.RequestHeader{
AuthenticationToken: ua.NewTwoByteNodeID(0),
Timestamp: time.Now(),
TimeoutHint: uint32(cfg.RequestTimeout / time.Millisecond),
AdditionalHeader: ua.NewExtensionObject(nil),
TimeoutHint: uint32(cfg.RequestTimeout / time.Millisecond),
AdditionalHeader: ua.NewExtensionObject(nil),
},
state: secureChannelCreated,
handler: make(map[uint32]chan Response),
Expand Down Expand Up @@ -214,7 +215,7 @@ func (s *SecureChannel) newRequestMessage(req ua.Request, authToken *ua.NodeID,
s.cfg.RequestID++
s.reqhdr.AuthenticationToken = authToken
s.reqhdr.RequestHandle++
s.reqhdr.Timestamp = time.Now()
s.reqhdr.Timestamp = s.timeNow()
if timeout > 0 && timeout < s.cfg.RequestTimeout {
timeout = s.cfg.RequestTimeout
}
Expand Down Expand Up @@ -673,7 +674,7 @@ func (s *SecureChannel) handleOpenSecureChannelRequest(svc interface{}) error {
}
resp := &ua.OpenSecureChannelResponse{
ResponseHeader: &ua.ResponseHeader{
Timestamp: time.Now(),
Timestamp: s.timeNow(),
RequestHandle: req.RequestHeader.RequestHandle,
ServiceDiagnostics: &ua.DiagnosticInfo{},
StringTable: []string{},
Expand All @@ -683,7 +684,7 @@ func (s *SecureChannel) handleOpenSecureChannelRequest(svc interface{}) error {
SecurityToken: &ua.ChannelSecurityToken{
ChannelID: s.cfg.SecureChannelID,
TokenID: s.cfg.SecurityTokenID,
CreatedAt: time.Now(),
CreatedAt: s.timeNow(),
RevisedLifetime: req.RequestedLifetime,
},
ServerNonce: nonce,
Expand All @@ -708,6 +709,13 @@ func (s *SecureChannel) popHandlerLock(reqid uint32) chan Response {
return ch
}

func (s *SecureChannel) timeNow() time.Time {
if s.time != nil {
return s.time()
}
return time.Now()
}

func mergeChunks(chunks []*MessageChunk) ([]byte, error) {
if len(chunks) == 0 {
return nil, nil
Expand Down
135 changes: 135 additions & 0 deletions uasc/secure_channel_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package uasc

import (
"math"
"testing"
"time"

"github.com/gopcua/opcua/id"
"github.com/gopcua/opcua/ua"

"github.com/pascaldekloe/goe/verify"
)

func TestNewRequestMessage(t *testing.T) {
fixedTime := func() time.Time { return time.Date(2019, 1, 1, 12, 13, 14, 0, time.UTC) }
tests := []struct {
name string
sechan *SecureChannel
req ua.Request
authToken *ua.NodeID
timeout time.Duration
m *Message
}{
{
name: "first-request",
sechan: &SecureChannel{
cfg: &Config{},
reqhdr: &ua.RequestHeader{},
time: fixedTime,
},
req: &ua.ReadRequest{},
m: &Message{
MessageHeader: &MessageHeader{
Header: &Header{
MessageType: MessageTypeMessage,
ChunkType: ChunkTypeFinal,
},
SymmetricSecurityHeader: &SymmetricSecurityHeader{},
SequenceHeader: &SequenceHeader{
SequenceNumber: 1,
RequestID: 1,
},
},
TypeID: ua.NewFourByteExpandedNodeID(0, id.ReadRequest_Encoding_DefaultBinary),
Service: &ua.ReadRequest{
RequestHeader: &ua.RequestHeader{
AuthenticationToken: ua.NewTwoByteNodeID(0),
Timestamp: fixedTime(),
RequestHandle: 1,
},
},
},
},
{
name: "subsequent-request",
sechan: &SecureChannel{
cfg: &Config{
SequenceNumber: 777,
RequestID: 555,
},
reqhdr: &ua.RequestHeader{
RequestHandle: 444,
},
time: fixedTime,
},
req: &ua.ReadRequest{},
m: &Message{
MessageHeader: &MessageHeader{
Header: &Header{
MessageType: MessageTypeMessage,
ChunkType: ChunkTypeFinal,
},
SymmetricSecurityHeader: &SymmetricSecurityHeader{},
SequenceHeader: &SequenceHeader{
SequenceNumber: 778,
RequestID: 556,
},
},
TypeID: ua.NewFourByteExpandedNodeID(0, id.ReadRequest_Encoding_DefaultBinary),
Service: &ua.ReadRequest{
RequestHeader: &ua.RequestHeader{
AuthenticationToken: ua.NewTwoByteNodeID(0),
Timestamp: fixedTime(),
RequestHandle: 445,
},
},
},
},
{
name: "counter-rollover",
sechan: &SecureChannel{
cfg: &Config{
SequenceNumber: math.MaxUint32,
RequestID: math.MaxUint32,
},
reqhdr: &ua.RequestHeader{
RequestHandle: math.MaxUint32,
},
time: fixedTime,
},
req: &ua.ReadRequest{},
m: &Message{
MessageHeader: &MessageHeader{
Header: &Header{
MessageType: MessageTypeMessage,
ChunkType: ChunkTypeFinal,
},
SymmetricSecurityHeader: &SymmetricSecurityHeader{},
SequenceHeader: &SequenceHeader{
SequenceNumber: 0,
RequestID: 0,
},
},
TypeID: ua.NewFourByteExpandedNodeID(0, id.ReadRequest_Encoding_DefaultBinary),
Service: &ua.ReadRequest{
RequestHeader: &ua.RequestHeader{
AuthenticationToken: ua.NewTwoByteNodeID(0),
Timestamp: fixedTime(),
RequestHandle: 0,
},
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
m, err := tt.sechan.newRequestMessage(tt.req, tt.authToken, tt.timeout)
if err != nil {
t.Fatalf("got err %v want nil", err)
}
verify.Values(t, "", m, tt.m)
})
}
}

0 comments on commit 6a8e9fe

Please sign in to comment.