Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion internal/sharedtest/testclient/fake_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type FakeLDClient struct {
dataSourceStatus *interfaces.DataSourceStatus
initialized bool
lock sync.Mutex
closeOnce sync.Once
}

type CapturedLDClient struct {
Expand Down Expand Up @@ -68,9 +69,13 @@ func (c *FakeLDClient) GetDataStoreStatus() sdks.DataStoreStatusInfo {
return sdks.DataStoreStatusInfo{Available: true}
}

// Close is idempotent, matching the real SDK client: Relay may tear a client down from more than
// one code path, and the second call must not panic.
func (c *FakeLDClient) Close() error {
if c.CloseCh != nil {
close(c.CloseCh)
c.closeOnce.Do(func() {
close(c.CloseCh)
})
}
return nil
}
Expand Down
42 changes: 42 additions & 0 deletions internal/sharedtest/testclient/fake_client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package testclient

import (
"sync"
"testing"

"github.com/launchdarkly/ld-relay/v8/config"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestFakeLDClientCloseIsIdempotent(t *testing.T) {
c := &FakeLDClient{Key: config.SDKKey("key"), CloseCh: make(chan struct{})}

require.NoError(t, c.Close())
require.NoError(t, c.Close())

select {
case <-c.CloseCh:
default:
assert.Fail(t, "CloseCh was not closed")
}
}

func TestFakeLDClientCloseIsSafeForConcurrentCallers(t *testing.T) {
c := &FakeLDClient{Key: config.SDKKey("key"), CloseCh: make(chan struct{})}

var wg sync.WaitGroup
for range 20 {
wg.Go(func() {
assert.NoError(t, c.Close())
})
}
wg.Wait()

select {
case <-c.CloseCh:
default:
assert.Fail(t, "CloseCh was not closed")
}
}