1 /* 2 * Copyright 2017, OpenCensus Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.opencensus.trace.samplers; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import io.opencensus.trace.NoopSpan; 22 import io.opencensus.trace.Sampler; 23 import io.opencensus.trace.Span; 24 import io.opencensus.trace.SpanContext; 25 import io.opencensus.trace.SpanId; 26 import io.opencensus.trace.TraceId; 27 import io.opencensus.trace.TraceOptions; 28 import java.util.Arrays; 29 import java.util.Collections; 30 import java.util.EnumSet; 31 import java.util.List; 32 import java.util.Random; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.junit.runners.JUnit4; 36 37 /** Unit tests for {@link Samplers}. */ 38 @RunWith(JUnit4.class) 39 public class SamplersTest { 40 private static final String SPAN_NAME = "MySpanName"; 41 private static final int NUM_SAMPLE_TRIES = 1000; 42 private final Random random = new Random(1234); 43 private final TraceId traceId = TraceId.generateRandomId(random); 44 private final SpanId parentSpanId = SpanId.generateRandomId(random); 45 private final SpanId spanId = SpanId.generateRandomId(random); 46 private final SpanContext sampledSpanContext = 47 SpanContext.create(traceId, parentSpanId, TraceOptions.builder().setIsSampled(true).build()); 48 private final SpanContext notSampledSpanContext = 49 SpanContext.create(traceId, parentSpanId, TraceOptions.DEFAULT); 50 private final Span sampledSpan = 51 new NoopSpan(sampledSpanContext, EnumSet.of(Span.Options.RECORD_EVENTS)); 52 53 @Test alwaysSampleSampler_AlwaysReturnTrue()54 public void alwaysSampleSampler_AlwaysReturnTrue() { 55 // Sampled parent. 56 assertThat( 57 Samplers.alwaysSample() 58 .shouldSample( 59 sampledSpanContext, 60 false, 61 traceId, 62 spanId, 63 "Another name", 64 Collections.<Span>emptyList())) 65 .isTrue(); 66 // Not sampled parent. 67 assertThat( 68 Samplers.alwaysSample() 69 .shouldSample( 70 notSampledSpanContext, 71 false, 72 traceId, 73 spanId, 74 "Yet another name", 75 Collections.<Span>emptyList())) 76 .isTrue(); 77 } 78 79 @Test alwaysSampleSampler_ToString()80 public void alwaysSampleSampler_ToString() { 81 assertThat(Samplers.alwaysSample().toString()).isEqualTo("AlwaysSampleSampler"); 82 } 83 84 @Test neverSampleSampler_AlwaysReturnFalse()85 public void neverSampleSampler_AlwaysReturnFalse() { 86 // Sampled parent. 87 assertThat( 88 Samplers.neverSample() 89 .shouldSample( 90 sampledSpanContext, 91 false, 92 traceId, 93 spanId, 94 "bar", 95 Collections.<Span>emptyList())) 96 .isFalse(); 97 // Not sampled parent. 98 assertThat( 99 Samplers.neverSample() 100 .shouldSample( 101 notSampledSpanContext, 102 false, 103 traceId, 104 spanId, 105 "quux", 106 Collections.<Span>emptyList())) 107 .isFalse(); 108 } 109 110 @Test neverSampleSampler_ToString()111 public void neverSampleSampler_ToString() { 112 assertThat(Samplers.neverSample().toString()).isEqualTo("NeverSampleSampler"); 113 } 114 115 @Test(expected = IllegalArgumentException.class) probabilitySampler_outOfRangeHighProbability()116 public void probabilitySampler_outOfRangeHighProbability() { 117 Samplers.probabilitySampler(1.01); 118 } 119 120 @Test(expected = IllegalArgumentException.class) probabilitySampler_outOfRangeLowProbability()121 public void probabilitySampler_outOfRangeLowProbability() { 122 Samplers.probabilitySampler(-0.00001); 123 } 124 125 // Applies the given sampler to NUM_SAMPLE_TRIES random traceId/spanId pairs. assertSamplerSamplesWithProbability( Sampler sampler, SpanContext parent, List<Span> parentLinks, double probability)126 private static void assertSamplerSamplesWithProbability( 127 Sampler sampler, SpanContext parent, List<Span> parentLinks, double probability) { 128 Random random = new Random(1234); 129 int count = 0; // Count of spans with sampling enabled 130 for (int i = 0; i < NUM_SAMPLE_TRIES; i++) { 131 if (sampler.shouldSample( 132 parent, 133 false, 134 TraceId.generateRandomId(random), 135 SpanId.generateRandomId(random), 136 SPAN_NAME, 137 parentLinks)) { 138 count++; 139 } 140 } 141 double proportionSampled = (double) count / NUM_SAMPLE_TRIES; 142 // Allow for a large amount of slop (+/- 10%) in number of sampled traces, to avoid flakiness. 143 assertThat(proportionSampled < probability + 0.1 && proportionSampled > probability - 0.1) 144 .isTrue(); 145 } 146 147 @Test probabilitySampler_DifferentProbabilities_NotSampledParent()148 public void probabilitySampler_DifferentProbabilities_NotSampledParent() { 149 final Sampler neverSample = Samplers.probabilitySampler(0.0); 150 assertSamplerSamplesWithProbability( 151 neverSample, notSampledSpanContext, Collections.<Span>emptyList(), 0.0); 152 final Sampler alwaysSample = Samplers.probabilitySampler(1.0); 153 assertSamplerSamplesWithProbability( 154 alwaysSample, notSampledSpanContext, Collections.<Span>emptyList(), 1.0); 155 final Sampler fiftyPercentSample = Samplers.probabilitySampler(0.5); 156 assertSamplerSamplesWithProbability( 157 fiftyPercentSample, notSampledSpanContext, Collections.<Span>emptyList(), 0.5); 158 final Sampler twentyPercentSample = Samplers.probabilitySampler(0.2); 159 assertSamplerSamplesWithProbability( 160 twentyPercentSample, notSampledSpanContext, Collections.<Span>emptyList(), 0.2); 161 final Sampler twoThirdsSample = Samplers.probabilitySampler(2.0 / 3.0); 162 assertSamplerSamplesWithProbability( 163 twoThirdsSample, notSampledSpanContext, Collections.<Span>emptyList(), 2.0 / 3.0); 164 } 165 166 @Test probabilitySampler_DifferentProbabilities_SampledParent()167 public void probabilitySampler_DifferentProbabilities_SampledParent() { 168 final Sampler neverSample = Samplers.probabilitySampler(0.0); 169 assertSamplerSamplesWithProbability( 170 neverSample, sampledSpanContext, Collections.<Span>emptyList(), 1.0); 171 final Sampler alwaysSample = Samplers.probabilitySampler(1.0); 172 assertSamplerSamplesWithProbability( 173 alwaysSample, sampledSpanContext, Collections.<Span>emptyList(), 1.0); 174 final Sampler fiftyPercentSample = Samplers.probabilitySampler(0.5); 175 assertSamplerSamplesWithProbability( 176 fiftyPercentSample, sampledSpanContext, Collections.<Span>emptyList(), 1.0); 177 final Sampler twentyPercentSample = Samplers.probabilitySampler(0.2); 178 assertSamplerSamplesWithProbability( 179 twentyPercentSample, sampledSpanContext, Collections.<Span>emptyList(), 1.0); 180 final Sampler twoThirdsSample = Samplers.probabilitySampler(2.0 / 3.0); 181 assertSamplerSamplesWithProbability( 182 twoThirdsSample, sampledSpanContext, Collections.<Span>emptyList(), 1.0); 183 } 184 185 @Test probabilitySampler_DifferentProbabilities_SampledParentLink()186 public void probabilitySampler_DifferentProbabilities_SampledParentLink() { 187 final Sampler neverSample = Samplers.probabilitySampler(0.0); 188 assertSamplerSamplesWithProbability( 189 neverSample, notSampledSpanContext, Arrays.asList(sampledSpan), 1.0); 190 final Sampler alwaysSample = Samplers.probabilitySampler(1.0); 191 assertSamplerSamplesWithProbability( 192 alwaysSample, notSampledSpanContext, Arrays.asList(sampledSpan), 1.0); 193 final Sampler fiftyPercentSample = Samplers.probabilitySampler(0.5); 194 assertSamplerSamplesWithProbability( 195 fiftyPercentSample, notSampledSpanContext, Arrays.asList(sampledSpan), 1.0); 196 final Sampler twentyPercentSample = Samplers.probabilitySampler(0.2); 197 assertSamplerSamplesWithProbability( 198 twentyPercentSample, notSampledSpanContext, Arrays.asList(sampledSpan), 1.0); 199 final Sampler twoThirdsSample = Samplers.probabilitySampler(2.0 / 3.0); 200 assertSamplerSamplesWithProbability( 201 twoThirdsSample, notSampledSpanContext, Arrays.asList(sampledSpan), 1.0); 202 } 203 204 @Test probabilitySampler_SampleBasedOnTraceId()205 public void probabilitySampler_SampleBasedOnTraceId() { 206 final Sampler defaultProbability = Samplers.probabilitySampler(0.0001); 207 // This traceId will not be sampled by the ProbabilitySampler because the first 8 bytes as long 208 // is not less than probability * Long.MAX_VALUE; 209 TraceId notSampledtraceId = 210 TraceId.fromBytes( 211 new byte[] { 212 (byte) 0x8F, 213 (byte) 0xFF, 214 (byte) 0xFF, 215 (byte) 0xFF, 216 (byte) 0xFF, 217 (byte) 0xFF, 218 (byte) 0xFF, 219 (byte) 0xFF, 220 0, 221 0, 222 0, 223 0, 224 0, 225 0, 226 0, 227 0 228 }); 229 assertThat( 230 defaultProbability.shouldSample( 231 null, 232 false, 233 notSampledtraceId, 234 SpanId.generateRandomId(random), 235 SPAN_NAME, 236 Collections.<Span>emptyList())) 237 .isFalse(); 238 // This traceId will be sampled by the ProbabilitySampler because the first 8 bytes as long 239 // is less than probability * Long.MAX_VALUE; 240 TraceId sampledtraceId = 241 TraceId.fromBytes( 242 new byte[] { 243 (byte) 0x00, 244 (byte) 0x00, 245 (byte) 0xFF, 246 (byte) 0xFF, 247 (byte) 0xFF, 248 (byte) 0xFF, 249 (byte) 0xFF, 250 (byte) 0xFF, 251 0, 252 0, 253 0, 254 0, 255 0, 256 0, 257 0, 258 0 259 }); 260 assertThat( 261 defaultProbability.shouldSample( 262 null, 263 false, 264 sampledtraceId, 265 SpanId.generateRandomId(random), 266 SPAN_NAME, 267 Collections.<Span>emptyList())) 268 .isTrue(); 269 } 270 271 @Test probabilitySampler_getDescription()272 public void probabilitySampler_getDescription() { 273 assertThat((Samplers.probabilitySampler(0.5)).getDescription()) 274 .isEqualTo(String.format("ProbabilitySampler{%.6f}", 0.5)); 275 } 276 277 @Test probabilitySampler_ToString()278 public void probabilitySampler_ToString() { 279 assertThat((Samplers.probabilitySampler(0.5)).toString()).contains("0.5"); 280 } 281 } 282