Merge ~logrotate-charmers/charm-logrotated:bugs_1833095_1833093 into ~logrotate-charmers/charm-logrotated:master
- Git
- lp:~logrotate-charmers/charm-logrotated
- bugs_1833095_1833093
- Merge into master
Proposed by
Diko Parvanov
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Diko Parvanov | ||||||||
Approved revision: | 6d391ef597fad5552bfdee132025c4aa603a21d9 | ||||||||
Merge reported by: | Diko Parvanov | ||||||||
Merged at revision: | 6d391ef597fad5552bfdee132025c4aa603a21d9 | ||||||||
Proposed branch: | ~logrotate-charmers/charm-logrotated:bugs_1833095_1833093 | ||||||||
Merge into: | ~logrotate-charmers/charm-logrotated:master | ||||||||
Diff against target: |
672 lines (+148/-131) 10 files modified
actions/actions.py (+12/-21) dev/null (+0/-13) lib/lib_cron.py (+38/-32) lib/lib_logrotate.py (+17/-24) reactive/logrotate.py (+20/-8) tests/functional/conftest.py (+14/-9) tests/functional/juju_tools.py (+14/-13) tests/functional/test_logrotate.py (+5/-2) tests/unit/conftest.py (+11/-0) tests/unit/test_logrotate.py (+17/-9) |
||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Diko Parvanov | Approve | ||
Review via email: mp+369020@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Diko Parvanov (dparv) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/actions/__init__.py b/actions/__init__.py |
2 | deleted file mode 100755 |
3 | index 9b088de..0000000 |
4 | --- a/actions/__init__.py |
5 | +++ /dev/null |
6 | @@ -1,13 +0,0 @@ |
7 | -# Copyright 2016 Canonical Ltd |
8 | -# |
9 | -# Licensed under the Apache License, Version 2.0 (the "License"); |
10 | -# you may not use this file except in compliance with the License. |
11 | -# You may obtain a copy of the License at |
12 | -# |
13 | -# http://www.apache.org/licenses/LICENSE-2.0 |
14 | -# |
15 | -# Unless required by applicable law or agreed to in writing, software |
16 | -# distributed under the License is distributed on an "AS IS" BASIS, |
17 | -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
18 | -# See the License for the specific language governing permissions and |
19 | -# limitations under the License. |
20 | diff --git a/actions/actions.py b/actions/actions.py |
21 | index aee6bb7..8178850 100755 |
22 | --- a/actions/actions.py |
23 | +++ b/actions/actions.py |
24 | @@ -1,45 +1,36 @@ |
25 | #!/usr/bin/env python3 |
26 | -# |
27 | -# Copyright 2016 Canonical Ltd |
28 | -# |
29 | -# Licensed under the Apache License, Version 2.0 (the "License"); |
30 | -# you may not use this file except in compliance with the License. |
31 | -# You may obtain a copy of the License at |
32 | -# |
33 | -# http://www.apache.org/licenses/LICENSE-2.0 |
34 | -# |
35 | -# Unless required by applicable law or agreed to in writing, software |
36 | -# distributed under the License is distributed on an "AS IS" BASIS, |
37 | -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
38 | -# See the License for the specific language governing permissions and |
39 | -# limitations under the License. |
40 | +"""Actions module.""" |
41 | |
42 | import os |
43 | import sys |
44 | |
45 | -sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib')) |
46 | -from charmhelpers.core import ( |
47 | - hookenv, |
48 | - host, |
49 | -) |
50 | +from charmhelpers.core import hookenv |
51 | |
52 | -from lib_logrotate import LogrotateHelper |
53 | from lib_cron import CronHelper |
54 | |
55 | +from lib_logrotate import LogrotateHelper |
56 | + |
57 | +sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib')) |
58 | + |
59 | hooks = hookenv.Hooks() |
60 | logrotate = LogrotateHelper() |
61 | cron = CronHelper() |
62 | |
63 | + |
64 | @hooks.hook("update-logrotate-files") |
65 | def update_logrotate_files(): |
66 | + """Update the logrotate files.""" |
67 | logrotate.read_config() |
68 | logrotate.modify_configs() |
69 | |
70 | + |
71 | @hooks.hook("update-cronjob") |
72 | def update_cronjob(): |
73 | + """Update the cronjob file.""" |
74 | cron.read_config() |
75 | cron.install_cronjob() |
76 | |
77 | + |
78 | if __name__ == "__main__": |
79 | + """Main function.""" |
80 | hooks.execute(sys.argv) |
81 | - |
82 | diff --git a/lib/lib_cron.py b/lib/lib_cron.py |
83 | index 15bcdaf..f560084 100644 |
84 | --- a/lib/lib_cron.py |
85 | +++ b/lib/lib_cron.py |
86 | @@ -1,24 +1,27 @@ |
87 | +"""Cron helper module.""" |
88 | import os |
89 | -import re |
90 | + |
91 | from lib_logrotate import LogrotateHelper |
92 | |
93 | + |
94 | class CronHelper: |
95 | """Helper class for logrotate charm.""" |
96 | |
97 | - @classmethod |
98 | def __init__(self): |
99 | - """Init function""" |
100 | - self.cronjob_check_paths = [ "hourly", "daily", "weekly", "monthly" ] |
101 | + """Init function.""" |
102 | + self.cronjob_base_path = "/etc/cron." |
103 | + self.cronjob_etc_config = "/etc/logrotate_cronjob_config" |
104 | + self.cronjob_check_paths = ["hourly", "daily", "weekly", "monthly"] |
105 | self.cronjob_logrotate_cron_file = "charm-logrotate" |
106 | |
107 | - |
108 | - @classmethod |
109 | def read_config(self): |
110 | - """Config changed/install hooks dumps config out to disk, |
111 | - Here we read that config to update the cronjob""" |
112 | + """Read the configuration from the file. |
113 | |
114 | - config_file = open("/etc/logrotate_cronjob_config", "r") |
115 | - lines = config_file.read() |
116 | + Config changed/install hooks dumps config out to disk, |
117 | + Here we read that config to update the cronjob. |
118 | + """ |
119 | + config_file = open(self.cronjob_etc_config, "r") |
120 | + lines = config_file.read() |
121 | lines = lines.split('\n') |
122 | |
123 | if lines[0] == 'True': |
124 | @@ -28,51 +31,54 @@ class CronHelper: |
125 | |
126 | self.cronjob_frequency = int(self.cronjob_check_paths.index(lines[1])) |
127 | |
128 | - |
129 | - @classmethod |
130 | def install_cronjob(self): |
131 | - """If logrotate-cronjob config option is set to True |
132 | - install cronjob. Otherwise cleanup""" |
133 | + """Install the cron job task. |
134 | |
135 | + If logrotate-cronjob config option is set to True install cronjob, |
136 | + otherwise cleanup. |
137 | + """ |
138 | clean_up_file = self.cronjob_frequency if self.cronjob_enabled else -1 |
139 | |
140 | if self.cronjob_enabled is True: |
141 | path_to_lib = os.path.realpath(__file__) |
142 | - cron_file_path = "/etc/cron." + self.cronjob_check_paths[clean_up_file] \ |
143 | - + "/" + self.cronjob_logrotate_cron_file |
144 | + cron_file_path = self.cronjob_base_path\ |
145 | + + self.cronjob_check_paths[clean_up_file]\ |
146 | + + "/" + self.cronjob_logrotate_cron_file |
147 | |
148 | # upgrade to template if logic increases |
149 | cron_file = open(cron_file_path, 'w') |
150 | cron_file.write("#!/bin/sh\n/usr/bin/python3 " + path_to_lib + "\n\n") |
151 | cron_file.close() |
152 | - os.chmod(cron_file_path,700) |
153 | - |
154 | - self.cleanup_cronjob(clean_up_file) |
155 | + os.chmod(cron_file_path, 700) |
156 | |
157 | + self.cleanup_cronjob(clean_up_file) |
158 | |
159 | - @classmethod |
160 | - def cleanup_cronjob(self, frequency = -1): |
161 | - """Cleanup previous config""" |
162 | - for i in range(4): |
163 | - if frequency != i: |
164 | - path = "/etc/cron." + self.cronjob_check_paths[i] + "/" +\ |
165 | - self.cronjob_logrotate_cron_file |
166 | + def cleanup_cronjob(self, frequency=-1): |
167 | + """Cleanup previous config.""" |
168 | + if frequency == -1: |
169 | + for check_path in self.cronjob_check_paths: |
170 | + path = self.cronjob_base_path \ |
171 | + + check_path \ |
172 | + + "/" \ |
173 | + + self.cronjob_logrotate_cron_file |
174 | if os.path.exists(path): |
175 | os.remove(path) |
176 | + if os.path.exists(self.cronjob_etc_config): |
177 | + os.remove(self.cronjob_etc_config) |
178 | |
179 | - @classmethod |
180 | def update_logrotate_etc(self): |
181 | - """Run logrotate update config""" |
182 | + """Run logrotate update config.""" |
183 | logrotate = LogrotateHelper() |
184 | logrotate.read_config() |
185 | logrotate.modify_configs() |
186 | |
187 | |
188 | def main(): |
189 | - cronHelper = CronHelper() |
190 | - cronHelper.read_config() |
191 | - cronHelper.update_logrotate_etc() |
192 | - cronHelper.install_cronjob() |
193 | + """Ran by cron.""" |
194 | + cronhelper = CronHelper() |
195 | + cronhelper.read_config() |
196 | + cronhelper.update_logrotate_etc() |
197 | + cronhelper.install_cronjob() |
198 | |
199 | |
200 | if __name__ == '__main__': |
201 | diff --git a/lib/lib_logrotate.py b/lib/lib_logrotate.py |
202 | index d823020..67245cb 100644 |
203 | --- a/lib/lib_logrotate.py |
204 | +++ b/lib/lib_logrotate.py |
205 | @@ -1,6 +1,8 @@ |
206 | +"""Logrotate module.""" |
207 | import os |
208 | import re |
209 | |
210 | +from charmhelpers.core import hookenv |
211 | |
212 | LOGROTATE_DIR = "/etc/logrotate.d/" |
213 | |
214 | @@ -8,27 +10,24 @@ LOGROTATE_DIR = "/etc/logrotate.d/" |
215 | class LogrotateHelper: |
216 | """Helper class for logrotate charm.""" |
217 | |
218 | - @classmethod |
219 | def __init__(self): |
220 | - """Init function""" |
221 | - pass |
222 | + """Init function.""" |
223 | + self.retention = hookenv.config('logrotate-retention') |
224 | |
225 | - @classmethod |
226 | def read_config(self): |
227 | - """Config changed/install hooks dumps config out to disk, |
228 | - Here we read that config to update the cronjob""" |
229 | + """Read changes from disk. |
230 | |
231 | + Config changed/install hooks dumps config out to disk, |
232 | + Here we read that config to update the cronjob |
233 | + """ |
234 | config_file = open("/etc/logrotate_cronjob_config", "r") |
235 | lines = config_file.read() |
236 | lines = lines.split('\n') |
237 | |
238 | self.retention = int(lines[2]) |
239 | |
240 | - |
241 | - @classmethod |
242 | def modify_configs(self): |
243 | """Modify the logrotate config files.""" |
244 | - |
245 | for config_file in os.listdir(LOGROTATE_DIR): |
246 | file_path = LOGROTATE_DIR + config_file |
247 | |
248 | @@ -44,11 +43,8 @@ class LogrotateHelper: |
249 | logrotate_file.write(mod_contents) |
250 | logrotate_file.close() |
251 | |
252 | - |
253 | - @classmethod |
254 | def modify_content(self, content): |
255 | - """Helper function to edit the content of a logrotate file.""" |
256 | - |
257 | + """Edit the content of a logrotate file.""" |
258 | # Split the contents in a logrotate file in separate entries (if |
259 | # multiple are found in the file) and put in a list for further |
260 | # processing |
261 | @@ -66,7 +62,7 @@ class LogrotateHelper: |
262 | # the rotate option to the appropriate value |
263 | results = [] |
264 | for item in items: |
265 | - count = self.calculate_count(item) |
266 | + count = self.calculate_count(item, self.retention) |
267 | rotate = 'rotate {}'.format(count) |
268 | result = re.sub(r'rotate \d+\.?[0-9]*', rotate, item) |
269 | results.append(result) |
270 | @@ -75,10 +71,8 @@ class LogrotateHelper: |
271 | |
272 | return results |
273 | |
274 | - @classmethod |
275 | def modify_header(self, content): |
276 | - """Helper function to add Juju headers to the file.""" |
277 | - |
278 | + """Add Juju headers to the file.""" |
279 | header = "# Configuration file maintained by Juju. Local changes may be overwritten" |
280 | |
281 | split = content.split('\n') |
282 | @@ -90,23 +84,22 @@ class LogrotateHelper: |
283 | return result |
284 | |
285 | @classmethod |
286 | - def calculate_count(self, item): |
287 | + def calculate_count(cls, item, retention): |
288 | """Calculate rotate based on rotation interval. Always round up.""" |
289 | - |
290 | # Fallback to default lowest retention - days |
291 | # better to keep the logs than lose them |
292 | - count = self.retention |
293 | + count = retention |
294 | # Daily 1:1 to configuration retention period (in days) |
295 | if 'daily' in item: |
296 | - count = self.retention |
297 | + count = retention |
298 | # Weekly rounding up, as weeks are 7 days |
299 | if 'weekly' in item: |
300 | - count = int(round(self.retention/7)) |
301 | + count = int(round(retention/7)) |
302 | # Monthly default 30 days and round up because of 28/31 days months |
303 | if 'monthly' in item: |
304 | - count = int(round(self.retention/30)) |
305 | + count = int(round(retention/30)) |
306 | # For every 360 days - add 1 year |
307 | if 'yearly' in item: |
308 | - count = self.retention // 360 + 1 if self.retention > 360 else 1 |
309 | + count = retention // 360 + 1 if retention > 360 else 1 |
310 | |
311 | return count |
312 | diff --git a/reactive/logrotate.py b/reactive/logrotate.py |
313 | index 4a8d5c1..1810707 100644 |
314 | --- a/reactive/logrotate.py |
315 | +++ b/reactive/logrotate.py |
316 | @@ -1,36 +1,48 @@ |
317 | -from lib_logrotate import LogrotateHelper |
318 | -from lib_cron import CronHelper |
319 | +"""Reactive charm hooks.""" |
320 | from charmhelpers.core import hookenv |
321 | + |
322 | from charms.reactive import set_flag, when, when_not |
323 | |
324 | +from lib_cron import CronHelper |
325 | + |
326 | +from lib_logrotate import LogrotateHelper |
327 | + |
328 | + |
329 | +hooks = hookenv.Hooks() |
330 | logrotate = LogrotateHelper() |
331 | cron = CronHelper() |
332 | |
333 | + |
334 | @when_not('logrotate.installed') |
335 | def install_logrotate(): |
336 | - dump_config_to_disk(); |
337 | + """Install the logrotate charm.""" |
338 | + dump_config_to_disk() |
339 | logrotate.read_config() |
340 | cron.read_config() |
341 | logrotate.modify_configs() |
342 | hookenv.status_set('active', 'Unit is ready.') |
343 | set_flag('logrotate.installed') |
344 | - cron.install_cronjob(); |
345 | + cron.install_cronjob() |
346 | + |
347 | |
348 | @when('config.changed') |
349 | def config_changed(): |
350 | + """Run when configuration changes.""" |
351 | dump_config_to_disk() |
352 | cron.read_config() |
353 | logrotate.read_config() |
354 | hookenv.status_set('maintenance', 'Modifying configs.') |
355 | logrotate.modify_configs() |
356 | hookenv.status_set('active', 'Unit is ready.') |
357 | - cron.install_cronjob(); |
358 | + cron.install_cronjob() |
359 | + |
360 | |
361 | def dump_config_to_disk(): |
362 | + """Dump configurations to disk.""" |
363 | cronjob_enabled = hookenv.config('logrotate-cronjob') |
364 | cronjob_frequency = hookenv.config('logrotate-cronjob-frequency') |
365 | logrotate_retention = hookenv.config('logrotate-retention') |
366 | with open('/etc/logrotate_cronjob_config', 'w+') as cronjob_config_file: |
367 | - cronjob_config_file.write(str(cronjob_enabled) + '\n') |
368 | - cronjob_config_file.write(str(cronjob_frequency) + '\n') |
369 | - cronjob_config_file.write(str(logrotate_retention) + '\n') |
370 | + cronjob_config_file.write(str(cronjob_enabled) + '\n') |
371 | + cronjob_config_file.write(str(cronjob_frequency) + '\n') |
372 | + cronjob_config_file.write(str(logrotate_retention) + '\n') |
373 | diff --git a/tests/functional/conftest.py b/tests/functional/conftest.py |
374 | index 56925ff..1b22cb8 100644 |
375 | --- a/tests/functional/conftest.py |
376 | +++ b/tests/functional/conftest.py |
377 | @@ -1,28 +1,32 @@ |
378 | #!/usr/bin/python3 |
379 | -''' |
380 | -Reusable pytest fixtures for functional testing |
381 | +""" |
382 | +Reusable pytest fixtures for functional testing. |
383 | |
384 | Environment variables |
385 | --------------------- |
386 | |
387 | test_preserve_model: |
388 | if set, the testing model won't be torn down at the end of the testing session |
389 | -''' |
390 | +""" |
391 | |
392 | import asyncio |
393 | import os |
394 | -import uuid |
395 | -import pytest |
396 | import subprocess |
397 | +import uuid |
398 | |
399 | from juju.controller import Controller |
400 | + |
401 | from juju_tools import JujuTools |
402 | |
403 | +import pytest |
404 | + |
405 | |
406 | @pytest.fixture(scope='module') |
407 | def event_loop(): |
408 | - '''Override the default pytest event loop to allow for fixtures using a |
409 | - broader scope''' |
410 | + """Override the default pytest event loop. |
411 | + |
412 | + Do this too allow for fixtures using a broader scope. |
413 | + """ |
414 | loop = asyncio.get_event_loop_policy().new_event_loop() |
415 | asyncio.set_event_loop(loop) |
416 | loop.set_debug(True) |
417 | @@ -33,7 +37,7 @@ def event_loop(): |
418 | |
419 | @pytest.fixture(scope='module') |
420 | async def controller(): |
421 | - '''Connect to the current controller''' |
422 | + """Connect to the current controller.""" |
423 | _controller = Controller() |
424 | await _controller.connect_current() |
425 | yield _controller |
426 | @@ -42,7 +46,7 @@ async def controller(): |
427 | |
428 | @pytest.fixture(scope='module') |
429 | async def model(controller): |
430 | - '''This model lives only for the duration of the test''' |
431 | + """Live only for the duration of the test.""" |
432 | model_name = "functest-{}".format(str(uuid.uuid4())[-12:]) |
433 | _model = await controller.add_model(model_name, |
434 | cloud_name=os.getenv('PYTEST_CLOUD_NAME'), |
435 | @@ -62,5 +66,6 @@ async def model(controller): |
436 | |
437 | @pytest.fixture(scope='module') |
438 | async def jujutools(controller, model): |
439 | + """Juju tools.""" |
440 | tools = JujuTools(controller, model) |
441 | return tools |
442 | diff --git a/tests/functional/juju_tools.py b/tests/functional/juju_tools.py |
443 | index 2fd501d..5e4a1cc 100644 |
444 | --- a/tests/functional/juju_tools.py |
445 | +++ b/tests/functional/juju_tools.py |
446 | @@ -1,22 +1,26 @@ |
447 | +"""Juju tools.""" |
448 | +import base64 |
449 | import pickle |
450 | + |
451 | import juju |
452 | -import base64 |
453 | |
454 | # from juju.errors import JujuError |
455 | |
456 | |
457 | class JujuTools: |
458 | + """Juju tools.""" |
459 | + |
460 | def __init__(self, controller, model): |
461 | + """Init.""" |
462 | self.controller = controller |
463 | self.model = model |
464 | |
465 | async def run_command(self, cmd, target): |
466 | - ''' |
467 | - Runs a command on a unit. |
468 | + """Run a command on a unit. |
469 | |
470 | :param cmd: Command to be run |
471 | :param unit: Unit object or unit name string |
472 | - ''' |
473 | + """ |
474 | unit = ( |
475 | target |
476 | if isinstance(target, juju.unit.Unit) |
477 | @@ -26,13 +30,12 @@ class JujuTools: |
478 | return action.results |
479 | |
480 | async def remote_object(self, imports, remote_cmd, target): |
481 | - ''' |
482 | - Runs command on target machine and returns a python object of the result |
483 | + """Run command on target machine and returns a python object of the result. |
484 | |
485 | :param imports: Imports needed for the command to run |
486 | :param remote_cmd: The python command to execute |
487 | :param target: Unit object or unit name string |
488 | - ''' |
489 | + """ |
490 | python3 = "python3 -c '{}'" |
491 | python_cmd = ('import pickle;' |
492 | 'import base64;' |
493 | @@ -44,12 +47,11 @@ class JujuTools: |
494 | return pickle.loads(base64.b64decode(bytes(results['Stdout'][2:-1], 'utf8'))) |
495 | |
496 | async def file_stat(self, path, target): |
497 | - ''' |
498 | - Runs stat on a file |
499 | + """Run stat on a file. |
500 | |
501 | :param path: File path |
502 | :param target: Unit object or unit name string |
503 | - ''' |
504 | + """ |
505 | imports = 'import os;' |
506 | python_cmd = ('os.stat("{}")' |
507 | .format(path)) |
508 | @@ -57,12 +59,11 @@ class JujuTools: |
509 | return await self.remote_object(imports, python_cmd, target) |
510 | |
511 | async def file_contents(self, path, target): |
512 | - ''' |
513 | - Returns the contents of a file |
514 | + """Return the contents of a file. |
515 | |
516 | :param path: File path |
517 | :param target: Unit object or unit name string |
518 | - ''' |
519 | + """ |
520 | cmd = 'cat {}'.format(path) |
521 | result = await self.run_command(cmd, target) |
522 | return result['Stdout'] |
523 | diff --git a/tests/functional/test_logrotate.py b/tests/functional/test_logrotate.py |
524 | index b4402be..100690f 100644 |
525 | --- a/tests/functional/test_logrotate.py |
526 | +++ b/tests/functional/test_logrotate.py |
527 | @@ -1,6 +1,8 @@ |
528 | #!/usr/bin/python3.6 |
529 | +"""Main module for functional testing.""" |
530 | |
531 | import os |
532 | + |
533 | import pytest |
534 | |
535 | pytestmark = pytest.mark.asyncio |
536 | @@ -16,7 +18,7 @@ SERIES = ['xenial', |
537 | @pytest.fixture(scope='module', |
538 | params=SERIES) |
539 | async def deploy_app(request, model): |
540 | - '''Deploys the logrotate charm as a subordinate of ubuntu''' |
541 | + """Deploy the logrotate charm as a subordinate of ubuntu.""" |
542 | release = request.param |
543 | |
544 | await model.deploy( |
545 | @@ -42,7 +44,7 @@ async def deploy_app(request, model): |
546 | |
547 | @pytest.fixture(scope='module') |
548 | async def unit(deploy_app): |
549 | - '''Returns the logrotate unit we've deployed''' |
550 | + """Return the logrotate unit we've deployed.""" |
551 | return deploy_app.units.pop() |
552 | |
553 | ######### |
554 | @@ -51,4 +53,5 @@ async def unit(deploy_app): |
555 | |
556 | |
557 | async def test_deploy(deploy_app): |
558 | + """Tst the deployment.""" |
559 | assert deploy_app.status == 'active' |
560 | diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py |
561 | index 534e654..8520709 100644 |
562 | --- a/tests/unit/conftest.py |
563 | +++ b/tests/unit/conftest.py |
564 | @@ -1,11 +1,15 @@ |
565 | #!/usr/bin/python3 |
566 | +"""Configurations for tests.""" |
567 | + |
568 | import mock |
569 | + |
570 | import pytest |
571 | |
572 | # If layer options are used, add this to ${fixture} |
573 | # and import layer in logrotate |
574 | @pytest.fixture |
575 | def mock_layers(monkeypatch): |
576 | + """Layers mock.""" |
577 | import sys |
578 | sys.modules['charms.layer'] = mock.Mock() |
579 | sys.modules['reactive'] = mock.Mock() |
580 | @@ -21,8 +25,10 @@ def mock_layers(monkeypatch): |
581 | |
582 | monkeypatch.setattr('lib_logrotate.layer.options', options) |
583 | |
584 | + |
585 | @pytest.fixture |
586 | def mock_hookenv_config(monkeypatch): |
587 | + """Hookenv mock.""" |
588 | import yaml |
589 | |
590 | def mock_config(): |
591 | @@ -39,17 +45,22 @@ def mock_hookenv_config(monkeypatch): |
592 | |
593 | monkeypatch.setattr('lib_logrotate.hookenv.config', mock_config) |
594 | |
595 | + |
596 | @pytest.fixture |
597 | def mock_remote_unit(monkeypatch): |
598 | + """Remote unit mock.""" |
599 | monkeypatch.setattr('lib_logrotate.hookenv.remote_unit', lambda: 'unit-mock/0') |
600 | |
601 | |
602 | @pytest.fixture |
603 | def mock_charm_dir(monkeypatch): |
604 | + """Charm dir mock.""" |
605 | monkeypatch.setattr('lib_logrotate.hookenv.charm_dir', lambda: '/mock/charm/dir') |
606 | |
607 | + |
608 | @pytest.fixture |
609 | def logrotate(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch): |
610 | + """Logrotate fixture.""" |
611 | from lib_logrotate import LogrotateHelper |
612 | helper = LogrotateHelper |
613 | |
614 | diff --git a/tests/unit/test_logrotate.py b/tests/unit/test_logrotate.py |
615 | index 1f0ed9b..b01c7b5 100644 |
616 | --- a/tests/unit/test_logrotate.py |
617 | +++ b/tests/unit/test_logrotate.py |
618 | @@ -1,37 +1,45 @@ |
619 | -from unittest.mock import patch |
620 | +"""Main unit test module.""" |
621 | + |
622 | |
623 | class TestLogrotateHelper(): |
624 | + """Main test class.""" |
625 | + |
626 | def test_pytest(self): |
627 | + """Simple pytest.""" |
628 | assert True |
629 | |
630 | - |
631 | def test_daily_retention_count(self, logrotate): |
632 | + """Test daily retention count.""" |
633 | logrotate.retention = 90 |
634 | contents = '/var/log/some.log {\n rotate 123\n daily\n}' |
635 | - count = logrotate.calculate_count(contents) |
636 | + count = logrotate.calculate_count(contents, logrotate.retention) |
637 | assert count == 90 |
638 | |
639 | def test_weekly_retention_count(self, logrotate): |
640 | + """Test weekly retention count.""" |
641 | logrotate.retention = 21 |
642 | contents = '/var/log/some.log {\n rotate 123\n weekly\n}' |
643 | - count = logrotate.calculate_count(contents) |
644 | + count = logrotate.calculate_count(contents, logrotate.retention) |
645 | assert count == 3 |
646 | |
647 | def test_monthly_retention_count(self, logrotate): |
648 | + """Test monthly retention count.""" |
649 | logrotate.retention = 60 |
650 | contents = '/var/log/some.log {\n rotate 123\n monthly\n}' |
651 | - count = logrotate.calculate_count(contents) |
652 | + count = logrotate.calculate_count(contents, logrotate.retention) |
653 | assert count == 2 |
654 | |
655 | def test_yearly_retention_count(self, logrotate): |
656 | + """Test yearly retention count.""" |
657 | logrotate.retention = 180 |
658 | contents = '/var/log/some.log {\n rotate 123\n yearly\n}' |
659 | - count = logrotate.calculate_count(contents) |
660 | + count = logrotate.calculate_count(contents, logrotate.retention) |
661 | assert count == 1 |
662 | |
663 | def test_modify_content(self, logrotate): |
664 | + """Test the modify_content method.""" |
665 | logrotate.retention = 42 |
666 | - contents = '/var/log/some.log {\n rotate 123\n daily\n}\n/var/log/other.log {\n rotate 456\n weekly\n}' |
667 | - mod_contents = logrotate.modify_content(contents) |
668 | - expected_contents = '/var/log/some.log {\n rotate 42\n daily\n}\n\n/var/log/other.log {\n rotate 6\n weekly\n}\n' |
669 | + contents = '/log/some.log {\n rotate 123\n daily\n}\n/log/other.log {\n rotate 456\n weekly\n}' |
670 | + mod_contents = logrotate.modify_content(logrotate, contents) |
671 | + expected_contents = '/log/some.log {\n rotate 42\n daily\n}\n\n/log/other.log {\n rotate 6\n weekly\n}\n' |
672 | assert mod_contents == expected_contents |