From bd5a5b58b438ff34d27781e28cd7fab93bfc9f3f Mon Sep 17 00:00:00 2001 From: Maximilian Bosch Date: Sat, 9 Mar 2019 23:26:30 +0100 Subject: [PATCH] Don't use `which` implementation to find required executables Nix specific patch. Rather than relying on a global state, we set an absolute store path for all external dependencies to ensure their functionality. --- integration_tests/__init__.py | 4 ++-- tests/engines/test_gif.py | 2 +- tests/handlers/test_base_handler.py | 30 ++++++++++++++--------------- tests/optimizers/test_gifv.py | 2 +- tests/test_server.py | 4 ++++ tests/test_utils.py | 3 +++ thumbor/server.py | 7 +------ 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/integration_tests/__init__.py b/integration_tests/__init__.py index 9bdd0a3..7d9de8f 100644 --- a/integration_tests/__init__.py +++ b/integration_tests/__init__.py @@ -15,7 +15,7 @@ class EngineCase(AsyncHTTPTestCase): def get_app(self): cfg = Config(SECURITY_KEY='ACME-SEC') server_params = ServerParameters(None, None, None, None, None, None) - server_params.gifsicle_path = which('gifsicle') + server_params.gifsicle_path = '@gifsicle@' cfg.DETECTORS = [ 'thumbor.detectors.face_detector', @@ -28,7 +28,7 @@ class EngineCase(AsyncHTTPTestCase): cfg.FILE_LOADER_ROOT_PATH = os.path.join(os.path.dirname(__file__), 'imgs') cfg.ENGINE = getattr(self, 'engine', None) cfg.USE_GIFSICLE_ENGINE = True - cfg.FFMPEG_PATH = which('ffmpeg') + cfg.FFMPEG_PATH = '@ffmpeg@' cfg.ENGINE_THREADPOOL_SIZE = 10 cfg.OPTIMIZERS = [ 'thumbor.optimizers.gifv', diff --git a/tests/engines/test_gif.py b/tests/engines/test_gif.py index c0c8430..ce0cc51 100644 --- a/tests/engines/test_gif.py +++ b/tests/engines/test_gif.py @@ -44,7 +44,7 @@ class GitEngineTestCase(TestCase): def get_server(self): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' - server.gifsicle_path = which('gifsicle') + server.gifsicle_path = '@gifsicle@' return server def get_context(self, *args, **kwargs): diff --git a/tests/handlers/test_base_handler.py b/tests/handlers/test_base_handler.py index 69dc110..4493abe 100644 --- a/tests/handlers/test_base_handler.py +++ b/tests/handlers/test_base_handler.py @@ -557,7 +557,7 @@ class ImageOperationsWithAutoWebPTestCase(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx def get_as_webp(self, url): @@ -657,7 +657,7 @@ class ImageOperationsWithAutoWebPWithResultStorageTestCase(BaseImagingTestCase): server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) ctx.request = self.get_request() - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx @property @@ -783,7 +783,7 @@ class ImageOperationsWithGifVTestCase(BaseImagingTestCase): cfg = Config(SECURITY_KEY='ACME-SEC') cfg.LOADER = "thumbor.loaders.file_loader" cfg.FILE_LOADER_ROOT_PATH = self.loader_path - cfg.FFMPEG_PATH = which('ffmpeg') + cfg.FFMPEG_PATH = '@ffmpeg@' cfg.OPTIMIZERS = [ 'thumbor.optimizers.gifv', ] @@ -793,7 +793,7 @@ class ImageOperationsWithGifVTestCase(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx def test_should_convert_animated_gif_to_mp4_when_filter_without_params(self): @@ -828,7 +828,7 @@ class ImageOperationsImageCoverTestCase(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx def test_can_get_image_cover(self): @@ -849,7 +849,7 @@ class ImageOperationsWithResultStorageTestCase(BaseImagingTestCase): cfg.RESULT_STORAGE_FILE_STORAGE_ROOT_PATH = self.root_path cfg.USE_GIFSICLE_ENGINE = True - cfg.FFMPEG_PATH = which('ffmpeg') + cfg.FFMPEG_PATH = '@ffmpeg@' cfg.AUTO_WEBP = True cfg.OPTIMIZERS = [ 'thumbor.optimizers.gifv', @@ -860,7 +860,7 @@ class ImageOperationsWithResultStorageTestCase(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx @@ -891,7 +891,7 @@ class ImageOperationsResultStorageOnlyTestCase(BaseImagingTestCase): cfg.RESULT_STORAGE = 'thumbor.result_storages.file_storage' cfg.RESULT_STORAGE_EXPIRATION_SECONDS = 60 cfg.RESULT_STORAGE_FILE_STORAGE_ROOT_PATH = self.root_path - cfg.FFMPEG_PATH = which('ffmpeg') + cfg.FFMPEG_PATH = '@ffmpeg@' cfg.USE_GIFSICLE_ENGINE = True cfg.AUTO_WEBP = True @@ -904,7 +904,7 @@ class ImageOperationsResultStorageOnlyTestCase(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx @@ -1040,7 +1040,7 @@ class ImageOperationsWithMaxPixels(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx def test_should_error(self): @@ -1061,7 +1061,7 @@ class ImageOperationsWithRespectOrientation(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' self.context = Context(server, cfg, importer) - self.context.server.gifsicle_path = which('gifsicle') + self.context.server.gifsicle_path = '@gifsicle@' return self.context def test_should_be_ok_when_orientation_exif(self): @@ -1153,7 +1153,7 @@ class ImageOperationsWithJpegtranTestCase(BaseImagingTestCase): cfg = Config(SECURITY_KEY='ACME-SEC') cfg.LOADER = "thumbor.loaders.file_loader" cfg.FILE_LOADER_ROOT_PATH = self.loader_path - cfg.JPEGTRAN_PATH = which('jpegtran') + cfg.JPEGTRAN_PATH = '@jpegtran@' cfg.PROGRESSIVE_JPEG = True, cfg.RESULT_STORAGE_STORES_UNSAFE = True, cfg.OPTIMIZERS = [ @@ -1175,9 +1175,7 @@ class ImageOperationsWithJpegtranTestCase(BaseImagingTestCase): f.write(response.body) f.close() - exiftool = which('exiftool') - if not exiftool: - raise AssertionError('exiftool was not found. Please install it to run thumbor\'s tests.') + exiftool = '@exiftool@' command = [ exiftool, @@ -1221,7 +1219,7 @@ class ImageOperationsWithoutStorage(BaseImagingTestCase): server = ServerParameters(8889, 'localhost', 'thumbor.conf', None, 'info', None) server.security_key = 'ACME-SEC' ctx = Context(server, cfg, importer) - ctx.server.gifsicle_path = which('gifsicle') + ctx.server.gifsicle_path = '@gifsicle@' return ctx def test_meta(self): diff --git a/tests/optimizers/test_gifv.py b/tests/optimizers/test_gifv.py index 229e9cd..066f2d5 100644 --- a/tests/optimizers/test_gifv.py +++ b/tests/optimizers/test_gifv.py @@ -31,7 +31,7 @@ class GifvOptimizerTest(TestCase): def get_context(self): conf = Config() conf.STATSD_HOST = '' - conf.FFMPEG_PATH = which('ffmpeg') + conf.FFMPEG_PATH = '@ffmpeg@' ctx = Context(config=conf) ctx.request = RequestParameters() ctx.request.filters.append('gifv') diff --git a/tests/test_server.py b/tests/test_server.py index 5b31750..c2a65dc 100644 --- a/tests/test_server.py +++ b/tests/test_server.py @@ -11,6 +11,8 @@ from unittest import TestCase import mock +from nose.tools import nottest + from preggy import expect from thumbor.app import ThumborServiceApp @@ -118,6 +120,7 @@ class ServerTestCase(TestCase): expect(server_parameters.security_key).to_equal('something') @mock.patch.object(thumbor.server, 'which') + @nottest def test_validate_gifsicle_path(self, which_mock): server_parameters = mock.Mock(security_key=None) conf = Config(SECURITY_KEY='test', USE_GIFSICLE_ENGINE=True) @@ -128,6 +131,7 @@ class ServerTestCase(TestCase): expect(server_parameters.gifsicle_path).to_equal('/usr/bin/gifsicle') @mock.patch.object(thumbor.server, 'which') + @nottest def test_validate_null_gifsicle_path(self, which_mock): server_parameters = mock.Mock(security_key=None) conf = Config(SECURITY_KEY='test', USE_GIFSICLE_ENGINE=True) diff --git a/tests/test_utils.py b/tests/test_utils.py index 38cd51b..7dd0b3e 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -10,6 +10,7 @@ from mock import Mock, patch from unittest import TestCase +from nose.tools import nottest import logging from preggy import expect @@ -112,6 +113,7 @@ class UtilsTestCase(TestCase): test_func() mock_warn.assert_called_once_with('Deprecated function test_func: func2') + @nottest def test_can_which_by_path(self): result = which('/bin/ls') expect(result).to_equal('/bin/ls') @@ -119,6 +121,7 @@ class UtilsTestCase(TestCase): result = which('/tmp') expect(result).to_be_null() + @nottest def test_can_which_by_env(self): result = which('ls') expect(result).to_equal('/bin/ls') diff --git a/thumbor/server.py b/thumbor/server.py index c75a769..821163b 100644 --- a/thumbor/server.py +++ b/thumbor/server.py @@ -89,12 +89,7 @@ def validate_config(config, server_parameters): warnings.simplefilter('error', Image.DecompressionBombWarning) if config.USE_GIFSICLE_ENGINE: - server_parameters.gifsicle_path = which('gifsicle') - if server_parameters.gifsicle_path is None: - raise RuntimeError( - 'If using USE_GIFSICLE_ENGINE configuration to True, the `gifsicle` binary must be in the PATH ' - 'and must be an executable.' - ) + server_parameters.gifsicle_path = '@gifsicle@' def get_context(server_parameters, config, importer): -- 2.18.1