Commit c6d8eddd authored by Matthew Sykes's avatar Matthew Sykes
Browse files

[FAB-9150] race in TestRegister_ExpiredIdentity



The event server starts a go routine to distribute events to registered
handlers and the expired identity test reaches into the handler to force
the identity associated with the handler to expire in the past. The
current implementation expires the sessions and publishes a block to
trigger the event processing without serialization and this is reported
as a race.

A mutex was added to serialize reads and updates of the expiration time.
Although this is not strictly needed for the production code, it
resolves the race without refactoring to introduce a fake clock or
similar dependency.

Change-Id: I0cefd847a6e564d81099e116d463bf22231b4fc3
Signed-off-by: default avatarMatthew Sykes <sykesmat@us.ibm.com>
parent f48cf5c9
......@@ -10,6 +10,7 @@ import (
"fmt"
"math"
"strconv"
"sync"
"time"
"github.com/golang/protobuf/proto"
......@@ -24,9 +25,10 @@ import (
type handler struct {
ChatStream pb.Events_ChatServer
interestedEvents map[string]*pb.Interest
sessionEndTime time.Time
RemoteAddr string
eventProcessor *eventProcessor
sessionEndLock *sync.Mutex
sessionEndTime time.Time
}
func newHandler(stream pb.Events_ChatServer, ep *eventProcessor) *handler {
......@@ -35,6 +37,7 @@ func newHandler(stream pb.Events_ChatServer, ep *eventProcessor) *handler {
interestedEvents: map[string]*pb.Interest{},
RemoteAddr: util.ExtractRemoteAddress(stream.Context()),
eventProcessor: ep,
sessionEndLock: &sync.Mutex{},
}
logger.Debug("event handler created for", h.RemoteAddr)
return h
......@@ -139,7 +142,16 @@ func (h *handler) sendMessage(msg *pb.Event) error {
return nil
}
func (h *handler) setSessionEndTime(expiry time.Time) {
h.sessionEndLock.Lock()
h.sessionEndTime = expiry
h.sessionEndLock.Unlock()
}
func (h *handler) hasSessionExpired() bool {
h.sessionEndLock.Lock()
defer h.sessionEndLock.Unlock()
now := time.Now()
if !h.sessionEndTime.IsZero() && now.After(h.sessionEndTime) {
err := errors.Errorf("Client identity has expired for %s", h.RemoteAddr)
......@@ -175,7 +187,7 @@ func (h *handler) validateEventMessage(signedEvt *pb.SignedEvent) (*pb.Event, er
if !expirationTime.IsZero() && time.Now().After(expirationTime) {
return nil, fmt.Errorf("identity expired")
}
h.sessionEndTime = expirationTime
h.setSessionEndTime(expirationTime)
if evt.GetTimestamp() != nil {
evtTime := time.Unix(evt.GetTimestamp().Seconds, int64(evt.GetTimestamp().Nanos)).UTC()
......
......@@ -163,7 +163,7 @@ func TestSignedEvent(t *testing.T) {
recvChan := make(chan *streamEvent)
sendChan := make(chan *pb.Event)
stream := &mockEventStream{recvChan: recvChan, sendChan: sendChan}
mockHandler := &handler{ChatStream: stream, eventProcessor: gEventProcessor}
mockHandler := newHandler(stream, gEventProcessor)
backupSerializedIdentity := signerSerialized
signerSerialized = createExpiredIdentity(t)
// get a test event
......@@ -446,7 +446,7 @@ func TestRegister_ExpiredIdentity(t *testing.T) {
handlerList.Lock()
for k := range handlerList.handlers {
// Artificially move the session end time a minute into the past
k.sessionEndTime = time.Now().Add(-1 * time.Minute)
k.setSessionEndTime(time.Now().Add(-1 * time.Minute))
}
handlerList.Unlock()
gEventProcessor.RUnlock()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment