From 3e29cb9ea201492c8573763b1f899bc4f809c3eb Mon Sep 17 00:00:00 2001 From: Ilya Shakhat Date: Tue, 10 Sep 2013 15:12:28 +0400 Subject: [PATCH] make_range function is fixed and properly tested Fixes bug 1223293 Change-Id: I9c285be69cfa3e021cec418e5d794328b6066732 --- stackalytics/processor/runtime_storage.py | 14 +++----- stackalytics/processor/utils.py | 8 +++++ tests/unit/test_utils.py | 44 +++++++++++++++++++++++ 3 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 tests/unit/test_utils.py diff --git a/stackalytics/processor/runtime_storage.py b/stackalytics/processor/runtime_storage.py index 7a044cbf9..f714ba3eb 100644 --- a/stackalytics/processor/runtime_storage.py +++ b/stackalytics/processor/runtime_storage.py @@ -18,6 +18,7 @@ import re import memcache from stackalytics.openstack.common import log as logging +from stackalytics.processor import utils LOG = logging.getLogger(__name__) @@ -131,7 +132,7 @@ class MemcachedStorage(RuntimeStorage): for i in self.get_all_records(): yield i else: - for update_id_set in self._make_range(last_update, update_count, + for update_id_set in utils.make_range(last_update, update_count, BULK_READ_SIZE): update_set = self.memcached.get_multi( update_id_set, UPDATE_ID_PREFIX).values() @@ -156,7 +157,7 @@ class MemcachedStorage(RuntimeStorage): min_update = n first_valid_update = self.memcached.get('first_valid_update') or 0 - for delete_id_set in self._make_range(first_valid_update, min_update, + for delete_id_set in utils.make_range(first_valid_update, min_update, BULK_DELETE_SIZE): if not self.memcached.delete_multi(delete_id_set, key_prefix=UPDATE_ID_PREFIX): @@ -182,15 +183,8 @@ class MemcachedStorage(RuntimeStorage): def _set_record_count(self, count): self.memcached.set('record:count', count) - def _make_range(self, start, stop, step): - i = start - for i in xrange(start, stop, step): - yield xrange(i, i + step) - if (stop - start) % step > 0: - yield xrange(i, stop) - def get_all_records(self): - for record_id_set in self._make_range(0, self._get_record_count(), + for record_id_set in utils.make_range(0, self._get_record_count(), BULK_READ_SIZE): for i in self.memcached.get_multi( record_id_set, RECORD_ID_PREFIX).values(): diff --git a/stackalytics/processor/utils.py b/stackalytics/processor/utils.py index cc871c5ea..90ceeba87 100644 --- a/stackalytics/processor/utils.py +++ b/stackalytics/processor/utils.py @@ -52,6 +52,14 @@ def read_json_from_uri(uri): LOG.warn('Error while reading uri: %s' % e) +def make_range(start, stop, step): + last_full = stop - ((stop - start) % step) + for i in xrange(start, last_full, step): + yield xrange(i, i + step) + if stop > last_full: + yield xrange(last_full, stop) + + def store_user(runtime_storage_inst, user): runtime_storage_inst.set_by_key('user:%s' % user['user_id'], user) diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py new file mode 100644 index 000000000..4b42ac6ef --- /dev/null +++ b/tests/unit/test_utils.py @@ -0,0 +1,44 @@ +# Copyright (c) 2013 Mirantis Inc. +# +# 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. + +import testtools + +from stackalytics.processor import utils + + +class TestUtils(testtools.TestCase): + def setUp(self): + super(TestUtils, self).setUp() + + def _test_one_range(self, start, end, step): + elements = set() + for chunk in utils.make_range(start, end, step): + for item in chunk: + self.assertFalse(item in elements) + elements.add(item) + + self.assertTrue(set(range(start, end)) == elements) + + def test_make_range_0_10_1(self): + self._test_one_range(0, 10, 1) + + def test_make_range_0_10_3(self): + self._test_one_range(0, 10, 3) + + def test_make_range_3_5_4(self): + self._test_one_range(3, 5, 4) + + def test_make_range_5_26_10(self): + self._test_one_range(5, 26, 10)