Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
31 changes: 31 additions & 0 deletions rueidiscompatmock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,35 @@ p := rdb.Pipeline()
p.Get(ctx, "k1")
p.Set(ctx, "k2", "v2", 0)
p.Exec(ctx)
```

### Client-side caching example

Cached commands (`Cache(ttl)`) use the same `Expect*` calls as non-cached
commands, but expectation matching is origin-aware: a call made through
`Cache(ttl)` only matches an expectation marked `ViaCache()`, and a plain call
only matches an expectation without it. The TTL argument itself is not
matched against expectations.

```golang
compatmock.ExpectGet("key").ViaCache().SetVal("val")

cached := rdb.Cache(100 * time.Millisecond)
cached.Get(context.Background(), "key") // matches

rdb.Get(context.Background(), "key") // would NOT match the ViaCache() expectation
```

The reverse also holds: an expectation without `ViaCache()` only matches a
plain call and will not be satisfied by a call routed through `Cache(ttl)`.
`ExpectationsWereMet()` reports an unmatched expectation when the two origins
are mixed.

```golang
compatmock.ExpectGet("key").SetVal("val")

rdb.Get(context.Background(), "key") // matches

cached := rdb.Cache(100 * time.Millisecond)
cached.Get(context.Background(), "key") // would NOT match the plain expectation
```
48 changes: 29 additions & 19 deletions rueidiscompatmock/adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -369,16 +369,17 @@ type clientMock struct {
}

type expectation struct {
matcher gomock.Matcher
expected []string
result rueidis.RedisResult
rawResult any
err error
resultSet bool
rawSet bool
redisNil bool
regexpMatch bool
customMatch CustomMatch
matcher gomock.Matcher
expected []string
result rueidis.RedisResult
rawResult any
err error
resultSet bool
rawSet bool
redisNil bool
regexpMatch bool
customMatch CustomMatch
requireCache bool
}

type resolvedExpectation struct {
Expand Down Expand Up @@ -553,23 +554,29 @@ func (m *clientMock) wire() {
m.raw.EXPECT().
Do(gomock.Any(), gomock.Any()).
DoAndReturn(func(_ context.Context, cmd rueidis.Completed) rueidis.RedisResult {
return m.consume(1, []rueidis.Completed{cmd})[0]
return m.consume(1, []rueidis.Completed{cmd}, false)[0]
}).
AnyTimes()
m.raw.EXPECT().
DoMulti(gomock.Any(), gomock.Any()).
DoAndReturn(func(_ context.Context, cmds ...rueidis.Completed) []rueidis.RedisResult {
return m.consume(len(cmds), cmds)
return m.consume(len(cmds), cmds, false)
}).
AnyTimes()
m.raw.EXPECT().
DoCache(gomock.Any(), gomock.Any(), gomock.Any()).
DoAndReturn(func(_ context.Context, cmd rueidis.Cacheable, _ time.Duration) rueidis.RedisResult {
return m.consume(1, []rueidis.Completed{rueidis.Completed(cmd)}, true)[0]
}).
AnyTimes()
}

func (m *clientMock) consume(n int, cmds []rueidis.Completed) []rueidis.RedisResult {
func (m *clientMock) consume(n int, cmds []rueidis.Completed, viaCache bool) []rueidis.RedisResult {
m.mu.Lock()
defer m.mu.Unlock()
out := make([]rueidis.RedisResult, n)
for i, cmd := range cmds {
idx, ok := m.matchLocked(cmd)
idx, ok := m.matchLocked(cmd, viaCache)
if !ok {
err := fmt.Errorf("rueidiscompatmock: no expectation for command %v", cmd.Commands())
Comment thread
SomSamantray marked this conversation as resolved.
Outdated
m.unmatched = append(m.unmatched, err)
Expand All @@ -588,7 +595,7 @@ func (m *clientMock) consume(n int, cmds []rueidis.Completed) []rueidis.RedisRes
func (m *clientMock) consumeWithRaw(cmd rueidis.Completed) resolvedExpectation {
m.mu.Lock()
defer m.mu.Unlock()
idx, ok := m.matchLocked(cmd)
idx, ok := m.matchLocked(cmd, false)
if !ok {
err := fmt.Errorf("rueidiscompatmock: no expectation for command %v", cmd.Commands())
m.unmatched = append(m.unmatched, err)
Expand All @@ -604,25 +611,28 @@ func (m *clientMock) consumeWithRaw(cmd rueidis.Completed) resolvedExpectation {
return resolved
}

func (m *clientMock) matchLocked(cmd rueidis.Completed) (int, bool) {
func (m *clientMock) matchLocked(cmd rueidis.Completed, viaCache bool) (int, bool) {
if m.ordered {
if len(m.queue) == 0 {
return 0, false
}
if !m.queue[0].matches(cmd) {
if !m.queue[0].matches(cmd, viaCache) {
return 0, false
}
return 0, true
}
for i, e := range m.queue {
if e.matches(cmd) {
if e.matches(cmd, viaCache) {
return i, true
}
}
return 0, false
}

func (e *expectation) matches(cmd rueidis.Completed) bool {
func (e *expectation) matches(cmd rueidis.Completed, viaCache bool) bool {
if e.requireCache != viaCache {
return false
}
Comment thread
cursor[bot] marked this conversation as resolved.
if e.customMatch == nil && !e.regexpMatch {
return e.matcher.Matches(cmd)
}
Expand Down
Loading
Loading