diff --git a/app/plugins/contactRetry.go b/app/plugins/contactRetry.go index 7b29b0d..cb36c20 100644 --- a/app/plugins/contactRetry.go +++ b/app/plugins/contactRetry.go @@ -360,6 +360,13 @@ func (cr *contactRetry) addConnection(id string, state connections.ConnectionSta cr.connections.Store(id, p) cr.connCount += 1 return + } else { + // we have rerequested this connnection. Force set the queued parameter to true. + p, _ := cr.connections.Load(id) + if !p.(*contact).queued { + p.(*contact).queued = true + cr.connCount += 1 + } } } diff --git a/app/plugins/contactRetry_test.go b/app/plugins/contactRetry_test.go new file mode 100644 index 0000000..f3c446d --- /dev/null +++ b/app/plugins/contactRetry_test.go @@ -0,0 +1,73 @@ +package plugins + +import ( + "testing" + "time" + + "cwtch.im/cwtch/event" + "cwtch.im/cwtch/protocol/connections" + "git.openprivacy.ca/openprivacy/log" +) + +// TestContactRetryQueue simulates some basic connection queueing +// NOTE: This whole test is a race condition, and does flag go's detector +// We are invasively checking the internal state of the retry plugin and accessing pointers from another +// thread. +// We could build an entire thread safe monitoring functonality, but that would dramatically expand the scope of this test. +func TestContactRetryQueue(t *testing.T) { + log.SetLevel(log.LevelDebug) + bus := event.NewEventManager() + cr := NewConnectionRetry(bus, "").(*contactRetry) + cr.ACNUp = true // fake an ACN connection... + go cr.run() + + t.Logf("contact plugin up and running..sending peer connection...") + // Assert that there is a peer connection identified as "test" + bus.Publish(event.NewEvent(event.QueuePeerRequest, map[event.Field]string{event.RemotePeer: "test", event.LastSeen: "test"})) + + // Wait until the test actually exists, and is queued + // This is the worst part of this test setup. Ideally we would sleep, or some other yielding, but + // go test scheduling doesn't like that and even sleeping long periods won't cause the event thread to make + // progress... + for { + if pinf, exists := cr.connections.Load("test"); exists { + if pinf.(*contact).queued { + break + } + } + } + + pinf, _ := cr.connections.Load("test") + if pinf.(*contact).queued == false { + t.Fatalf("test connection should be queued, actually: %v", pinf.(*contact).queued) + } + + // Asset that "test" is authenticated + cr.handleEvent("test", connections.AUTHENTICATED, peerConn) + + // Assert that "test has a valid state" + pinf, _ = cr.connections.Load("test") + if pinf.(*contact).state != 3 { + t.Fatalf("test connection should be in authenticated after update, actually: %v", pinf.(*contact).state) + } + + // Publish an unrelated event to trigger the Plugin to go through a queuing cycle + // If we didn't do this we would have to wait 30 seconds for a check-in + bus.Publish(event.NewEvent(event.PeerStateChange, map[event.Field]string{event.RemotePeer: "test2", event.ConnectionState: "Disconnected"})) + time.Sleep(time.Second) + if pinf.(*contact).queued != false { + t.Fatalf("test connection should not be queued, actually: %v", pinf.(*contact).queued) + } + + // Publish a new peer request... + bus.Publish(event.NewEvent(event.QueuePeerRequest, map[event.Field]string{event.RemotePeer: "test"})) + time.Sleep(time.Second) // yield for a second so the event can catch up... + + // Peer test should be forced to queue.... + pinf, _ = cr.connections.Load("test") + if pinf.(*contact).queued != true { + t.Fatalf("test connection should be forced to queue after new queue peer request") + } + + cr.Shutdown() +} diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index d1671e5..3cebec5 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -953,14 +953,10 @@ func (cp *cwtchPeer) GetPeerState(handle string) connections.ConnectionState { return connections.DISCONNECTED } -// PeerWithOnion initiates a request to the Protocol Engine to set up Cwtch Session with a given tor v3 onion -// address. +// PeerWithOnion represents a request to connect immediately to a given peer. Instead +// of checking the last seed time, cwtch will treat the current time as the time of last action. func (cp *cwtchPeer) PeerWithOnion(onion string) { - lastSeen := event.CwtchEpoch - ci, err := cp.FetchConversationInfo(onion) - if err == nil { - lastSeen = cp.GetConversationLastSeenTime(ci.ID) - } + lastSeen := time.Now() cp.eventBus.Publish(event.NewEvent(event.QueuePeerRequest, map[event.Field]string{event.RemotePeer: onion, event.LastSeen: lastSeen.Format(time.RFC3339Nano)})) } diff --git a/testing/tests.sh b/testing/tests.sh index bfd80a0..3881ca6 100755 --- a/testing/tests.sh +++ b/testing/tests.sh @@ -3,7 +3,7 @@ set -e pwd GORACE="haltonerror=1" -go test -race ${1} -coverprofile=plugins.cover.out -v ./app/plugins +go test -coverprofile=plugins.cover.out -v ./app/plugins go test -race ${1} -coverprofile=model.cover.out -v ./model go test -race ${1} -coverprofile=event.cover.out -v ./event go test -race ${1} -coverprofile=storage.v1.cover.out -v ./storage/v1