# Copyright (c) 2010-2011 OpenStack, LLC. # # 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 datetime import datetime import logging import os import random from slogging import log_uploader import string from test.unit import temptree import unittest logging.basicConfig(level=logging.DEBUG) LOGGER = logging.getLogger() COMPRESSED_DATA = '\x1f\x8b\x08\x08\x87\xa5zM\x02\xffdata\x00KI,I\x04\x00c' \ '\xf3\xf3\xad\x04\x00\x00\x00' PROXY_SERVER_CONF = os.environ.get('SWIFT_PROXY_TEST_CONFIG_FILE', '/etc/swift/proxy-server.conf') access_regex = ''' ^ (?P[0-9]{4}) (?P[0-1][0-9]) (?P[0-3][0-9]) (?P[0-2][0-9]) .*$ ''' def mock_appconfig(*args, **kwargs): pass class MockInternalProxy(object): def __init__(self, *args, **kwargs): pass def create_container(self, *args, **kwargs): return True def upload_file(self, *args, **kwargs): return True _orig_LogUploader = log_uploader.LogUploader class MockLogUploader(_orig_LogUploader): def __init__(self, conf, logger=LOGGER): conf['swift_account'] = conf.get('swift_account', '') conf['container_name'] = conf.get('container_name', '') conf['new_log_cutoff'] = conf.get('new_log_cutoff', '0') conf['source_filename_format'] = conf.get( 'source_filename_format', conf.get('filename_format')) log_uploader.LogUploader.__init__(self, conf, 'plugin') self.logger = logger self.uploaded_files = [] def upload_one_log(self, filename, year, month, day, hour): d = {'year': year, 'month': month, 'day': day, 'hour': hour} self.uploaded_files.append((filename, d)) _orig_LogUploader.upload_one_log(self, filename, year, month, day, hour) class ErrorLogUploader(MockLogUploader): def upload_one_log(self, filename, year, month, day, hour): raise OSError('foo bar') class TestLogUploader(unittest.TestCase): def setUp(self): # mock internal proxy self._orig_InternalProxy = log_uploader.InternalProxy self._orig_appconfig = log_uploader.appconfig log_uploader.InternalProxy = MockInternalProxy log_uploader.appconfig = mock_appconfig def tearDown(self): log_uploader.appconfig = self._orig_appconfig log_uploader.InternalProxy = self._orig_InternalProxy def test_bad_upload(self): files = [datetime.now().strftime('%Y%m%d%H')] with temptree(files, contents=[COMPRESSED_DATA] * len(files)) as t: # invalid pattern conf = {'log_dir': t, 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': '%Y%m%d%h'} # should be %H uploader = MockLogUploader(conf) self.assertRaises(SystemExit, uploader.upload_all_logs) conf = {'log_dir': t, 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = ErrorLogUploader(conf) # this tests if the exception is handled uploader.upload_all_logs() def test_bad_pattern_in_config(self): files = [datetime.now().strftime('%Y%m%d%H')] with temptree(files, contents=[COMPRESSED_DATA] * len(files)) as t: # invalid pattern conf = {'log_dir': t, 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': '%Y%m%d%h'} # should be %H uploader = MockLogUploader(conf) self.assertRaises(SystemExit, uploader.upload_all_logs) conf = {'log_dir': t, 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = MockLogUploader(conf) uploader.upload_all_logs() self.assertEqual(len(uploader.uploaded_files), 1) def test_pattern_upload_all_logs(self): # test empty dir with temptree([]) as t: conf = {'log_dir': t, 'proxy_server_conf': PROXY_SERVER_CONF} uploader = MockLogUploader(conf) self.assertRaises(SystemExit, uploader.run_once) def get_random_length_str(max_len=10, chars=string.ascii_letters): return ''.join(random.choice(chars) for x in range(random.randint(1, max_len))) template = 'prefix_%(random)s_%(digits)s.blah.' \ '%(datestr)s%(hour)0.2d00-%(next_hour)0.2d00-%(number)s.gz' pattern = '''prefix_.*_[0-9]+\.blah\. (?P[0-9]{4}) (?P[0-1][0-9]) (?P[0-3][0-9]) (?P[0-2][0-9])00-[0-9]{2}00 -[0-9]?[0-9]\.gz''' files_that_should_match = [] # add some files that match for i in range(24): fname = template % { 'random': get_random_length_str(), 'digits': get_random_length_str(16, string.digits), 'datestr': datetime.now().strftime('%Y%m%d'), 'hour': i, 'next_hour': i + 1, 'number': random.randint(0, 20), } files_that_should_match.append(fname) # add some files that don't match files = list(files_that_should_match) for i in range(24): fname = template % { 'random': get_random_length_str(), 'digits': get_random_length_str(16, string.digits), 'datestr': datetime.now().strftime('%Y%m'), 'hour': i, 'next_hour': i + 1, 'number': random.randint(0, 20), } files.append(fname) for fname in files: print(fname) with temptree(files, contents=[COMPRESSED_DATA] * len(files)) as t: self.assertEqual(len(os.listdir(t)), 48) conf = {'source_filename_pattern': pattern, 'proxy_server_conf': PROXY_SERVER_CONF, 'log_dir': t} uploader = MockLogUploader(conf) uploader.run_once() self.assertEqual(len(os.listdir(t)), 24) self.assertEqual(len(uploader.uploaded_files), 24) files_that_were_uploaded = set(x[0] for x in uploader.uploaded_files) for f in files_that_should_match: self.assertTrue( os.path.join(t, f) in files_that_were_uploaded) def test_log_cutoff(self): files = [datetime.now().strftime('%Y%m%d%H')] with temptree(files) as t: conf = {'log_dir': t, 'new_log_cutoff': '7200', 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = MockLogUploader(conf) uploader.run_once() self.assertEqual(len(uploader.uploaded_files), 0) conf = {'log_dir': t, 'new_log_cutoff': '0', 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = MockLogUploader(conf) uploader.run_once() self.assertEqual(len(uploader.uploaded_files), 1) def test_create_container_fail(self): files = [datetime.now().strftime('%Y%m%d%H')] conf = {'source_filename_pattern': access_regex, 'proxy_server_conf': PROXY_SERVER_CONF} with temptree(files) as t: conf['log_dir'] = t uploader = MockLogUploader(conf) uploader.run_once() self.assertEqual(len(uploader.uploaded_files), 1) with temptree(files) as t: conf['log_dir'] = t uploader = MockLogUploader(conf) # mock create_container to fail uploader.internal_proxy.create_container = lambda *args: False uploader.run_once() self.assertEqual(len(uploader.uploaded_files), 0) def test_unlink_log(self): files = [datetime.now().strftime('%Y%m%d%H')] with temptree(files, contents=[COMPRESSED_DATA]) as t: conf = {'log_dir': t, 'unlink_log': 'false', 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = MockLogUploader(conf) uploader.run_once() self.assertEqual(len(uploader.uploaded_files), 1) # file still there self.assertEqual(len(os.listdir(t)), 1) conf = {'log_dir': t, 'unlink_log': 'true', 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = MockLogUploader(conf) uploader.run_once() self.assertEqual(len(uploader.uploaded_files), 1) # file gone self.assertEqual(len(os.listdir(t)), 0) def test_upload_file_failed(self): files = ['plugin-%s' % datetime.now().strftime('%Y%m%d%H')] with temptree(files, contents=[COMPRESSED_DATA]) as t: conf = {'log_dir': t, 'unlink_log': 'true', 'proxy_server_conf': PROXY_SERVER_CONF, 'source_filename_pattern': access_regex} uploader = MockLogUploader(conf) # mock upload_file to fail, and clean up mock def mock_upload_file(self, *args, **kwargs): uploader.uploaded_files.pop() return False uploader.internal_proxy.upload_file = mock_upload_file self.assertRaises(SystemExit, uploader.run_once) # file still there self.assertEqual(len(os.listdir(t)), 1) if __name__ == '__main__': unittest.main()