Skip to content

Commit 02780df

Browse files
committed
etcd: New function signature updated
Now etcd.New accepts a minimal interface instead of a concrete implementation. This makes it easier to use mocks when etcd.New is called inside some code.
1 parent 9601e22 commit 02780df

3 files changed

Lines changed: 598 additions & 67 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1111

1212
### Changed
1313

14+
- driver.etcd: etcd.New now accepts an interface that is compatible with
15+
`*etcdclientv3.Client` instead of the concrete type, which should not cause
16+
any issues when upgrading the version.
17+
1418
### Fixed
1519

1620
## [v1.1.2] - 2026-03-30

driver/etcd/etcd.go

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ import (
1818
"github.com/tarantool/go-storage/watch"
1919
)
2020

21-
// Client defines the minimal interface needed for etcd operations.
21+
// Client defines the minimal interface needed for etcd operations. It
22+
// is compatible with etcdclientv3.Client.
23+
//
2224
// This allows for easier testing and mock implementations.
2325
type Client interface {
26+
Watcher
27+
2428
// Txn creates a new transaction.
2529
Txn(ctx context.Context) etcd.Txn
2630
}
@@ -34,17 +38,10 @@ type Watcher interface {
3438
Close() error
3539
}
3640

37-
// WatcherFactory creates new watchers from a client.
38-
type WatcherFactory interface {
39-
// NewWatcher creates a new watcher.
40-
NewWatcher(client Client) Watcher
41-
}
42-
4341
// Driver is an etcd implementation of the storage driver interface.
4442
// It uses etcd as the underlying key-value storage backend.
4543
type Driver struct {
4644
client Client // etcd client interface.
47-
watcherFactory WatcherFactory // factory for creating watchers.
4845
}
4946

5047
var (
@@ -59,63 +56,11 @@ var (
5956
errUnsupportedOperationType = errors.New("unsupported operation type")
6057
)
6158

62-
// etcdClientAdapter wraps etcd.Client to implement our Client interface.
63-
type etcdClientAdapter struct {
64-
client *etcd.Client
65-
}
66-
67-
func (a *etcdClientAdapter) Txn(ctx context.Context) etcd.Txn {
68-
return a.client.Txn(ctx)
69-
}
70-
71-
// etcdWatcherAdapter wraps etcd.Watcher to implement our Watcher interface.
72-
type etcdWatcherAdapter struct {
73-
watcher etcd.Watcher
74-
}
75-
76-
func (a *etcdWatcherAdapter) Watch(ctx context.Context, key string, opts ...etcd.OpOption) etcd.WatchChan {
77-
return a.watcher.Watch(ctx, key, opts...)
78-
}
79-
80-
func (a *etcdWatcherAdapter) Close() error {
81-
return fmt.Errorf("failed to close: %w", a.watcher.Close())
82-
}
83-
84-
// etcdWatcherFactory implements WatcherFactory for etcd clients.
85-
type etcdWatcherFactory struct{}
86-
87-
func (f *etcdWatcherFactory) NewWatcher(client Client) Watcher {
88-
// For etcd clients, we need access to the underlying client.
89-
if adapter, ok := client.(*etcdClientAdapter); ok {
90-
return &etcdWatcherAdapter{
91-
watcher: etcd.NewWatcher(adapter.client),
92-
}
93-
}
94-
95-
// For other implementations, return a no-op watcher.
96-
return &noopWatcher{}
97-
}
98-
99-
// noopWatcher is a no-op implementation of Watcher for non-etcd clients.
100-
type noopWatcher struct{}
101-
102-
func (w *noopWatcher) Watch(_ context.Context, _ string, _ ...etcd.OpOption) etcd.WatchChan {
103-
ch := make(chan etcd.WatchResponse)
104-
close(ch)
105-
106-
return ch
107-
}
108-
109-
func (w *noopWatcher) Close() error {
110-
return nil
111-
}
112-
11359
// New creates a new etcd driver instance using an existing etcd client.
11460
// The client should be properly configured and connected to an etcd cluster.
115-
func New(client *etcd.Client) *Driver {
61+
func New(client Client) *Driver {
11662
return &Driver{
117-
client: &etcdClientAdapter{client: client},
118-
watcherFactory: &etcdWatcherFactory{},
63+
client: client,
11964
}
12065
}
12166

@@ -167,14 +112,12 @@ const (
167112
func (d Driver) Watch(ctx context.Context, key []byte, _ ...watch.Option) (<-chan watch.Event, func(), error) {
168113
eventCh := make(chan watch.Event, eventChannelSize)
169114

170-
parentWatcher := d.watcherFactory.NewWatcher(d.client)
171-
172115
var opts []etcd.OpOption
173116
if bytes.HasSuffix(key, []byte("/")) {
174117
opts = append(opts, etcd.WithPrefix())
175118
}
176119

177-
watchChan := parentWatcher.Watch(ctx, string(key), opts...)
120+
watchChan := d.client.Watch(ctx, string(key), opts...)
178121

179122
go func() {
180123
defer close(eventCh)
@@ -206,7 +149,7 @@ func (d Driver) Watch(ctx context.Context, key []byte, _ ...watch.Option) (<-cha
206149
}()
207150

208151
return eventCh, func() {
209-
_ = parentWatcher.Close()
152+
d.client.Close()
210153
}, nil
211154
}
212155

0 commit comments

Comments
 (0)