Index: third_party/google-endpoints/test/test_distribution.py |
diff --git a/third_party/google-endpoints/test/test_distribution.py b/third_party/google-endpoints/test/test_distribution.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9c447e3cd97d10414b9e3ec76a001894ece48e3a |
--- /dev/null |
+++ b/third_party/google-endpoints/test/test_distribution.py |
@@ -0,0 +1,205 @@ |
+# Copyright 2016 Google Inc. All Rights Reserved. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+from __future__ import absolute_import |
+ |
+import sys |
+import unittest2 |
+from expects import expect, equal, raise_error |
+ |
+from google.api.control import distribution, messages |
+ |
+ |
+class TestCreateExponential(unittest2.TestCase): |
+ |
+ def test_should_fail_if_num_finite_buckets_is_bad(self): |
+ testf = lambda: distribution.create_exponential(0, 1.1, 0.1) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_fail_if_growth_factor_is_bad(self): |
+ testf = lambda: distribution.create_exponential(1, 0.9, 0.1) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_fail_if_scale_is_bad(self): |
+ testf = lambda: distribution.create_exponential(1, 1.1, -0.1) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_succeed_if_inputs_are_ok(self): |
+ num_finite_buckets = 1 |
+ got = distribution.create_exponential(num_finite_buckets, 1.1, 0.1) |
+ expect(len(got.bucketCounts)).to(equal(num_finite_buckets + 2)) |
+ |
+ |
+class TestCreateLinear(unittest2.TestCase): |
+ |
+ def test_should_fail_if_num_finite_buckets_is_bad(self): |
+ testf = lambda: distribution.create_linear(0, 1.1, 0.1) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_fail_if_growth_factor_is_bad(self): |
+ testf = lambda: distribution.create_linear(1, -0.1, 0.1) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_succeed_if_inputs_are_ok(self): |
+ num_finite_buckets = 1 |
+ got = distribution.create_linear(num_finite_buckets, 0.1, 0.1) |
+ expect(len(got.bucketCounts)).to(equal(num_finite_buckets + 2)) |
+ |
+ |
+class TestCreateExplicit(unittest2.TestCase): |
+ |
+ def test_should_fail_if_there_are_matching_bounds(self): |
+ testf = lambda: distribution.create_explicit([0.0, 0.1, 0.1]) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_succeed_if_inputs_are_ok(self): |
+ want = [0.1, 0.2, 0.3] |
+ got = distribution.create_explicit([0.1, 0.2, 0.3]) |
+ expect(got.explicitBuckets.bounds).to(equal(want)) |
+ expect(len(got.bucketCounts)).to(equal(len(want) + 1)) |
+ |
+ def test_should_succeed_if_input_bounds_are_unsorted(self): |
+ want = [0.1, 0.2, 0.3] |
+ got = distribution.create_explicit([0.3, 0.1, 0.2]) |
+ expect(got.explicitBuckets.bounds).to(equal(want)) |
+ |
+ |
+def _make_explicit_dist(): |
+ return distribution.create_explicit([0.1, 0.3, 0.5, 0.7]) |
+ |
+ |
+def _make_linear_dist(): |
+ return distribution.create_linear(3, 0.2, 0.1) |
+ |
+ |
+def _make_exponential_dist(): |
+ return distribution.create_exponential(3, 2, 0.1) |
+ |
+_UNDERFLOW_SAMPLE = 1e-5 |
+_LOW_SAMPLE = 0.11 |
+_HIGH_SAMPLE = 0.5 |
+_OVERFLOW_SAMPLE = 1e5 |
+ |
+_TEST_SAMPLES_AND_BUCKETS = [ |
+ { |
+ 'samples': [_UNDERFLOW_SAMPLE], |
+ 'want': [1, 0, 0, 0, 0] |
+ }, |
+ { |
+ 'samples': [_LOW_SAMPLE] * 2, |
+ 'want': [0, 2, 0, 0, 0] |
+ }, |
+ { |
+ 'samples': [_LOW_SAMPLE, _HIGH_SAMPLE, _HIGH_SAMPLE], |
+ 'want': [0, 1, 0, 2, 0] |
+ }, |
+ { |
+ 'samples': [_OVERFLOW_SAMPLE], |
+ 'want': [0, 0, 0, 0, 1] |
+ }, |
+] |
+ |
+ |
+def _expect_stats_eq_direct_calc_from_samples(d, samples): |
+ # pylint: disable=fixme |
+ # TODO: update this the sum of rho-squared |
+ want_mean = sum(samples) / len(samples) |
+ expect(d.mean).to(equal(want_mean)) |
+ expect(d.maximum).to(equal(max(samples))) |
+ expect(d.minimum).to(equal(min(samples))) |
+ |
+ |
+class TestAddSample(unittest2.TestCase): |
+ NOTHING_SET = messages.Distribution() |
+ |
+ def test_should_fail_if_no_buckets_are_set(self): |
+ testf = lambda: distribution.add_sample(_UNDERFLOW_SAMPLE, |
+ self.NOTHING_SET) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def expect_adds_test_samples_ok(self, make_dist_func): |
+ for t in _TEST_SAMPLES_AND_BUCKETS: |
+ d = make_dist_func() |
+ samples = t['samples'] |
+ for s in samples: |
+ distribution.add_sample(s, d) |
+ expect(d.bucketCounts).to(equal(t['want'])) |
+ _expect_stats_eq_direct_calc_from_samples(d, samples) |
+ |
+ def test_update_explict_buckets_ok(self): |
+ self.expect_adds_test_samples_ok(_make_explicit_dist) |
+ |
+ def test_update_exponential_buckets_ok(self): |
+ self.expect_adds_test_samples_ok(_make_exponential_dist) |
+ |
+ def test_update_linear_buckets_ok(self): |
+ self.expect_adds_test_samples_ok(_make_linear_dist) |
+ |
+ |
+class TestMerge(unittest2.TestCase): |
+ |
+ def setUp(self): |
+ self.merge_triples = ( |
+ ( |
+ distribution.create_exponential(3, 2, 0.1), |
+ distribution.create_exponential(3, 2, 0.1), |
+ distribution.create_exponential(4, 2, 0.1), |
+ ),( |
+ distribution.create_linear(3, 0.2, 0.1), |
+ distribution.create_linear(3, 0.2, 0.1), |
+ distribution.create_linear(4, 0.2, 0.1) |
+ ),( |
+ distribution.create_explicit([0.1, 0.3]), |
+ distribution.create_explicit([0.1, 0.3]), |
+ distribution.create_explicit([0.1, 0.3, 0.5]), |
+ ) |
+ ) |
+ for d1, d2, _ in self.merge_triples: |
+ distribution.add_sample(_LOW_SAMPLE, d1) |
+ distribution.add_sample(_HIGH_SAMPLE, d2) |
+ |
+ def test_should_fail_on_dissimilar_bucket_options(self): |
+ explicit = _make_explicit_dist() |
+ linear = _make_linear_dist() |
+ exponential = _make_exponential_dist() |
+ pairs = ( |
+ (explicit, linear), |
+ (explicit, exponential), |
+ (linear, exponential) |
+ ) |
+ for p in pairs: |
+ testf = lambda: distribution.merge(*p) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_fail_on_dissimilar_bucket_counts(self): |
+ for _, d2, d3 in self.merge_triples: |
+ testf = lambda: distribution.merge(d2, d3) |
+ expect(testf).to(raise_error(ValueError)) |
+ |
+ def test_should_merge_stats_correctly(self): |
+ # TODO(add a check of the variance) |
+ for d1, d2, _ in self.merge_triples: |
+ distribution.merge(d1, d2) |
+ expect(d2.count).to(equal(2)) |
+ expect(d2.mean).to(equal((_HIGH_SAMPLE + _LOW_SAMPLE) / 2)) |
+ expect(d2.maximum).to(equal(_HIGH_SAMPLE)) |
+ expect(d2.minimum).to(equal(_LOW_SAMPLE)) |
+ |
+ def test_should_merge_bucket_counts_correctly(self): |
+ for d1, d2, _ in self.merge_triples: |
+ d1_start = list(d1.bucketCounts) |
+ d2_start = list(d2.bucketCounts) |
+ want = [x + y for (x,y) in zip(d1_start, d2_start)] |
+ distribution.merge(d1, d2) |
+ expect(d2.bucketCounts).to(equal(want)) |