diff --git a/PKG-INFO b/PKG-INFO index a630e6b..4ae904a 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: swh.core -Version: 0.0.36 +Version: 0.0.37 Summary: Software Heritage core utilities Home-page: https://forge.softwareheritage.org/diffusion/DCORE/ Author: Software Heritage developers Author-email: swh-devel@inria.fr License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN diff --git a/bin/swh-hashdir b/bin/swh-hashdir deleted file mode 100755 index f3f30cc..0000000 --- a/bin/swh-hashdir +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/python3 - -# Copyright (C) 2015 The Software Heritage developers -# See the AUTHORS file at the top-level directory of this distribution -# License: GNU General Public License version 3, or any later version -# See top-level LICENSE file for more information - -import os -import sys - -from swh.core.hashutil import hashfile, hash_to_hex - -if __name__ == '__main__': - dirname = sys.argv[1] - - hashes = {} - for root, _dirs, files in os.walk(dirname): - for name in files: - path = os.path.join(root, name) - hashes[path] = { - algo: hash_to_hex(checksum) - for algo, checksum in hashfile(path).items() - } - hashes[path]['length'] = os.path.getsize(path) - - for (path, checksums) in hashes.items(): - print("\\\\x%(sha1)s\t\\\\x%(sha1_git)s\t\\\\x%(sha256)s\t%(length)d\tvisible" % # NOQA - checksums) diff --git a/bin/swh-hashfile b/bin/swh-hashfile deleted file mode 100755 index d7692aa..0000000 --- a/bin/swh-hashfile +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/python3 - -# Copyright (C) 2015 The Software Heritage developers -# See the AUTHORS file at the top-level directory of this distribution -# License: GNU General Public License version 3, or any later version -# See top-level LICENSE file for more information - -import sys - -from swh.core.hashutil import hashfile, hash_to_hex - -if __name__ == '__main__': - fname = sys.argv[1] - for (algo, checksum) in sorted(hashfile(fname).items()): - print('%s\t%s' % (algo, hash_to_hex(checksum))) diff --git a/setup.py b/setup.py index 5b6c3ef..8b2024c 100644 --- a/setup.py +++ b/setup.py @@ -1,30 +1,30 @@ #!/usr/bin/env python3 from setuptools import setup, find_packages def parse_requirements(): requirements = [] for reqf in ('requirements.txt', 'requirements-swh.txt'): with open(reqf) as f: for line in f.readlines(): line = line.strip() if not line or line.startswith('#'): continue requirements.append(line) return requirements setup( name='swh.core', description='Software Heritage core utilities', author='Software Heritage developers', author_email='swh-devel@inria.fr', url='https://forge.softwareheritage.org/diffusion/DCORE/', packages=find_packages(), - scripts=['bin/swh-hashdir', 'bin/swh-hashfile'], + scripts=[], install_requires=parse_requirements(), setup_requires=['vcversioner'], vcversioner={}, include_package_data=True, ) diff --git a/swh.core.egg-info/PKG-INFO b/swh.core.egg-info/PKG-INFO index a630e6b..4ae904a 100644 --- a/swh.core.egg-info/PKG-INFO +++ b/swh.core.egg-info/PKG-INFO @@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: swh.core -Version: 0.0.36 +Version: 0.0.37 Summary: Software Heritage core utilities Home-page: https://forge.softwareheritage.org/diffusion/DCORE/ Author: Software Heritage developers Author-email: swh-devel@inria.fr License: UNKNOWN Description: UNKNOWN Platform: UNKNOWN diff --git a/swh.core.egg-info/SOURCES.txt b/swh.core.egg-info/SOURCES.txt index fd3b0f2..0e8546e 100644 --- a/swh.core.egg-info/SOURCES.txt +++ b/swh.core.egg-info/SOURCES.txt @@ -1,44 +1,43 @@ .gitignore AUTHORS LICENSE MANIFEST.in Makefile README.md requirements-swh.txt requirements.txt setup.py version.txt -bin/swh-hashdir -bin/swh-hashfile debian/changelog debian/compat debian/control debian/copyright debian/rules debian/source/format docs/.gitignore docs/Makefile docs/conf.py docs/index.rst docs/_static/.placeholder docs/_templates/.placeholder sql/log-schema.sql swh/__init__.py swh.core.egg-info/PKG-INFO swh.core.egg-info/SOURCES.txt swh.core.egg-info/dependency_links.txt swh.core.egg-info/requires.txt swh.core.egg-info/top_level.txt swh/core/__init__.py swh/core/api.py swh/core/api_async.py swh/core/config.py swh/core/logger.py swh/core/serializers.py swh/core/tarball.py swh/core/utils.py swh/core/tests/db_testing.py +swh/core/tests/server_testing.py swh/core/tests/test_config.py swh/core/tests/test_logger.py swh/core/tests/test_serializers.py swh/core/tests/test_utils.py \ No newline at end of file diff --git a/swh/core/tests/server_testing.py b/swh/core/tests/server_testing.py new file mode 100644 index 0000000..e801a3e --- /dev/null +++ b/swh/core/tests/server_testing.py @@ -0,0 +1,146 @@ +# Copyright (C) 2015-2018 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +import abc +import aiohttp +import multiprocessing +import socket +import time + +from urllib.request import urlopen + + +class ServerTestFixtureBaseClass(metaclass=abc.ABCMeta): + """Base class for http client/server testing implementations. + + Override this class to implement the following methods: + - process_config: to do something needed for the server + configuration (e.g propagate the configuration to other part) + - define_worker_function: define the function that will actually + run the server. + + To ensure test isolation, each test will run in a different server + and a different folder. + + In order to correctly work, the subclass must call the parents + class's setUp() and tearDown() methods. + + """ + def setUp(self): + super().setUp() + self.start_server() + + def tearDown(self): + self.stop_server() + super().tearDown() + + def url(self): + return 'http://127.0.0.1:%d/' % self.port + + def process_config(self): + """Process the server's configuration. Do something useful for + example, pass along the self.config dictionary inside the + self.app. + + By default, do nothing. + + """ + pass + + @abc.abstractmethod + def define_worker_function(self, app, port): + """Define how the actual implementation server will run. + + """ + pass + + def start_server(self): + """ Spawn the API server using multiprocessing. + """ + self.process = None + + self.process_config() + + # Get an available port number + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.bind(('127.0.0.1', 0)) + self.port = sock.getsockname()[1] + sock.close() + + worker_fn = self.define_worker_function() + + self.process = multiprocessing.Process( + target=worker_fn, args=(self.app, self.port) + ) + self.process.start() + + # Wait max 5 seconds for server to spawn + i = 0 + while i < 500: + try: + urlopen(self.url()) + except Exception: + i += 1 + time.sleep(0.01) + else: + return + + def stop_server(self): + """ Terminate the API server's process. + """ + if self.process: + self.process.terminate() + + +class ServerTestFixture(ServerTestFixtureBaseClass): + """Base class for http client/server testing (e.g flask). + + Mix this in a test class in order to have access to an http server + running in background. + + Note that the subclass should define a dictionary in self.config + that contains the server config. And an application in self.app + that corresponds to the type of server the tested client needs. + + To ensure test isolation, each test will run in a different server + and a different folder. + + In order to correctly work, the subclass must call the parents + class's setUp() and tearDown() methods. + """ + def process_config(self): + # WSGI app configuration + for key, value in self.config.items(): + self.app.config[key] = value + + def define_worker_function(self): + def worker(app, port): + return app.run(port=port, use_reloader=False) + + return worker + + +class ServerTestFixtureAsync(ServerTestFixtureBaseClass): + """Base class for http client/server async testing (e.g aiohttp). + + Mix this in a test class in order to have access to an http server + running in background. + + Note that the subclass should define an application in self.app + that corresponds to the type of server the tested client needs. + + To ensure test isolation, each test will run in a different server + and a different folder. + + In order to correctly work, the subclass must call the parents + class's setUp() and tearDown() methods. + + """ + def define_worker_function(self): + def worker(app, port): + return aiohttp.web.run_app(app, port=int(port), + print=lambda *_: None) + + return worker diff --git a/version.txt b/version.txt index 64c0eae..6cf8d66 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v0.0.36-0-g141d1a3 \ No newline at end of file +v0.0.37-0-g5de410e \ No newline at end of file