diff --git a/compressor/management/commands/mtime_cache.py b/compressor/management/commands/mtime_cache.py index b1605ba..afd2390 100644 --- a/compressor/management/commands/mtime_cache.py +++ b/compressor/management/commands/mtime_cache.py @@ -1,6 +1,5 @@ import fnmatch import os -from optparse import make_option from django.core.management.base import BaseCommand, CommandError @@ -10,25 +9,30 @@ from compressor.cache import cache, get_mtime, get_mtime_cachekey class Command(BaseCommand): help = "Add or remove all mtime values from the cache" - option_list = BaseCommand.option_list + ( - make_option('-i', '--ignore', action='append', default=[], + + def add_arguments(self, parser): + parser.add_argument( + '-i', '--ignore', action='append', default=[], dest='ignore_patterns', metavar='PATTERN', help="Ignore files or directories matching this glob-style " - "pattern. Use multiple times to ignore more."), - make_option('--no-default-ignore', action='store_false', + "pattern. Use multiple times to ignore more."), + parser.add_argument( + '--no-default-ignore', action='store_false', dest='use_default_ignore_patterns', default=True, help="Don't ignore the common private glob-style patterns 'CVS', " - "'.*' and '*~'."), - make_option('--follow-links', dest='follow_links', action='store_true', + "'.*' and '*~'."), + parser.add_argument( + '--follow-links', dest='follow_links', action='store_true', help="Follow symlinks when traversing the COMPRESS_ROOT " - "(which defaults to STATIC_ROOT). Be aware that using this " - "can lead to infinite recursion if a link points to a parent " - "directory of itself."), - make_option('-c', '--clean', dest='clean', action='store_true', + "(which defaults to STATIC_ROOT). Be aware that using this " + "can lead to infinite recursion if a link points to a parent " + "directory of itself."), + parser.add_argument( + '-c', '--clean', dest='clean', action='store_true', help="Remove all items"), - make_option('-a', '--add', dest='add', action='store_true', + parser.add_argument( + '-a', '--add', dest='add', action='store_true', help="Add all items"), - ) def is_ignored(self, path): """ @@ -40,24 +44,27 @@ class Command(BaseCommand): return True return False - def handle_noargs(self, **options): + def handle(self, **options): ignore_patterns = options['ignore_patterns'] if options['use_default_ignore_patterns']: ignore_patterns += ['CVS', '.*', '*~'] options['ignore_patterns'] = ignore_patterns self.ignore_patterns = ignore_patterns - if (options['add'] and options['clean']) or (not options['add'] and not options['clean']): + if ((options['add'] and options['clean']) or + (not options['add'] and not options['clean'])): raise CommandError('Please specify either "--add" or "--clean"') if not settings.COMPRESS_MTIME_DELAY: - raise CommandError('mtime caching is currently disabled. Please ' + raise CommandError( + 'mtime caching is currently disabled. Please ' 'set the COMPRESS_MTIME_DELAY setting to a number of seconds.') files_to_add = set() keys_to_delete = set() - for root, dirs, files in os.walk(settings.COMPRESS_ROOT, followlinks=options['follow_links']): + for root, dirs, files in os.walk(settings.COMPRESS_ROOT, + followlinks=options['follow_links']): for dir_ in dirs: if self.is_ignored(dir_): dirs.remove(dir_) @@ -74,9 +81,11 @@ class Command(BaseCommand): if keys_to_delete: cache.delete_many(list(keys_to_delete)) - print("Deleted mtimes of %d files from the cache." % len(keys_to_delete)) + self.stdout.write("Deleted mtimes of %d files from the cache." + % len(keys_to_delete)) if files_to_add: for filename in files_to_add: get_mtime(filename) - print("Added mtimes of %d files to cache." % len(files_to_add)) + self.stdout.write("Added mtimes of %d files to cache." + % len(files_to_add)) diff --git a/compressor/tests/test_mtime_cache.py b/compressor/tests/test_mtime_cache.py new file mode 100644 index 0000000..fd0006c --- /dev/null +++ b/compressor/tests/test_mtime_cache.py @@ -0,0 +1,37 @@ +from django.core.management import call_command +from django.core.management.base import CommandError +from django.test import TestCase +from django.utils.six import StringIO + + +class TestMtimeCacheCommand(TestCase): + # FIXME: add actual tests, improve the existing ones. + + exclusion_patterns = [ + '*CACHE*', '*custom*', '*066cd253eada.js', 'test.txt*' + ] + + def default_ignore(self): + return ['--ignore=%s' % pattern for pattern in self.exclusion_patterns] + + def test_handle_no_args(self): + with self.assertRaises(CommandError): + call_command('mtime_cache') + + def test_handle_add(self): + out = StringIO() + with self.settings(CACHES={}): + call_command( + 'mtime_cache', '--add', *self.default_ignore(), stdout=out) + output = out.getvalue() + self.assertIn('Deleted mtimes of 19 files from the cache.', output) + self.assertIn('Added mtimes of 19 files to cache.', output) + + def test_handle_clean(self): + out = StringIO() + with self.settings(CACHES={}): + call_command( + 'mtime_cache', '--clean', *self.default_ignore(), stdout=out) + output = out.getvalue() + self.assertIn('Deleted mtimes of 19 files from the cache.', output) + self.assertNotIn('Added mtimes of 19 files to cache.', output) diff --git a/compressor/tests/test_offline.py b/compressor/tests/test_offline.py index 14397b3..1c1305a 100644 --- a/compressor/tests/test_offline.py +++ b/compressor/tests/test_offline.py @@ -5,6 +5,8 @@ import sys import unittest from importlib import import_module +from mock import patch + import django from django.core.management.base import CommandError from django.template import Template, Context @@ -171,6 +173,31 @@ class OfflineCompressBasicTestCase(OfflineTestCaseMixin, TestCase): templates_dir = 'basic' expected_hash = 'f5e179b8eca4' + @patch.object(CompressCommand, 'compress') + def test_handle_no_args(self, compress_mock): + CompressCommand().handle() + self.assertEqual(compress_mock.call_count, 1) + + @patch.object(CompressCommand, 'compress') + def test_handle_compress_disabled(self, compress_mock): + with self.settings(COMPRESS_ENABLED=False): + with self.assertRaises(CommandError): + CompressCommand().handle() + self.assertEqual(compress_mock.call_count, 0) + + @patch.object(CompressCommand, 'compress') + def test_handle_compress_offline_disabled(self, compress_mock): + with self.settings(COMPRESS_OFFLINE=False): + with self.assertRaises(CommandError): + CompressCommand().handle() + self.assertEqual(compress_mock.call_count, 0) + + @patch.object(CompressCommand, 'compress') + def test_handle_compress_offline_disabled_force(self, compress_mock): + with self.settings(COMPRESS_OFFLINE=False): + CompressCommand().handle(force=True) + self.assertEqual(compress_mock.call_count, 1) + def test_rendering_without_manifest_raises_exception(self): # flush cached manifest flush_offline_manifest()