github.com/m3db/m3@v1.5.0/src/m3ninx/search/proptest/concurrent_test.go (about) 1 // Copyright (c) 2018 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package proptest 22 23 import ( 24 "math/rand" 25 "os" 26 "sync" 27 "testing" 28 "time" 29 30 "github.com/m3db/m3/src/m3ninx/index" 31 "github.com/m3db/m3/src/m3ninx/index/segment/fst" 32 "github.com/m3db/m3/src/m3ninx/search" 33 "github.com/m3db/m3/src/m3ninx/search/executor" 34 "github.com/m3db/m3/src/x/context" 35 36 "github.com/leanovate/gopter" 37 "github.com/leanovate/gopter/prop" 38 "github.com/stretchr/testify/require" 39 ) 40 41 func TestConcurrentQueries(t *testing.T) { 42 ctx := context.NewBackground() 43 parameters := gopter.DefaultTestParameters() 44 seed := time.Now().UnixNano() 45 parameters.MinSuccessfulTests = 100 46 parameters.MaxSize = 20 47 parameters.Rng = rand.New(rand.NewSource(seed)) 48 properties := gopter.NewProperties(parameters) 49 50 simpleSeg := newTestMemSegment(t, lotsTestDocuments) 51 simpleReader, err := simpleSeg.Reader() 52 require.NoError(t, err) 53 simpleExec := executor.NewExecutor([]index.Reader{simpleReader}) 54 55 fstSeg := fst.ToTestSegment(t, simpleSeg, fstOptions) 56 fstReader, err := fstSeg.Reader() 57 require.NoError(t, err) 58 fstExec := executor.NewExecutor([]index.Reader{fstReader}) 59 60 properties.Property("Any concurrent queries segments does not affect fst segments", prop.ForAll( 61 func(q search.Query) (bool, error) { 62 dOrg, err := simpleExec.Execute(ctx, q) 63 require.NoError(t, err) 64 matchedDocs, err := collectDocs(dOrg) 65 require.NoError(t, err) 66 docMatcher, err := newDocumentIteratorMatcher(t, matchedDocs...) 67 require.NoError(t, err) 68 69 var ( 70 numConcurrentWorkers = 2 71 wg sync.WaitGroup 72 errLock sync.Mutex 73 matchErr error 74 ) 75 wg.Add(numConcurrentWorkers) 76 77 for i := 0; i < numConcurrentWorkers; i++ { 78 go func() { 79 defer wg.Done() 80 fstDocs, err := fstExec.Execute(ctx, q) 81 require.NoError(t, err) 82 if err := docMatcher.Matches(fstDocs); err != nil { 83 errLock.Lock() 84 matchErr = err 85 errLock.Unlock() 86 } 87 }() 88 } 89 wg.Wait() 90 errLock.Lock() 91 defer errLock.Unlock() 92 if matchErr != nil { 93 return false, matchErr 94 } 95 96 return true, nil 97 }, 98 GenQuery(lotsTestDocuments), 99 )) 100 101 reporter := gopter.NewFormatedReporter(true, 160, os.Stdout) 102 if !properties.Run(reporter) { 103 t.Errorf("failed with initial seed: %d", seed) 104 } 105 }