mirror of
https://github.com/tendermint/tendermint.git
synced 2026-09-03 06:37:14 +00:00
service: remove stop method and use contexts (#7292)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -8,8 +9,11 @@ import (
|
||||
)
|
||||
|
||||
func TestEventCache_Flush(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
err := evsw.Start(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = evsw.AddListenerForEvent("nothingness", "", func(data EventData) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
tmsync "github.com/tendermint/tendermint/internal/libs/sync"
|
||||
@@ -45,6 +46,7 @@ type Fireable interface {
|
||||
type EventSwitch interface {
|
||||
service.Service
|
||||
Fireable
|
||||
Stop() error
|
||||
|
||||
AddListenerForEvent(listenerID, eventValue string, cb EventCallback) error
|
||||
RemoveListenerForEvent(event string, listenerID string)
|
||||
@@ -68,7 +70,7 @@ func NewEventSwitch() EventSwitch {
|
||||
return evsw
|
||||
}
|
||||
|
||||
func (evsw *eventSwitch) OnStart() error {
|
||||
func (evsw *eventSwitch) OnStart(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+80
-118
@@ -1,6 +1,7 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -14,23 +15,20 @@ import (
|
||||
// TestAddListenerForEventFireOnce sets up an EventSwitch, subscribes a single
|
||||
// listener to an event, and sends a string "data".
|
||||
func TestAddListenerForEventFireOnce(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
messages := make(chan EventData)
|
||||
err = evsw.AddListenerForEvent("listener", "event",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event",
|
||||
func(data EventData) {
|
||||
// test there's no deadlock if we remove the listener inside a callback
|
||||
evsw.RemoveListener("listener")
|
||||
messages <- data
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
go evsw.FireEvent("event", "data")
|
||||
received := <-messages
|
||||
if received != "data" {
|
||||
@@ -41,24 +39,21 @@ func TestAddListenerForEventFireOnce(t *testing.T) {
|
||||
// TestAddListenerForEventFireMany sets up an EventSwitch, subscribes a single
|
||||
// listener to an event, and sends a thousand integers.
|
||||
func TestAddListenerForEventFireMany(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
doneSum := make(chan uint64)
|
||||
doneSending := make(chan uint64)
|
||||
numbers := make(chan uint64, 4)
|
||||
// subscribe one listener for one event
|
||||
err = evsw.AddListenerForEvent("listener", "event",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
// collect received events
|
||||
go sumReceivedNumbers(numbers, doneSum)
|
||||
// go fire events
|
||||
@@ -75,14 +70,12 @@ func TestAddListenerForEventFireMany(t *testing.T) {
|
||||
// listener to three different events and sends a thousand integers for each
|
||||
// of the three events.
|
||||
func TestAddListenerForDifferentEvents(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
doneSum := make(chan uint64)
|
||||
doneSending1 := make(chan uint64)
|
||||
@@ -90,21 +83,18 @@ func TestAddListenerForDifferentEvents(t *testing.T) {
|
||||
doneSending3 := make(chan uint64)
|
||||
numbers := make(chan uint64, 4)
|
||||
// subscribe one listener to three events
|
||||
err = evsw.AddListenerForEvent("listener", "event1",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event1",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event2",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener", "event3",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event3",
|
||||
func(data EventData) {
|
||||
numbers <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
// collect received events
|
||||
go sumReceivedNumbers(numbers, doneSum)
|
||||
// go fire events
|
||||
@@ -127,15 +117,13 @@ func TestAddListenerForDifferentEvents(t *testing.T) {
|
||||
// listener to two of those three events, and then sends a thousand integers
|
||||
// for each of the three events.
|
||||
func TestAddDifferentListenerForDifferentEvents(t *testing.T) {
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
evsw := NewEventSwitch()
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
doneSum1 := make(chan uint64)
|
||||
doneSum2 := make(chan uint64)
|
||||
@@ -145,31 +133,26 @@ func TestAddDifferentListenerForDifferentEvents(t *testing.T) {
|
||||
numbers1 := make(chan uint64, 4)
|
||||
numbers2 := make(chan uint64, 4)
|
||||
// subscribe two listener to three events
|
||||
err = evsw.AddListenerForEvent("listener1", "event1",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener1", "event1",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener1", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener1", "event2",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener1", "event3",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener1", "event3",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener2", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener2", "event2",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener2", "event3",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener2", "event3",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
// collect received events for listener1
|
||||
go sumReceivedNumbers(numbers1, doneSum1)
|
||||
// collect received events for listener2
|
||||
@@ -199,14 +182,12 @@ func TestAddAndRemoveListenerConcurrency(t *testing.T) {
|
||||
roundCount = 2000
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
done1 := make(chan struct{})
|
||||
done2 := make(chan struct{})
|
||||
@@ -249,14 +230,12 @@ func TestAddAndRemoveListenerConcurrency(t *testing.T) {
|
||||
// two events, fires a thousand integers for the first event, then unsubscribes
|
||||
// the listener and fires a thousand integers for the second event.
|
||||
func TestAddAndRemoveListener(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
doneSum1 := make(chan uint64)
|
||||
doneSum2 := make(chan uint64)
|
||||
@@ -265,16 +244,14 @@ func TestAddAndRemoveListener(t *testing.T) {
|
||||
numbers1 := make(chan uint64, 4)
|
||||
numbers2 := make(chan uint64, 4)
|
||||
// subscribe two listener to three events
|
||||
err = evsw.AddListenerForEvent("listener", "event1",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event1",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event2",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
// collect received events for event1
|
||||
go sumReceivedNumbers(numbers1, doneSum1)
|
||||
// collect received events for event2
|
||||
@@ -300,29 +277,23 @@ func TestAddAndRemoveListener(t *testing.T) {
|
||||
|
||||
// TestRemoveListener does basic tests on adding and removing
|
||||
func TestRemoveListener(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
count := 10
|
||||
sum1, sum2 := 0, 0
|
||||
// add some listeners and make sure they work
|
||||
err = evsw.AddListenerForEvent("listener", "event1",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event1",
|
||||
func(data EventData) {
|
||||
sum1++
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = evsw.AddListenerForEvent("listener", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener", "event2",
|
||||
func(data EventData) {
|
||||
sum2++
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
|
||||
for i := 0; i < count; i++ {
|
||||
evsw.FireEvent("event1", true)
|
||||
@@ -361,14 +332,11 @@ func TestRemoveListener(t *testing.T) {
|
||||
// NOTE: it is important to run this test with race conditions tracking on,
|
||||
// `go test -race`, to examine for possible race conditions.
|
||||
func TestRemoveListenersAsync(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
evsw := NewEventSwitch()
|
||||
err := evsw.Start()
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
if err := evsw.Stop(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
})
|
||||
require.NoError(t, evsw.Start(ctx))
|
||||
t.Cleanup(evsw.Wait)
|
||||
|
||||
doneSum1 := make(chan uint64)
|
||||
doneSum2 := make(chan uint64)
|
||||
@@ -378,36 +346,30 @@ func TestRemoveListenersAsync(t *testing.T) {
|
||||
numbers1 := make(chan uint64, 4)
|
||||
numbers2 := make(chan uint64, 4)
|
||||
// subscribe two listener to three events
|
||||
err = evsw.AddListenerForEvent("listener1", "event1",
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener1", "event1",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener1", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener1", "event2",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener1", "event3",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener1", "event3",
|
||||
func(data EventData) {
|
||||
numbers1 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener2", "event1",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener2", "event1",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener2", "event2",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener2", "event2",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
err = evsw.AddListenerForEvent("listener2", "event3",
|
||||
}))
|
||||
require.NoError(t, evsw.AddListenerForEvent("listener2", "event3",
|
||||
func(data EventData) {
|
||||
numbers2 <- data.(uint64)
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}))
|
||||
// collect received events for event1
|
||||
go sumReceivedNumbers(numbers1, doneSum1)
|
||||
// collect received events for event2
|
||||
|
||||
@@ -12,8 +12,9 @@ import (
|
||||
)
|
||||
|
||||
func TestExample(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: "example-client",
|
||||
|
||||
@@ -341,7 +341,7 @@ func (s *Server) OnStop() { s.stop() }
|
||||
func (s *Server) Wait() { <-s.exited; s.BaseService.Wait() }
|
||||
|
||||
// OnStart implements Service.OnStart by starting the server.
|
||||
func (s *Server) OnStart() error { s.run(); return nil }
|
||||
func (s *Server) OnStart(ctx context.Context) error { s.run(); return nil }
|
||||
|
||||
// OnReset implements Service.OnReset. It has no effect for this service.
|
||||
func (s *Server) OnReset() error { return nil }
|
||||
|
||||
+58
-34
@@ -7,7 +7,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -20,8 +19,10 @@ const (
|
||||
)
|
||||
|
||||
func TestSubscribeWithArgs(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
t.Run("DefaultLimit", func(t *testing.T) {
|
||||
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
@@ -47,8 +48,10 @@ func TestSubscribeWithArgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestObserver(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
done := make(chan struct{})
|
||||
var got interface{}
|
||||
@@ -65,8 +68,10 @@ func TestObserver(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestObserverErrors(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
require.Error(t, s.Observe(ctx, nil, query.Empty{}))
|
||||
require.NoError(t, s.Observe(ctx, func(pubsub.Message) error { return nil }))
|
||||
@@ -74,8 +79,10 @@ func TestObserverErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPublishDoesNotBlock(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: clientID,
|
||||
@@ -100,8 +107,10 @@ func TestPublishDoesNotBlock(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSubscribeErrors(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
t.Run("EmptyQueryErr", func(t *testing.T) {
|
||||
_, err := s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{ClientID: clientID})
|
||||
@@ -118,8 +127,10 @@ func TestSubscribeErrors(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSlowSubscriber(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: clientID,
|
||||
@@ -137,8 +148,10 @@ func TestSlowSubscriber(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDifferentClients(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
sub1 := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: "client-1",
|
||||
@@ -188,8 +201,10 @@ func TestDifferentClients(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSubscribeDuplicateKeys(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
testCases := []struct {
|
||||
query string
|
||||
@@ -241,8 +256,10 @@ func TestSubscribeDuplicateKeys(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClientSubscribesTwice(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
q := query.MustParse("tm.events.type='NewBlock'")
|
||||
events := []abci.Event{{
|
||||
@@ -274,8 +291,10 @@ func TestClientSubscribesTwice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnsubscribe(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
sub := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: clientID,
|
||||
@@ -296,8 +315,10 @@ func TestUnsubscribe(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestClientUnsubscribesTwice(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: clientID,
|
||||
@@ -315,8 +336,10 @@ func TestClientUnsubscribesTwice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestResubscribe(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
args := pubsub.SubscribeArgs{
|
||||
ClientID: clientID,
|
||||
@@ -336,8 +359,10 @@ func TestResubscribe(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnsubscribeAll(t *testing.T) {
|
||||
s := newTestServer(t)
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
s := newTestServer(ctx, t)
|
||||
|
||||
sub1 := newTestSub(t).must(s.SubscribeWithArgs(ctx, pubsub.SubscribeArgs{
|
||||
ClientID: clientID,
|
||||
@@ -364,28 +389,27 @@ func TestBufferCapacity(t *testing.T) {
|
||||
|
||||
require.Equal(t, 2, s.BufferCapacity())
|
||||
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
require.NoError(t, s.Publish(ctx, "Nighthawk"))
|
||||
require.NoError(t, s.Publish(ctx, "Sage"))
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, 100*time.Millisecond)
|
||||
ctx, cancel = context.WithTimeout(ctx, 100*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
require.ErrorIs(t, s.Publish(ctx, "Ironclad"), context.DeadlineExceeded)
|
||||
}
|
||||
|
||||
func newTestServer(t testing.TB) *pubsub.Server {
|
||||
func newTestServer(ctx context.Context, t testing.TB) *pubsub.Server {
|
||||
t.Helper()
|
||||
|
||||
s := pubsub.NewServer(func(s *pubsub.Server) {
|
||||
s.Logger = log.TestingLogger()
|
||||
})
|
||||
|
||||
require.NoError(t, s.Start())
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, s.Stop())
|
||||
})
|
||||
require.NoError(t, s.Start(ctx))
|
||||
t.Cleanup(s.Wait)
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
+44
-55
@@ -1,8 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
@@ -22,22 +22,10 @@ var (
|
||||
|
||||
// Service defines a service that can be started, stopped, and reset.
|
||||
type Service interface {
|
||||
// Start the service.
|
||||
// If it's already started or stopped, will return an error.
|
||||
// If OnStart() returns an error, it's returned by Start()
|
||||
Start() error
|
||||
OnStart() error
|
||||
|
||||
// Stop the service.
|
||||
// If it's already stopped, will return an error.
|
||||
// OnStop must never error.
|
||||
Stop() error
|
||||
OnStop()
|
||||
|
||||
// Reset the service.
|
||||
// Panics by default - must be overwritten to enable reset.
|
||||
Reset() error
|
||||
OnReset() error
|
||||
// Start is called to start the service, which should run until
|
||||
// the context terminates. If the service is already running, Start
|
||||
// must report an error.
|
||||
Start(context.Context) error
|
||||
|
||||
// Return true if the service is running
|
||||
IsRunning() bool
|
||||
@@ -52,6 +40,18 @@ type Service interface {
|
||||
Wait()
|
||||
}
|
||||
|
||||
// Implementation describes the implementation that the
|
||||
// BaseService implementation wraps.
|
||||
type Implementation interface {
|
||||
Service
|
||||
|
||||
// Called by the Services Start Method
|
||||
OnStart(context.Context) error
|
||||
|
||||
// Called when the service's context is canceled.
|
||||
OnStop()
|
||||
}
|
||||
|
||||
/*
|
||||
Classical-inheritance-style service declarations. Services can be started, then
|
||||
stopped, then optionally restarted.
|
||||
@@ -82,7 +82,7 @@ Typical usage:
|
||||
return fs
|
||||
}
|
||||
|
||||
func (fs *FooService) OnStart() error {
|
||||
func (fs *FooService) OnStart(ctx context.Context) error {
|
||||
fs.BaseService.OnStart() // Always call the overridden method.
|
||||
// initialize private fields
|
||||
// start subroutines, etc.
|
||||
@@ -102,11 +102,11 @@ type BaseService struct {
|
||||
quit chan struct{}
|
||||
|
||||
// The "subclass" of BaseService
|
||||
impl Service
|
||||
impl Implementation
|
||||
}
|
||||
|
||||
// NewBaseService creates a new BaseService.
|
||||
func NewBaseService(logger log.Logger, name string, impl Service) *BaseService {
|
||||
func NewBaseService(logger log.Logger, name string, impl Implementation) *BaseService {
|
||||
if logger == nil {
|
||||
logger = log.NewNopLogger()
|
||||
}
|
||||
@@ -119,10 +119,10 @@ func NewBaseService(logger log.Logger, name string, impl Service) *BaseService {
|
||||
}
|
||||
}
|
||||
|
||||
// Start implements Service by calling OnStart (if defined). An error will be
|
||||
// returned if the service is already running or stopped. Not to start the
|
||||
// stopped service, you need to call Reset.
|
||||
func (bs *BaseService) Start() error {
|
||||
// Start starts the Service and calls its OnStart method. An error will be
|
||||
// returned if the service is already running or stopped. To restart a
|
||||
// stopped service, call Reset.
|
||||
func (bs *BaseService) Start(ctx context.Context) error {
|
||||
if atomic.CompareAndSwapUint32(&bs.started, 0, 1) {
|
||||
if atomic.LoadUint32(&bs.stopped) == 1 {
|
||||
bs.Logger.Error("not starting service; already stopped", "service", bs.name, "impl", bs.impl.String())
|
||||
@@ -132,11 +132,26 @@ func (bs *BaseService) Start() error {
|
||||
|
||||
bs.Logger.Info("starting service", "service", bs.name, "impl", bs.impl.String())
|
||||
|
||||
if err := bs.impl.OnStart(); err != nil {
|
||||
if err := bs.impl.OnStart(ctx); err != nil {
|
||||
// revert flag
|
||||
atomic.StoreUint32(&bs.started, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
go func(ctx context.Context) {
|
||||
<-ctx.Done()
|
||||
if err := bs.Stop(); err != nil {
|
||||
bs.Logger.Error("stopped service",
|
||||
"err", err.Error(),
|
||||
"service", bs.name,
|
||||
"impl", bs.impl.String())
|
||||
}
|
||||
|
||||
bs.Logger.Info("stopped service",
|
||||
"service", bs.name,
|
||||
"impl", bs.impl.String())
|
||||
}(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -147,7 +162,7 @@ func (bs *BaseService) Start() error {
|
||||
// OnStart implements Service by doing nothing.
|
||||
// NOTE: Do not put anything in here,
|
||||
// that way users don't need to call BaseService.OnStart()
|
||||
func (bs *BaseService) OnStart() error { return nil }
|
||||
func (bs *BaseService) OnStart(ctx context.Context) error { return nil }
|
||||
|
||||
// Stop implements Service by calling OnStop (if defined) and closing quit
|
||||
// channel. An error will be returned if the service is already stopped.
|
||||
@@ -175,26 +190,6 @@ func (bs *BaseService) Stop() error {
|
||||
// that way users don't need to call BaseService.OnStop()
|
||||
func (bs *BaseService) OnStop() {}
|
||||
|
||||
// Reset implements Service by calling OnReset callback (if defined). An error
|
||||
// will be returned if the service is running.
|
||||
func (bs *BaseService) Reset() error {
|
||||
if !atomic.CompareAndSwapUint32(&bs.stopped, 1, 0) {
|
||||
bs.Logger.Debug("cannot reset service; not stopped", "service", bs.name, "impl", bs.impl.String())
|
||||
return fmt.Errorf("can't reset running %s", bs.name)
|
||||
}
|
||||
|
||||
// whether or not we've started, we can reset
|
||||
atomic.CompareAndSwapUint32(&bs.started, 1, 0)
|
||||
|
||||
bs.quit = make(chan struct{})
|
||||
return bs.impl.OnReset()
|
||||
}
|
||||
|
||||
// OnReset implements Service by panicking.
|
||||
func (bs *BaseService) OnReset() error {
|
||||
panic("The service cannot be reset")
|
||||
}
|
||||
|
||||
// IsRunning implements Service by returning true or false depending on the
|
||||
// service's state.
|
||||
func (bs *BaseService) IsRunning() bool {
|
||||
@@ -202,16 +197,10 @@ func (bs *BaseService) IsRunning() bool {
|
||||
}
|
||||
|
||||
// Wait blocks until the service is stopped.
|
||||
func (bs *BaseService) Wait() {
|
||||
<-bs.quit
|
||||
}
|
||||
func (bs *BaseService) Wait() { <-bs.quit }
|
||||
|
||||
// String implements Service by returning a string representation of the service.
|
||||
func (bs *BaseService) String() string {
|
||||
return bs.name
|
||||
}
|
||||
func (bs *BaseService) String() string { return bs.name }
|
||||
|
||||
// Quit Implements Service by returning a quit channel.
|
||||
func (bs *BaseService) Quit() <-chan struct{} {
|
||||
return bs.quit
|
||||
}
|
||||
func (bs *BaseService) Quit() <-chan struct{} { return bs.quit }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -16,9 +17,12 @@ func (testService) OnReset() error {
|
||||
}
|
||||
|
||||
func TestBaseServiceWait(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
ts := &testService{}
|
||||
ts.BaseService = *NewBaseService(nil, "TestService", ts)
|
||||
err := ts.Start()
|
||||
err := ts.Start(ctx)
|
||||
require.NoError(t, err)
|
||||
|
||||
waitFinished := make(chan struct{})
|
||||
@@ -36,22 +40,3 @@ func TestBaseServiceWait(t *testing.T) {
|
||||
t.Fatal("expected Wait() to finish within 100 ms.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBaseServiceReset(t *testing.T) {
|
||||
ts := &testService{}
|
||||
ts.BaseService = *NewBaseService(nil, "TestService", ts)
|
||||
err := ts.Start()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ts.Reset()
|
||||
require.Error(t, err, "expected cant reset service error")
|
||||
|
||||
err = ts.Stop()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ts.Reset()
|
||||
require.NoError(t, err)
|
||||
|
||||
err = ts.Start()
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ func SplitAndTrim(s, sep, cutset string) []string {
|
||||
return spl
|
||||
}
|
||||
|
||||
// TrimSpace removes all leading and trailing whitespace from the
|
||||
// string.
|
||||
func TrimSpace(s string) string { return strings.TrimSpace(s) }
|
||||
|
||||
// Returns true if s is a non-empty printable non-tab ascii character.
|
||||
func IsASCIIText(s string) bool {
|
||||
if len(s) == 0 {
|
||||
|
||||
Reference in New Issue
Block a user