1
# Copyright (c) 2010, 2011, Canonical Ltd
3
# This program is free software: you can redistribute it and/or modify
4
# it under the terms of the GNU Affero General Public License as published by
5
# the Free Software Foundation, either version 3 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU Affero General Public License for more details.
13
# You should have received a copy of the GNU Affero General Public License
14
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15
# GNU Affero General Public License version 3 (see the file LICENSE).
17
"""Tests for the unique file naming facility."""
25
from fixtures import TempDir
29
from oops.uniquefileallocator import UniqueFileAllocator
32
UTC = pytz.timezone('UTC')
35
class TestUniqueFileAllocator(testtools.TestCase):
38
super(TestUniqueFileAllocator, self).setUp()
39
tempdir = self.useFixture(TempDir())
40
self._tempdir = tempdir.path
42
def test_setToken(self):
43
namer = UniqueFileAllocator("/any-old/path/", 'OOPS', 'T')
44
self.assertEqual('T', namer.get_log_infix())
46
# Some scripts will append a string token to the prefix.
48
self.assertEqual('TCW', namer.get_log_infix())
50
# Some scripts run multiple processes and append a string number
53
self.assertEqual('T1', namer.get_log_infix())
55
def assertUniqueFileAllocator(self, namer, now, expected_id,
56
expected_last_id, expected_suffix, expected_lastdir):
57
logid, filename = namer.newId(now)
58
self.assertEqual(logid, expected_id)
59
self.assertEqual(filename,
60
os.path.join(namer._output_root, expected_suffix))
61
self.assertEqual(namer._last_serial, expected_last_id)
62
self.assertEqual(namer._last_output_dir,
63
os.path.join(namer._output_root, expected_lastdir))
66
# TODO: This should return an id, fileobj instead of a file name, to
67
# reduce races with threads that are slow to use what they asked for,
68
# when combined with configuration changes causing disk scans. That
69
# would also permit using a completely stubbed out file system,
70
# reducing IO in tests that use UniqueFileAllocator (such as all the
71
# pagetests in Launchpad. At that point an interface to obtain a
72
# factory of UniqueFileAllocator's would be useful to parameterise the
74
namer = UniqueFileAllocator(self._tempdir, 'OOPS', 'T')
75
# first name of the day
76
self.assertUniqueFileAllocator(namer,
77
datetime.datetime(2006, 04, 01, 00, 30, 00, tzinfo=UTC),
78
'OOPS-91T1', 1, '2006-04-01/01800.T1', '2006-04-01')
79
# second name of the day
80
self.assertUniqueFileAllocator(namer,
81
datetime.datetime(2006, 04, 01, 12, 00, 00, tzinfo=UTC),
82
'OOPS-91T2', 2, '2006-04-01/43200.T2', '2006-04-01')
84
# first name of the following day sets a new dir and the id starts
86
self.assertUniqueFileAllocator(namer,
87
datetime.datetime(2006, 04, 02, 00, 30, 00, tzinfo=UTC),
88
'OOPS-92T1', 1, '2006-04-02/01800.T1', '2006-04-02')
90
# Setting a token inserts the token into the filename.
92
logid, filename = namer.newId(
93
datetime.datetime(2006, 04, 02, 00, 30, 00, tzinfo=UTC))
94
self.assertEqual(logid, 'OOPS-92TYYY2')
96
# Setting a type controls the log id:
98
namer._log_type = "PROFILE"
99
logid, filename = namer.newId(
100
datetime.datetime(2006, 04, 02, 00, 30, 00, tzinfo=UTC))
101
self.assertEqual(logid, 'PROFILE-92T3')
103
# Native timestamps are not permitted - UTC only.
104
now = datetime.datetime(2006, 04, 02, 00, 30, 00)
105
self.assertRaises(ValueError, namer.newId, now)
107
def test_changeErrorDir(self):
108
"""Test changing the log output dir."""
109
namer = UniqueFileAllocator(self._tempdir, 'OOPS', 'T')
111
# First an id in the original error directory.
112
self.assertUniqueFileAllocator(namer,
113
datetime.datetime(2006, 04, 01, 00, 30, 00, tzinfo=UTC),
114
'OOPS-91T1', 1, '2006-04-01/01800.T1', '2006-04-01')
116
# UniqueFileAllocator uses the _output_root attribute to get the
117
# current output directory.
118
new_output_dir = self.useFixture(TempDir()).path
119
namer._output_root = new_output_dir
121
# Now an id on the same day, in the new directory.
122
now = datetime.datetime(2006, 04, 01, 12, 00, 00, tzinfo=UTC)
123
log_id, filename = namer.newId(now)
125
# Since it's a new directory, with no previous logs, the id is 1
126
# again, rather than 2.
127
self.assertEqual(log_id, 'OOPS-91T1')
128
self.assertEqual(namer._last_serial, 1)
129
self.assertEqual(namer._last_output_dir,
130
os.path.join(new_output_dir, '2006-04-01'))
132
def test_findHighestSerial(self):
133
namer = UniqueFileAllocator(self._tempdir, "OOPS", "T")
134
# Creates the dir using now as the timestamp.
135
output_dir = namer.output_dir()
136
# write some files, in non-serial order.
137
open(os.path.join(output_dir, '12343.T1'), 'w').close()
138
open(os.path.join(output_dir, '12342.T2'), 'w').close()
139
open(os.path.join(output_dir, '12345.T3'), 'w').close()
140
open(os.path.join(output_dir, '1234567.T0010'), 'w').close()
141
open(os.path.join(output_dir, '12346.A42'), 'w').close()
142
open(os.path.join(output_dir, '12346.B100'), 'w').close()
143
# The namer should figure out the right highest serial.
144
self.assertEqual(namer._findHighestSerial(output_dir), 10)
146
def test_output_dir_permission(self):
147
# Set up default dir creation mode to rwx------.
148
umask_permission = stat.S_IRWXG | stat.S_IRWXO
149
old_umask = os.umask(umask_permission)
150
namer = UniqueFileAllocator(self._tempdir, "OOPS", "T")
151
output_dir = namer.output_dir()
152
st = os.stat(output_dir)
153
# Permission we want here is: rwxr-xr-x
154
wanted_permission = (
155
stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH |
157
# Get only the permission bits for this directory.
158
dir_permission = stat.S_IMODE(st.st_mode)
159
self.assertEqual(dir_permission, wanted_permission)
160
# Restore the umask to the original value.
161
ignored = os.umask(old_umask)