261 lines
9.4 KiB
Python
261 lines
9.4 KiB
Python
# 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.
|
|
|
|
import unittest
|
|
import os
|
|
from datetime import datetime
|
|
from tempfile import mkdtemp
|
|
from shutil import rmtree
|
|
from functools import partial
|
|
from collections import defaultdict
|
|
import random
|
|
import string
|
|
|
|
from test.unit import temptree
|
|
from slogging import log_uploader
|
|
|
|
import logging
|
|
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'
|
|
|
|
access_regex = '''
|
|
^
|
|
(?P<year>[0-9]{4})
|
|
(?P<month>[0-1][0-9])
|
|
(?P<day>[0-3][0-9])
|
|
(?P<hour>[0-2][0-9])
|
|
.*$
|
|
'''
|
|
|
|
|
|
def mock_appconfig(*args, **kwargs):
|
|
pass
|
|
|
|
|
|
class MockInternalProxy():
|
|
|
|
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,
|
|
'source_filename_pattern': '%Y%m%d%h'} # should be %H
|
|
uploader = MockLogUploader(conf)
|
|
self.assertRaises(SystemExit, uploader.upload_all_logs)
|
|
|
|
conf = {'log_dir': t, '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,
|
|
'source_filename_pattern': '%Y%m%d%h'} # should be %H
|
|
uploader = MockLogUploader(conf)
|
|
self.assertRaises(SystemExit, uploader.upload_all_logs)
|
|
|
|
conf = {'log_dir': t, 'source_filename_pattern': access_regex}
|
|
uploader = MockLogUploader(conf)
|
|
uploader.upload_all_logs()
|
|
self.assertEquals(len(uploader.uploaded_files), 1)
|
|
|
|
def test_pattern_upload_all_logs(self):
|
|
|
|
# test empty dir
|
|
with temptree([]) as t:
|
|
conf = {'log_dir': t}
|
|
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<year>[0-9]{4})
|
|
(?P<month>[0-1][0-9])
|
|
(?P<day>[0-3][0-9])
|
|
(?P<hour>[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.assertEquals(len(os.listdir(t)), 48)
|
|
conf = {'source_filename_pattern': pattern, 'log_dir': t}
|
|
uploader = MockLogUploader(conf)
|
|
uploader.run_once()
|
|
self.assertEquals(len(os.listdir(t)), 24)
|
|
self.assertEquals(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.assert_(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',
|
|
'source_filename_pattern': access_regex}
|
|
uploader = MockLogUploader(conf)
|
|
uploader.run_once()
|
|
self.assertEquals(len(uploader.uploaded_files), 0)
|
|
conf = {'log_dir': t, 'new_log_cutoff': '0',
|
|
'source_filename_pattern': access_regex}
|
|
uploader = MockLogUploader(conf)
|
|
uploader.run_once()
|
|
self.assertEquals(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}
|
|
with temptree(files) as t:
|
|
conf['log_dir'] = t
|
|
uploader = MockLogUploader(conf)
|
|
uploader.run_once()
|
|
self.assertEquals(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.assertEquals(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',
|
|
'source_filename_pattern': access_regex}
|
|
uploader = MockLogUploader(conf)
|
|
uploader.run_once()
|
|
self.assertEquals(len(uploader.uploaded_files), 1)
|
|
# file still there
|
|
self.assertEquals(len(os.listdir(t)), 1)
|
|
|
|
conf = {'log_dir': t, 'unlink_log': 'true',
|
|
'source_filename_pattern': access_regex}
|
|
uploader = MockLogUploader(conf)
|
|
uploader.run_once()
|
|
self.assertEquals(len(uploader.uploaded_files), 1)
|
|
# file gone
|
|
self.assertEquals(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',
|
|
'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.assertEquals(len(os.listdir(t)), 1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|