go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/internal/tracesampler_test.go (about) 1 // Copyright 2019 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package internal 16 17 import ( 18 "math/rand" 19 "sync/atomic" 20 "testing" 21 "time" 22 23 "go.opentelemetry.io/otel/sdk/trace" 24 25 . "github.com/smartystreets/goconvey/convey" 26 . "go.chromium.org/luci/common/testing/assertions" 27 ) 28 29 func TestSamplerParsing(t *testing.T) { 30 t.Parallel() 31 32 Convey("Percent", t, func() { 33 s, err := BaseSampler("0.1%") 34 So(err, ShouldBeNil) 35 So(s, ShouldNotBeNil) 36 37 _, err = BaseSampler("abc%") 38 So(err, ShouldErrLike, `not a float percent "abc%"`) 39 }) 40 41 Convey("QPS", t, func() { 42 s, err := BaseSampler("0.1qps") 43 So(err, ShouldBeNil) 44 So(s, ShouldNotBeNil) 45 46 _, err = BaseSampler("abcqps") 47 So(err, ShouldErrLike, `not a float QPS "abcqps"`) 48 }) 49 50 Convey("Unrecognized", t, func() { 51 _, err := BaseSampler("huh") 52 So(err, ShouldErrLike, "unrecognized sampling spec string") 53 }) 54 } 55 56 func TestQPSSampler(t *testing.T) { 57 t.Parallel() 58 59 Convey("Works", t, func() { 60 now := atomic.Value{} 61 now.Store(time.Now()) // the absolute value doesn't matter 62 tick := func(dt time.Duration) { now.Store(now.Load().(time.Time).Add(dt)) } 63 64 sampler := qpsSampler{ 65 period: time.Second, // sample one request per second 66 now: func() time.Time { return now.Load().(time.Time) }, 67 rnd: rand.New(rand.NewSource(0)), 68 } 69 70 sampled := 0 71 for i := 0; i < 10000; i++ { 72 // Note: TraceID is not used in the current implementation, but we supply 73 // it nonetheless to make the test also work with other implementations. 74 params := trace.SamplingParameters{} 75 if _, err := rand.Read(params.TraceID[:]); err != nil { 76 panic(err) 77 } 78 if sampler.ShouldSample(params).Decision == trace.RecordAndSample { 79 sampled++ 80 } 81 tick(10 * time.Millisecond) // 100 QPS 82 } 83 So(sampled, ShouldEqual, 10000/100+1) // '+1' is due to randomization 84 }) 85 }