service: remove stop method and use contexts (#7292)

This commit is contained in:
Sam Kleinman
2021-11-18 17:56:21 -05:00
committed by GitHub
parent 1c34d17240
commit 6ab62fe7b6
115 changed files with 3613 additions and 2271 deletions
+5 -1
View File
@@ -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) {
+3 -1
View File
@@ -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
View File
@@ -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
+3 -2
View File
@@ -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",
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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 }
+5 -20
View File
@@ -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)
}
+4
View File
@@ -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 {