From ba58144de14355680ec8347500c70bff33882639 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 24 Aug 2023 20:54:29 +0300 Subject: [PATCH 1/5] [#647] objsvc/search: Remove netmap.Source wrapper Signed-off-by: Evgenii Stratonikov --- pkg/services/object/search/exec.go | 2 +- pkg/services/object/search/search_test.go | 2 +- pkg/services/object/search/service.go | 10 ++++------ pkg/services/object/search/util.go | 9 --------- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/pkg/services/object/search/exec.go b/pkg/services/object/search/exec.go index c1a9a0c1c..f471da20e 100644 --- a/pkg/services/object/search/exec.go +++ b/pkg/services/object/search/exec.go @@ -74,7 +74,7 @@ func (exec *execCtx) initEpoch() bool { return true } - e, err := exec.svc.currentEpochReceiver.currentEpoch() + e, err := exec.svc.currentEpochReceiver.Epoch() switch { default: diff --git a/pkg/services/object/search/search_test.go b/pkg/services/object/search/search_test.go index 1eb32a29a..d8c5ad090 100644 --- a/pkg/services/object/search/search_test.go +++ b/pkg/services/object/search/search_test.go @@ -56,7 +56,7 @@ type simpleIDWriter struct { type testEpochReceiver uint64 -func (e testEpochReceiver) currentEpoch() (uint64, error) { +func (e testEpochReceiver) Epoch() (uint64, error) { return uint64(e), nil } diff --git a/pkg/services/object/search/service.go b/pkg/services/object/search/service.go index 16b82a620..fd3dbb07b 100644 --- a/pkg/services/object/search/service.go +++ b/pkg/services/object/search/service.go @@ -49,7 +49,7 @@ type cfg struct { } currentEpochReceiver interface { - currentEpoch() (uint64, error) + Epoch() (uint64, error) } keyStore *util.KeyStorage @@ -71,11 +71,9 @@ func New(e *engine.StorageEngine, localStorage: &storageEngineWrapper{ storage: e, }, - traverserGenerator: (*traverseGeneratorWrapper)(tg), - currentEpochReceiver: &nmSrcWrapper{ - nmSrc: ns, - }, - keyStore: ks, + traverserGenerator: (*traverseGeneratorWrapper)(tg), + currentEpochReceiver: ns, + keyStore: ks, } for i := range opts { diff --git a/pkg/services/object/search/util.go b/pkg/services/object/search/util.go index b5b351a3b..6ea8e3f14 100644 --- a/pkg/services/object/search/util.go +++ b/pkg/services/object/search/util.go @@ -5,7 +5,6 @@ import ( "sync" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/client" - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/core/netmap" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/util" @@ -36,10 +35,6 @@ type storageEngineWrapper struct { type traverseGeneratorWrapper util.TraverserGenerator -type nmSrcWrapper struct { - nmSrc netmap.Source -} - func newUniqueAddressWriter(w IDListWriter) IDListWriter { return &uniqueIDWriter{ written: make(map[oid.ID]struct{}), @@ -143,7 +138,3 @@ func idsFromAddresses(addrs []oid.Address) []oid.ID { func (e *traverseGeneratorWrapper) generateTraverser(cnr cid.ID, epoch uint64) (*placement.Traverser, error) { return (*util.TraverserGenerator)(e).GenerateTraverser(cnr, nil, epoch) } - -func (n *nmSrcWrapper) currentEpoch() (uint64, error) { - return n.nmSrc.Epoch() -} -- 2.45.3 From 56f841b022eec6a9bd37349154718cfdc9b3c426 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 24 Aug 2023 20:57:53 +0300 Subject: [PATCH 2/5] [#647] objsvc/search: Remove TraverserGenerator wrapper Signed-off-by: Evgenii Stratonikov --- pkg/services/object/search/exec.go | 2 +- pkg/services/object/search/search_test.go | 2 +- pkg/services/object/search/service.go | 4 ++-- pkg/services/object/search/util.go | 8 -------- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/pkg/services/object/search/exec.go b/pkg/services/object/search/exec.go index f471da20e..d69cb9b50 100644 --- a/pkg/services/object/search/exec.go +++ b/pkg/services/object/search/exec.go @@ -93,7 +93,7 @@ func (exec *execCtx) initEpoch() bool { } func (exec *execCtx) generateTraverser(cnr cid.ID) (*placement.Traverser, bool) { - t, err := exec.svc.traverserGenerator.generateTraverser(cnr, exec.curProcEpoch) + t, err := exec.svc.traverserGenerator.GenerateTraverser(cnr, nil, exec.curProcEpoch) switch { default: diff --git a/pkg/services/object/search/search_test.go b/pkg/services/object/search/search_test.go index d8c5ad090..9bfc54739 100644 --- a/pkg/services/object/search/search_test.go +++ b/pkg/services/object/search/search_test.go @@ -71,7 +71,7 @@ func newTestStorage() *testStorage { } } -func (g *testTraverserGenerator) generateTraverser(_ cid.ID, epoch uint64) (*placement.Traverser, error) { +func (g *testTraverserGenerator) GenerateTraverser(_ cid.ID, _ *oid.ID, epoch uint64) (*placement.Traverser, error) { return placement.NewTraverser( placement.ForContainer(g.c), placement.UseBuilder(g.b[epoch]), diff --git a/pkg/services/object/search/service.go b/pkg/services/object/search/service.go index fd3dbb07b..863312200 100644 --- a/pkg/services/object/search/service.go +++ b/pkg/services/object/search/service.go @@ -45,7 +45,7 @@ type cfg struct { } traverserGenerator interface { - generateTraverser(cid.ID, uint64) (*placement.Traverser, error) + GenerateTraverser(cid.ID, *oid.ID, uint64) (*placement.Traverser, error) } currentEpochReceiver interface { @@ -71,7 +71,7 @@ func New(e *engine.StorageEngine, localStorage: &storageEngineWrapper{ storage: e, }, - traverserGenerator: (*traverseGeneratorWrapper)(tg), + traverserGenerator: tg, currentEpochReceiver: ns, keyStore: ks, } diff --git a/pkg/services/object/search/util.go b/pkg/services/object/search/util.go index 6ea8e3f14..37d215256 100644 --- a/pkg/services/object/search/util.go +++ b/pkg/services/object/search/util.go @@ -8,8 +8,6 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/local_object_storage/engine" internalclient "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/internal/client" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object/util" - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement" - cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" ) @@ -33,8 +31,6 @@ type storageEngineWrapper struct { storage *engine.StorageEngine } -type traverseGeneratorWrapper util.TraverserGenerator - func newUniqueAddressWriter(w IDListWriter) IDListWriter { return &uniqueIDWriter{ written: make(map[oid.ID]struct{}), @@ -134,7 +130,3 @@ func idsFromAddresses(addrs []oid.Address) []oid.ID { return ids } - -func (e *traverseGeneratorWrapper) generateTraverser(cnr cid.ID, epoch uint64) (*placement.Traverser, error) { - return (*util.TraverserGenerator)(e).GenerateTraverser(cnr, nil, epoch) -} -- 2.45.3 From 966ad22abfc9e47397e112f7947a138b5d619c0d Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 24 Aug 2023 21:44:55 +0300 Subject: [PATCH 3/5] [#647] objsvc/search: Simplify error handling Signed-off-by: Evgenii Stratonikov --- pkg/services/object/search/container.go | 41 ++++++-------- pkg/services/object/search/exec.go | 72 ++++--------------------- pkg/services/object/search/local.go | 20 ++++--- pkg/services/object/search/search.go | 35 ++++++------ 4 files changed, 51 insertions(+), 117 deletions(-) diff --git a/pkg/services/object/search/container.go b/pkg/services/object/search/container.go index 2b6101a98..a8865f5f0 100644 --- a/pkg/services/object/search/container.go +++ b/pkg/services/object/search/container.go @@ -3,6 +3,7 @@ package searchsvc import ( "context" "encoding/hex" + "fmt" "sync" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" @@ -10,12 +11,7 @@ import ( "go.uber.org/zap" ) -func (exec *execCtx) executeOnContainer(ctx context.Context) { - if exec.isLocal() { - exec.log.Debug(logs.SearchReturnResultDirectly) - return - } - +func (exec *execCtx) executeOnContainer(ctx context.Context) error { lookupDepth := exec.netmapLookupDepth() exec.log.Debug(logs.TryingToExecuteInContainer, @@ -23,13 +19,12 @@ func (exec *execCtx) executeOnContainer(ctx context.Context) { ) // initialize epoch number - ok := exec.initEpoch() - if !ok { - return + if err := exec.initEpoch(); err != nil { + return fmt.Errorf("%s: %w", logs.CouldNotGetCurrentEpochNumber, err) } for { - if exec.processCurrentEpoch(ctx) { + if err := exec.processCurrentEpoch(ctx); err != nil { break } @@ -44,18 +39,17 @@ func (exec *execCtx) executeOnContainer(ctx context.Context) { exec.curProcEpoch-- } - exec.status = statusOK - exec.err = nil + return nil } -func (exec *execCtx) processCurrentEpoch(ctx context.Context) bool { +func (exec *execCtx) processCurrentEpoch(ctx context.Context) error { exec.log.Debug(logs.ProcessEpoch, zap.Uint64("number", exec.curProcEpoch), ) - traverser, ok := exec.generateTraverser(exec.containerID()) - if !ok { - return true + traverser, err := exec.svc.traverserGenerator.GenerateTraverser(exec.containerID(), nil, exec.curProcEpoch) + if err != nil { + return fmt.Errorf("%s: %w", logs.SearchCouldNotGenerateContainerTraverser, err) } ctx, cancel := context.WithCancel(ctx) @@ -91,12 +85,7 @@ func (exec *execCtx) processCurrentEpoch(ctx context.Context) bool { c, err := exec.svc.clientConstructor.get(info) if err != nil { - mtx.Lock() - exec.status = statusUndefined - exec.err = err - mtx.Unlock() - - exec.log.Debug(logs.SearchCouldNotConstructRemoteNodeClient) + exec.log.Debug(logs.SearchCouldNotConstructRemoteNodeClient, zap.String("error", err.Error())) return } @@ -109,13 +98,17 @@ func (exec *execCtx) processCurrentEpoch(ctx context.Context) bool { } mtx.Lock() - exec.writeIDList(ids) + err = exec.writeIDList(ids) mtx.Unlock() + if err != nil { + exec.log.Debug(logs.SearchCouldNotWriteObjectIdentifiers, zap.String("error", err.Error())) + return + } }(i) } wg.Wait() } - return false + return nil } diff --git a/pkg/services/object/search/exec.go b/pkg/services/object/search/exec.go index d69cb9b50..62ef5827f 100644 --- a/pkg/services/object/search/exec.go +++ b/pkg/services/object/search/exec.go @@ -1,8 +1,6 @@ package searchsvc import ( - "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" - "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/services/object_manager/placement" "git.frostfs.info/TrueCloudLab/frostfs-node/pkg/util/logger" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" objectSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" @@ -10,28 +8,16 @@ import ( "go.uber.org/zap" ) -type statusError struct { - status int - err error -} - type execCtx struct { svc *Service prm Prm - statusError - log *logger.Logger curProcEpoch uint64 } -const ( - statusUndefined int = iota - statusOK -) - func (exec *execCtx) prepare() { if _, ok := exec.prm.writer.(*uniqueIDWriter); !ok { exec.prm.writer = newUniqueAddressWriter(exec.prm.writer) @@ -68,64 +54,24 @@ func (exec *execCtx) netmapLookupDepth() uint64 { return exec.prm.common.NetmapLookupDepth() } -func (exec *execCtx) initEpoch() bool { +func (exec *execCtx) initEpoch() error { exec.curProcEpoch = exec.netmapEpoch() if exec.curProcEpoch > 0 { - return true + return nil } e, err := exec.svc.currentEpochReceiver.Epoch() - - switch { - default: - exec.status = statusUndefined - exec.err = err - - exec.log.Debug(logs.CouldNotGetCurrentEpochNumber, - zap.String("error", err.Error()), - ) - - return false - case err == nil: - exec.curProcEpoch = e - return true + if err != nil { + return err } + + exec.curProcEpoch = e + return nil } -func (exec *execCtx) generateTraverser(cnr cid.ID) (*placement.Traverser, bool) { - t, err := exec.svc.traverserGenerator.GenerateTraverser(cnr, nil, exec.curProcEpoch) - - switch { - default: - exec.status = statusUndefined - exec.err = err - - exec.log.Debug(logs.SearchCouldNotGenerateContainerTraverser, - zap.String("error", err.Error()), - ) - - return nil, false - case err == nil: - return t, true - } -} - -func (exec *execCtx) writeIDList(ids []oid.ID) { +func (exec *execCtx) writeIDList(ids []oid.ID) error { ids = exec.filterAllowedObjectIDs(ids) - err := exec.prm.writer.WriteIDs(ids) - - switch { - default: - exec.status = statusUndefined - exec.err = err - - exec.log.Debug(logs.SearchCouldNotWriteObjectIdentifiers, - zap.String("error", err.Error()), - ) - case err == nil: - exec.status = statusOK - exec.err = nil - } + return exec.prm.writer.WriteIDs(ids) } func (exec *execCtx) filterAllowedObjectIDs(objIDs []oid.ID) []oid.ID { diff --git a/pkg/services/object/search/local.go b/pkg/services/object/search/local.go index 1af69caf1..cfaed13b8 100644 --- a/pkg/services/object/search/local.go +++ b/pkg/services/object/search/local.go @@ -2,24 +2,22 @@ package searchsvc import ( "context" + "fmt" "git.frostfs.info/TrueCloudLab/frostfs-node/internal/logs" "go.uber.org/zap" ) -func (exec *execCtx) executeLocal(ctx context.Context) { +func (exec *execCtx) executeLocal(ctx context.Context) error { ids, err := exec.svc.localStorage.search(ctx, exec) - if err != nil { - exec.status = statusUndefined - exec.err = err - - exec.log.Debug(logs.SearchLocalOperationFailed, - zap.String("error", err.Error()), - ) - - return + exec.log.Debug(logs.SearchLocalOperationFailed, zap.String("error", err.Error())) + return err } - exec.writeIDList(ids) + if err := exec.writeIDList(ids); err != nil { + return fmt.Errorf("%s: %w", logs.SearchCouldNotWriteObjectIdentifiers, err) + } + + return nil } diff --git a/pkg/services/object/search/search.go b/pkg/services/object/search/search.go index 7a7cbfc5b..2be6bb0e3 100644 --- a/pkg/services/object/search/search.go +++ b/pkg/services/object/search/search.go @@ -18,33 +18,30 @@ func (s *Service) Search(ctx context.Context, prm Prm) error { exec.setLogger(s.log) - exec.execute(ctx) - - return exec.statusError.err + return exec.execute(ctx) } -func (exec *execCtx) execute(ctx context.Context) { +func (exec *execCtx) execute(ctx context.Context) error { exec.log.Debug(logs.ServingRequest) - // perform local operation - exec.executeLocal(ctx) + err := exec.executeLocal(ctx) + exec.logResult(err) - exec.analyzeStatus(ctx, true) + if exec.isLocal() { + exec.log.Debug(logs.SearchReturnResultDirectly) + return err + } + + err = exec.executeOnContainer(ctx) + exec.logResult(err) + return err } -func (exec *execCtx) analyzeStatus(ctx context.Context, execCnr bool) { - // analyze local result - switch exec.status { +func (exec *execCtx) logResult(err error) { + switch { default: - exec.log.Debug(logs.OperationFinishedWithError, - zap.String("error", exec.err.Error()), - ) - case statusOK: + exec.log.Debug(logs.OperationFinishedWithError, zap.String("error", err.Error())) + case err == nil: exec.log.Debug(logs.OperationFinishedSuccessfully) } - - if execCnr { - exec.executeOnContainer(ctx) - exec.analyzeStatus(ctx, false) - } } -- 2.45.3 From 4db2cbc9274b8314157b6856fa093191aed73fa9 Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 24 Aug 2023 21:55:36 +0300 Subject: [PATCH 4/5] [#647] objsvc/search: Wrap in uniqueIDWriter during parameter setting Signed-off-by: Evgenii Stratonikov --- pkg/services/object/search/exec.go | 6 ------ pkg/services/object/search/prm.go | 4 ++-- pkg/services/object/search/search.go | 2 -- pkg/services/object/search/util.go | 5 ++++- 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/pkg/services/object/search/exec.go b/pkg/services/object/search/exec.go index 62ef5827f..2e0d48773 100644 --- a/pkg/services/object/search/exec.go +++ b/pkg/services/object/search/exec.go @@ -18,12 +18,6 @@ type execCtx struct { curProcEpoch uint64 } -func (exec *execCtx) prepare() { - if _, ok := exec.prm.writer.(*uniqueIDWriter); !ok { - exec.prm.writer = newUniqueAddressWriter(exec.prm.writer) - } -} - func (exec *execCtx) setLogger(l *logger.Logger) { exec.log = &logger.Logger{Logger: l.With( zap.String("request", "SEARCH"), diff --git a/pkg/services/object/search/prm.go b/pkg/services/object/search/prm.go index d2918d6e7..95fe82e2f 100644 --- a/pkg/services/object/search/prm.go +++ b/pkg/services/object/search/prm.go @@ -12,7 +12,7 @@ import ( // Prm groups parameters of Get service call. type Prm struct { - writer IDListWriter + writer *uniqueIDWriter common *util.CommonPrm @@ -40,7 +40,7 @@ func (p *Prm) SetCommonParameters(common *util.CommonPrm) { // SetWriter sets target component to write list of object identifiers. func (p *Prm) SetWriter(w IDListWriter) { - p.writer = w + p.writer = newUniqueAddressWriter(w) } // SetRequestForwarder sets callback for forwarding diff --git a/pkg/services/object/search/search.go b/pkg/services/object/search/search.go index 2be6bb0e3..4a5c414d5 100644 --- a/pkg/services/object/search/search.go +++ b/pkg/services/object/search/search.go @@ -14,8 +14,6 @@ func (s *Service) Search(ctx context.Context, prm Prm) error { prm: prm, } - exec.prepare() - exec.setLogger(s.log) return exec.execute(ctx) diff --git a/pkg/services/object/search/util.go b/pkg/services/object/search/util.go index 37d215256..67b6c0d01 100644 --- a/pkg/services/object/search/util.go +++ b/pkg/services/object/search/util.go @@ -31,7 +31,10 @@ type storageEngineWrapper struct { storage *engine.StorageEngine } -func newUniqueAddressWriter(w IDListWriter) IDListWriter { +func newUniqueAddressWriter(w IDListWriter) *uniqueIDWriter { + if w, ok := w.(*uniqueIDWriter); ok { + return w + } return &uniqueIDWriter{ written: make(map[oid.ID]struct{}), writer: w, -- 2.45.3 From 40b556fc197666a454b4b84a518c6c59e78ce4bb Mon Sep 17 00:00:00 2001 From: Evgenii Stratonikov Date: Thu, 24 Aug 2023 22:17:27 +0300 Subject: [PATCH 5/5] [#647] objsvc/search: Improve testing coverage Signed-off-by: Evgenii Stratonikov --- pkg/services/object/search/search_test.go | 113 +++++++++++++++++----- 1 file changed, 90 insertions(+), 23 deletions(-) diff --git a/pkg/services/object/search/search_test.go b/pkg/services/object/search/search_test.go index 9bfc54739..09d98eff2 100644 --- a/pkg/services/object/search/search_test.go +++ b/pkg/services/object/search/search_test.go @@ -22,6 +22,7 @@ import ( frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" + oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" sessionsdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" "github.com/google/uuid" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" @@ -60,6 +61,14 @@ func (e testEpochReceiver) Epoch() (uint64, error) { return uint64(e), nil } +type errIDWriter struct { + err error +} + +func (e errIDWriter) WriteIDs(ids []oid.ID) error { + return e.err +} + func (s *simpleIDWriter) WriteIDs(ids []oid.ID) error { s.ids = append(s.ids, ids...) return nil @@ -194,6 +203,20 @@ func TestGetLocalOnly(t *testing.T) { w := new(simpleIDWriter) p := newPrm(cnr, w) + err := svc.Search(ctx, p) + require.ErrorIs(t, err, testErr) + }) + t.Run("FAIL while writing ID", func(t *testing.T) { + storage := newTestStorage() + svc := newSvc(storage) + + cnr := cidtest.ID() + storage.addResult(cnr, []oid.ID{oidtest.ID()}, nil) + + testErr := errors.New("any error") + w := errIDWriter{testErr} + p := newPrm(cnr, w) + err := svc.Search(ctx, p) require.ErrorIs(t, err, testErr) }) @@ -280,33 +303,34 @@ func TestGetRemoteSmall(t *testing.T) { return p } + var addr oid.Address + addr.SetContainer(id) + + ns, as := testNodeMatrix(t, placementDim) + + builder := &testPlacementBuilder{ + vectors: map[string][][]netmap.NodeInfo{ + addr.EncodeToString(): ns, + }, + } + + c1 := newTestStorage() + ids1 := generateIDs(10) + + c2 := newTestStorage() + ids2 := generateIDs(10) + + svc := newSvc(builder, &testClientCache{ + clients: map[string]*testStorage{ + as[0][0]: c1, + as[0][1]: c2, + }, + }) + t.Run("OK", func(t *testing.T) { - var addr oid.Address - addr.SetContainer(id) - - ns, as := testNodeMatrix(t, placementDim) - - builder := &testPlacementBuilder{ - vectors: map[string][][]netmap.NodeInfo{ - addr.EncodeToString(): ns, - }, - } - - c1 := newTestStorage() - ids1 := generateIDs(10) c1.addResult(id, ids1, nil) - - c2 := newTestStorage() - ids2 := generateIDs(10) c2.addResult(id, ids2, nil) - svc := newSvc(builder, &testClientCache{ - clients: map[string]*testStorage{ - as[0][0]: c1, - as[0][1]: c2, - }, - }) - w := new(simpleIDWriter) p := newPrm(id, w) @@ -319,6 +343,49 @@ func TestGetRemoteSmall(t *testing.T) { require.Contains(t, w.ids, id) } }) + t.Run("non-local fail is not a FAIL", func(t *testing.T) { + testErr := errors.New("opaque") + + c1.addResult(id, ids1, nil) + c2.addResult(id, nil, testErr) + + w := new(simpleIDWriter) + p := newPrm(id, w) + + err := svc.Search(ctx, p) + require.NoError(t, err) + require.Equal(t, ids1, w.ids) + }) + t.Run("client init fail is not a FAIL", func(t *testing.T) { + svc := newSvc(builder, &testClientCache{ + clients: map[string]*testStorage{ + as[0][0]: c1, + }, + }) + c1.addResult(id, ids1, nil) + c2.addResult(id, ids2, nil) + + w := new(simpleIDWriter) + p := newPrm(id, w) + + err := svc.Search(ctx, p) + require.NoError(t, err) + require.Equal(t, ids1, w.ids) + }) + t.Run("context is respected", func(t *testing.T) { + c1.addResult(id, ids1, nil) + c2.addResult(id, ids2, nil) + + w := new(simpleIDWriter) + p := newPrm(id, w) + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + err := svc.Search(ctx, p) + require.NoError(t, err) + require.Empty(t, w.ids) + }) } func TestGetFromPastEpoch(t *testing.T) { -- 2.45.3