diff --git a/glance/tests/unit/test_test_utils.py b/glance/tests/unit/test_test_utils.py new file mode 100644 index 0000000000..740e8cc678 --- /dev/null +++ b/glance/tests/unit/test_test_utils.py @@ -0,0 +1,37 @@ +# Copyright 2020 Red Hat, 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 glance.tests import utils as test_utils + + +class TestFakeData(test_utils.BaseTestCase): + def test_via_read(self): + fd = test_utils.FakeData(1024) + data = [] + for i in range(0, 1025, 256): + chunk = fd.read(256) + data.append(chunk) + if not chunk: + break + + self.assertEqual(5, len(data)) + # Make sure we got a zero-length final read + self.assertEqual(b'', data[-1]) + # Make sure we only got 1024 bytes + self.assertEqual(1024, len(b''.join(data))) + + def test_via_iter(self): + data = b''.join(list(test_utils.FakeData(1024))) + self.assertEqual(1024, len(data)) diff --git a/glance/tests/utils.py b/glance/tests/utils.py index f267226c53..3e697bfe97 100644 --- a/glance/tests/utils.py +++ b/glance/tests/utils.py @@ -32,6 +32,7 @@ from oslo_config import cfg from oslo_config import fixture as cfg_fixture from oslo_log.fixture import logging_error as log_fixture from oslo_log import log +from oslo_utils import units import six from six.moves import BaseHTTPServer from six.moves import http_client as http @@ -690,3 +691,44 @@ def start_standalone_http_server(): thread.start() return thread, httpd, port + + +class FakeData(object): + """Generate a bunch of data without storing it in memory. + + This acts like a read-only file object which generates fake data + in chunks when read() is called or it is used as a generator. It + can generate an arbitrary amount of data without storing it in + memory. + + :param length: The number of bytes to generate + :param chunk_size: The chunk size to return in iteration mode, or when + read() is called unbounded + + """ + def __init__(self, length, chunk_size=64 * units.Ki): + self._max = length + self._chunk_size = chunk_size + self._len = 0 + + def read(self, length=None): + if length is None: + length = self._chunk_size + + length = min(length, self._max - self._len) + + self._len += length + if length == 0: + return b'' + else: + return b'0' * length + + def __iter__(self): + return self + + def __next__(self): + r = self.read() + if len(r) == 0: + raise StopIteration() + else: + return r