Ensure deterministic execution, for tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
Arve Knudsen 2023-10-20 16:16:10 +02:00
parent 6dcebc9e25
commit efcd876b50
2 changed files with 15 additions and 4 deletions

View file

@ -93,6 +93,11 @@ func (p *postingsForMatcherPromise) result(ctx context.Context) (index.Postings,
case <-ctx.Done(): case <-ctx.Done():
return nil, ctx.Err() return nil, ctx.Err()
case <-p.done: case <-p.done:
// Checking context error is necessary for deterministic tests,
// as channel selection order is random
if ctx.Err() != nil {
return nil, ctx.Err()
}
if p.err != nil { if p.err != nil {
return nil, p.err return nil, p.err
} }
@ -107,12 +112,18 @@ func (c *PostingsForMatchersCache) postingsForMatchersPromise(ix IndexPostingsRe
key := matchersKey(ms) key := matchersKey(ms)
oldPromise, loaded := c.calls.LoadOrStore(key, promise) oldPromise, loaded := c.calls.LoadOrStore(key, promise)
if loaded { if loaded {
promise = oldPromise.(*postingsForMatcherPromise) // promise was not stored, we return a previously stored promise, that's possibly being fulfilled in another goroutine
return promise.result close(promise.done)
return oldPromise.(*postingsForMatcherPromise).result
} }
// promise was stored, close its channel after fulfilment
defer close(promise.done) defer close(promise.done)
// FIXME: do we need to cancel the call to postingsForMatchers if all the callers waiting for the result have cancelled their context? // Don't let context cancellation fail the promise, since it may be used by multiple goroutines, each with
// its own context. Also, keep the call independent of this particular context, since the promise will be reused.
// FIXME: do we need to cancel the call to postingsForMatchers if all the callers waiting for the result have
// cancelled their context?
if postings, err := c.postingsForMatchers(context.Background(), ix, ms...); err != nil { if postings, err := c.postingsForMatchers(context.Background(), ix, ms...); err != nil {
promise.err = err promise.err = err
} else { } else {

View file

@ -352,7 +352,7 @@ func TestPostingsForMatchersCache(t *testing.T) {
ctx1, cancel := context.WithCancel(context.Background()) ctx1, cancel := context.WithCancel(context.Background())
cancel() cancel()
_, err := c.PostingsForMatchers(ctx1, indexForPostingsMock{}, true, matchers...) _, err := c.PostingsForMatchers(ctx1, indexForPostingsMock{}, true, matchers...)
require.Equal(t, context.Canceled, err) require.ErrorIs(t, err, context.Canceled)
ctx2 := context.Background() ctx2 := context.Background()
actualPostings, err := c.PostingsForMatchers(ctx2, indexForPostingsMock{}, true, matchers...) actualPostings, err := c.PostingsForMatchers(ctx2, indexForPostingsMock{}, true, matchers...)