Merge ~vultaire/charm-logrotated:black-20.08 into charm-logrotated:master

Proposed by Paul Goins
Status: Merged
Approved by: Xav Paice
Approved revision: 98174e23a023bad96dbaa1b6ab396d05d0046301
Merged at revision: 1ec74c351769c8e778ae23604e379b1b3c6540f3
Proposed branch: ~vultaire/charm-logrotated:black-20.08
Merge into: charm-logrotated:master
Prerequisite: ~vultaire/charm-logrotated:makefile-20.08
Diff against target: 668 lines (+147/-122)
10 files modified
src/actions/actions.py (+1/-1)
src/lib/lib_cron.py (+22/-12)
src/lib/lib_logrotate.py (+33/-28)
src/reactive/logrotate.py (+15/-15)
src/tests/functional/conftest.py (+11/-10)
src/tests/functional/juju_tools.py (+13/-11)
src/tests/functional/test_logrotate.py (+15/-19)
src/tests/unit/conftest.py (+14/-12)
src/tests/unit/test_logrotate.py (+21/-9)
src/tox.ini (+2/-5)
Reviewer Review Type Date Requested Status
Xav Paice (community) Approve
Canonical IS Reviewers Pending
Review via email: mp+388839@code.launchpad.net

Commit message

Blackened repository to 88 lines

To post a comment you must log in.
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

This merge proposal is being monitored by mergebot. Change the status to Approved to merge.

Revision history for this message
Paul Goins (vultaire) wrote :

Just rebased today.

Revision history for this message
Xav Paice (xavpaice) wrote :

lgtm

review: Approve
Revision history for this message
🤖 Canonical IS Merge Bot (canonical-is-mergebot) wrote :

Change successfully merged at revision 1ec74c351769c8e778ae23604e379b1b3c6540f3

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/src/actions/actions.py b/src/actions/actions.py
index 8178850..dd311d4 100755
--- a/src/actions/actions.py
+++ b/src/actions/actions.py
@@ -10,7 +10,7 @@ from lib_cron import CronHelper
1010
11from lib_logrotate import LogrotateHelper11from lib_logrotate import LogrotateHelper
1212
13sys.path.insert(0, os.path.join(os.environ['CHARM_DIR'], 'lib'))13sys.path.insert(0, os.path.join(os.environ["CHARM_DIR"], "lib"))
1414
15hooks = hookenv.Hooks()15hooks = hookenv.Hooks()
16logrotate = LogrotateHelper()16logrotate = LogrotateHelper()
diff --git a/src/lib/lib_cron.py b/src/lib/lib_cron.py
index b7d24c4..5c17738 100644
--- a/src/lib/lib_cron.py
+++ b/src/lib/lib_cron.py
@@ -24,9 +24,9 @@ class CronHelper:
24 """24 """
25 config_file = open(self.cronjob_etc_config, "r")25 config_file = open(self.cronjob_etc_config, "r")
26 lines = config_file.read()26 lines = config_file.read()
27 lines = lines.split('\n')27 lines = lines.split("\n")
2828
29 if lines[0] == 'True':29 if lines[0] == "True":
30 self.cronjob_enabled = True30 self.cronjob_enabled = True
31 else:31 else:
32 self.cronjob_enabled = False32 self.cronjob_enabled = False
@@ -43,17 +43,22 @@ class CronHelper:
4343
44 if self.cronjob_enabled is True:44 if self.cronjob_enabled is True:
45 cronjob_path = os.path.realpath(__file__)45 cronjob_path = os.path.realpath(__file__)
46 cron_file_path = self.cronjob_base_path\46 cron_file_path = (
47 + self.cronjob_check_paths[clean_up_file]\47 self.cronjob_base_path
48 + "/" + self.cronjob_logrotate_cron_file48 + self.cronjob_check_paths[clean_up_file]
49 + "/"
50 + self.cronjob_logrotate_cron_file
51 )
4952
50 logrotate_unit = hookenv.local_unit()53 logrotate_unit = hookenv.local_unit()
51 python_venv_path = os.getcwd().replace('charm', '') + '.venv/bin/python3'54 python_venv_path = os.getcwd().replace("charm", "") + ".venv/bin/python3"
52 # upgrade to template if logic increases55 # upgrade to template if logic increases
53 cron_file = open(cron_file_path, 'w')56 cron_file = open(cron_file_path, "w")
54 cron_job = """#!/bin/bash57 cron_job = """#!/bin/bash
55/usr/bin/sudo /usr/bin/juju-run {} "{} {}"58/usr/bin/sudo /usr/bin/juju-run {} "{} {}"
56""".format(logrotate_unit, python_venv_path, cronjob_path)59""".format(
60 logrotate_unit, python_venv_path, cronjob_path
61 )
57 cron_file.write(cron_job)62 cron_file.write(cron_job)
58 cron_file.close()63 cron_file.close()
59 os.chmod(cron_file_path, 700)64 os.chmod(cron_file_path, 700)
@@ -64,7 +69,12 @@ class CronHelper:
64 """Cleanup previous config."""69 """Cleanup previous config."""
65 if frequency == -1:70 if frequency == -1:
66 for check_path in self.cronjob_check_paths:71 for check_path in self.cronjob_check_paths:
67 path = self.cronjob_base_path + check_path + "/" + self.cronjob_logrotate_cron_file72 path = (
73 self.cronjob_base_path
74 + check_path
75 + "/"
76 + self.cronjob_logrotate_cron_file
77 )
68 if os.path.exists(path):78 if os.path.exists(path):
69 os.remove(path)79 os.remove(path)
70 if os.path.exists(self.cronjob_etc_config):80 if os.path.exists(self.cronjob_etc_config):
@@ -79,13 +89,13 @@ class CronHelper:
7989
80def main():90def main():
81 """Ran by cron."""91 """Ran by cron."""
82 hookenv.status_set('maintenance', 'Executing cron job.')92 hookenv.status_set("maintenance", "Executing cron job.")
83 cronhelper = CronHelper()93 cronhelper = CronHelper()
84 cronhelper.read_config()94 cronhelper.read_config()
85 cronhelper.update_logrotate_etc()95 cronhelper.update_logrotate_etc()
86 cronhelper.install_cronjob()96 cronhelper.install_cronjob()
87 hookenv.status_set('active', 'Unit is ready.')97 hookenv.status_set("active", "Unit is ready.")
8898
8999
90if __name__ == '__main__':100if __name__ == "__main__":
91 main()101 main()
diff --git a/src/lib/lib_logrotate.py b/src/lib/lib_logrotate.py
index d8c4327..497f609 100644
--- a/src/lib/lib_logrotate.py
+++ b/src/lib/lib_logrotate.py
@@ -13,9 +13,9 @@ class LogrotateHelper:
1313
14 def __init__(self):14 def __init__(self):
15 """Init function."""15 """Init function."""
16 self.retention = hookenv.config('logrotate-retention')16 self.retention = hookenv.config("logrotate-retention")
17 self.override_interval_regex = re.compile("(daily|weekly|monthly|yearly)")17 self.override_interval_regex = re.compile("(daily|weekly|monthly|yearly)")
18 self.override = json.loads(hookenv.config('override'))18 self.override = json.loads(hookenv.config("override"))
19 self.override_files = self.get_override_files()19 self.override_files = self.get_override_files()
2020
21 def read_config(self):21 def read_config(self):
@@ -26,7 +26,7 @@ class LogrotateHelper:
26 """26 """
27 config_file = open("/etc/logrotate_cronjob_config", "r")27 config_file = open("/etc/logrotate_cronjob_config", "r")
28 lines = config_file.read()28 lines = config_file.read()
29 lines = lines.split('\n')29 lines = lines.split("\n")
3030
31 self.retention = int(lines[2])31 self.retention = int(lines[2])
3232
@@ -35,7 +35,7 @@ class LogrotateHelper:
35 for config_file in os.listdir(LOGROTATE_DIR):35 for config_file in os.listdir(LOGROTATE_DIR):
36 file_path = LOGROTATE_DIR + config_file36 file_path = LOGROTATE_DIR + config_file
3737
38 logrotate_file = open(file_path, 'r')38 logrotate_file = open(file_path, "r")
39 content = logrotate_file.read()39 content = logrotate_file.read()
40 logrotate_file.close()40 logrotate_file.close()
4141
@@ -43,14 +43,17 @@ class LogrotateHelper:
4343
44 mod_contents = self.modify_header(mod_contents)44 mod_contents = self.modify_header(mod_contents)
4545
46 logrotate_file = open(file_path, 'w')46 logrotate_file = open(file_path, "w")
47 logrotate_file.write(mod_contents)47 logrotate_file.write(mod_contents)
48 logrotate_file.close()48 logrotate_file.close()
4949
50 def get_override_files(self):50 def get_override_files(self):
51 """Return paths for files to be overrided."""51 """Return paths for files to be overrided."""
52 return [path['path'] for path in self.override52 return [
53 if set(path.keys()) == {'path', 'rotate', 'interval'}]53 path["path"]
54 for path in self.override
55 if set(path.keys()) == {"path", "rotate", "interval"}
56 ]
5457
55 def get_override_settings(self, file_path):58 def get_override_settings(self, file_path):
56 """Return settings in key:value pairs for the file_path requested.59 """Return settings in key:value pairs for the file_path requested.
@@ -58,22 +61,22 @@ class LogrotateHelper:
58 param: file_path: path to the file for manual settings.61 param: file_path: path to the file for manual settings.
59 """62 """
60 for override_entry in self.override:63 for override_entry in self.override:
61 if file_path == override_entry['path']:64 if file_path == override_entry["path"]:
62 rotate = override_entry['rotate']65 rotate = override_entry["rotate"]
63 interval = override_entry['interval']66 interval = override_entry["interval"]
64 return {'rotate': rotate, 'interval': interval}67 return {"rotate": rotate, "interval": interval}
6568
66 def modify_content(self, content, file_path):69 def modify_content(self, content, file_path):
67 """Edit the content of a logrotate file."""70 """Edit the content of a logrotate file."""
68 # Split the contents in a logrotate file in separate entries (if71 # Split the contents in a logrotate file in separate entries (if
69 # multiple are found in the file) and put in a list for further72 # multiple are found in the file) and put in a list for further
70 # processing73 # processing
71 split = content.split('\n')74 split = content.split("\n")
72 items = []75 items = []
73 string = ""76 string = ""
74 for row in split:77 for row in split:
75 string += row + '\n'78 string += row + "\n"
76 if '}' in row:79 if "}" in row:
77 items.append(string)80 items.append(string)
78 string = ""81 string = ""
79 continue82 continue
@@ -84,35 +87,37 @@ class LogrotateHelper:
84 for item in items:87 for item in items:
85 # Override rotate, if defined88 # Override rotate, if defined
86 if file_path in self.override_files:89 if file_path in self.override_files:
87 count = self.get_override_settings(file_path)['rotate']90 count = self.get_override_settings(file_path)["rotate"]
88 else:91 else:
89 count = self.calculate_count(item, self.retention)92 count = self.calculate_count(item, self.retention)
90 rotate = 'rotate {}'.format(count)93 rotate = "rotate {}".format(count)
91 # if rotate is missing, add it as last line in the item entry94 # if rotate is missing, add it as last line in the item entry
92 if 'rotate' in item:95 if "rotate" in item:
93 result = re.sub(r'rotate \d+\.?[0-9]*', rotate, item)96 result = re.sub(r"rotate \d+\.?[0-9]*", rotate, item)
94 else:97 else:
95 result = item.replace('}', ' ' + rotate + '\n}')98 result = item.replace("}", " " + rotate + "\n}")
96 results.append(result)99 results.append(result)
97100
98 results = '\n'.join(results)101 results = "\n".join(results)
99102
100 # Override interval, if defined103 # Override interval, if defined
101 if file_path in self.override_files:104 if file_path in self.override_files:
102 interval = self.get_override_settings(file_path)['interval']105 interval = self.get_override_settings(file_path)["interval"]
103 results = self.override_interval_regex.sub(interval, results)106 results = self.override_interval_regex.sub(interval, results)
104107
105 return results108 return results
106109
107 def modify_header(self, content):110 def modify_header(self, content):
108 """Add Juju headers to the file."""111 """Add Juju headers to the file."""
109 header = "# Configuration file maintained by Juju. Local changes may be overwritten"112 header = (
113 "# Configuration file maintained by Juju. Local changes may be overwritten"
114 )
110115
111 split = content.split('\n')116 split = content.split("\n")
112 if split[0].startswith(header):117 if split[0].startswith(header):
113 result = content118 result = content
114 else:119 else:
115 result = header + '\n' + content120 result = header + "\n" + content
116121
117 return result122 return result
118123
@@ -123,16 +128,16 @@ class LogrotateHelper:
123 # better to keep the logs than lose them128 # better to keep the logs than lose them
124 count = retention129 count = retention
125 # Daily 1:1 to configuration retention period (in days)130 # Daily 1:1 to configuration retention period (in days)
126 if 'daily' in item:131 if "daily" in item:
127 count = retention132 count = retention
128 # Weekly rounding up, as weeks are 7 days133 # Weekly rounding up, as weeks are 7 days
129 if 'weekly' in item:134 if "weekly" in item:
130 count = int(round(retention / 7))135 count = int(round(retention / 7))
131 # Monthly default 30 days and round up because of 28/31 days months136 # Monthly default 30 days and round up because of 28/31 days months
132 if 'monthly' in item:137 if "monthly" in item:
133 count = int(round(retention / 30))138 count = int(round(retention / 30))
134 # For every 360 days - add 1 year139 # For every 360 days - add 1 year
135 if 'yearly' in item:140 if "yearly" in item:
136 count = retention // 360 + 1 if retention > 360 else 1141 count = retention // 360 + 1 if retention > 360 else 1
137142
138 return count143 return count
diff --git a/src/reactive/logrotate.py b/src/reactive/logrotate.py
index b0e349a..119ac96 100644
--- a/src/reactive/logrotate.py
+++ b/src/reactive/logrotate.py
@@ -13,7 +13,7 @@ logrotate = LogrotateHelper()
13cron = CronHelper()13cron = CronHelper()
1414
1515
16@when_not('logrotate.installed')16@when_not("logrotate.installed")
17def install_logrotate():17def install_logrotate():
18 """Install the logrotate charm."""18 """Install the logrotate charm."""
19 try:19 try:
@@ -23,32 +23,32 @@ def install_logrotate():
23 logrotate.modify_configs()23 logrotate.modify_configs()
24 cron.install_cronjob()24 cron.install_cronjob()
25 except Exception as ex:25 except Exception as ex:
26 hookenv.status_set('blocked', str(ex))26 hookenv.status_set("blocked", str(ex))
27 hookenv.status_set('active', 'Unit is ready.')27 hookenv.status_set("active", "Unit is ready.")
28 set_flag('logrotate.installed')28 set_flag("logrotate.installed")
2929
3030
31@when('config.changed')31@when("config.changed")
32def config_changed():32def config_changed():
33 """Run when configuration changes."""33 """Run when configuration changes."""
34 try:34 try:
35 dump_config_to_disk()35 dump_config_to_disk()
36 cron.read_config()36 cron.read_config()
37 logrotate.read_config()37 logrotate.read_config()
38 hookenv.status_set('maintenance', 'Modifying configs.')38 hookenv.status_set("maintenance", "Modifying configs.")
39 logrotate.modify_configs()39 logrotate.modify_configs()
40 cron.install_cronjob()40 cron.install_cronjob()
41 except Exception as ex:41 except Exception as ex:
42 hookenv.status_set('blocked', str(ex))42 hookenv.status_set("blocked", str(ex))
43 hookenv.status_set('active', 'Unit is ready.')43 hookenv.status_set("active", "Unit is ready.")
4444
4545
46def dump_config_to_disk():46def dump_config_to_disk():
47 """Dump configurations to disk."""47 """Dump configurations to disk."""
48 cronjob_enabled = hookenv.config('logrotate-cronjob')48 cronjob_enabled = hookenv.config("logrotate-cronjob")
49 cronjob_frequency = hookenv.config('logrotate-cronjob-frequency')49 cronjob_frequency = hookenv.config("logrotate-cronjob-frequency")
50 logrotate_retention = hookenv.config('logrotate-retention')50 logrotate_retention = hookenv.config("logrotate-retention")
51 with open('/etc/logrotate_cronjob_config', 'w+') as cronjob_config_file:51 with open("/etc/logrotate_cronjob_config", "w+") as cronjob_config_file:
52 cronjob_config_file.write(str(cronjob_enabled) + '\n')52 cronjob_config_file.write(str(cronjob_enabled) + "\n")
53 cronjob_config_file.write(str(cronjob_frequency) + '\n')53 cronjob_config_file.write(str(cronjob_frequency) + "\n")
54 cronjob_config_file.write(str(logrotate_retention) + '\n')54 cronjob_config_file.write(str(logrotate_retention) + "\n")
diff --git a/src/tests/functional/conftest.py b/src/tests/functional/conftest.py
index 1b22cb8..2cc4343 100644
--- a/src/tests/functional/conftest.py
+++ b/src/tests/functional/conftest.py
@@ -21,7 +21,7 @@ from juju_tools import JujuTools
21import pytest21import pytest
2222
2323
24@pytest.fixture(scope='module')24@pytest.fixture(scope="module")
25def event_loop():25def event_loop():
26 """Override the default pytest event loop.26 """Override the default pytest event loop.
2727
@@ -35,7 +35,7 @@ def event_loop():
35 asyncio.set_event_loop(None)35 asyncio.set_event_loop(None)
3636
3737
38@pytest.fixture(scope='module')38@pytest.fixture(scope="module")
39async def controller():39async def controller():
40 """Connect to the current controller."""40 """Connect to the current controller."""
41 _controller = Controller()41 _controller = Controller()
@@ -44,27 +44,28 @@ async def controller():
44 await _controller.disconnect()44 await _controller.disconnect()
4545
4646
47@pytest.fixture(scope='module')47@pytest.fixture(scope="module")
48async def model(controller):48async def model(controller):
49 """Live only for the duration of the test."""49 """Live only for the duration of the test."""
50 model_name = "functest-{}".format(str(uuid.uuid4())[-12:])50 model_name = "functest-{}".format(str(uuid.uuid4())[-12:])
51 _model = await controller.add_model(model_name,51 _model = await controller.add_model(
52 cloud_name=os.getenv('PYTEST_CLOUD_NAME'),52 model_name,
53 region=os.getenv('PYTEST_CLOUD_REGION'),53 cloud_name=os.getenv("PYTEST_CLOUD_NAME"),
54 )54 region=os.getenv("PYTEST_CLOUD_REGION"),
55 )
55 # https://github.com/juju/python-libjuju/issues/26756 # https://github.com/juju/python-libjuju/issues/267
56 subprocess.check_call(['juju', 'models'])57 subprocess.check_call(["juju", "models"])
57 while model_name not in await controller.list_models():58 while model_name not in await controller.list_models():
58 await asyncio.sleep(1)59 await asyncio.sleep(1)
59 yield _model60 yield _model
60 await _model.disconnect()61 await _model.disconnect()
61 if not os.getenv('PYTEST_KEEP_MODEL'):62 if not os.getenv("PYTEST_KEEP_MODEL"):
62 await controller.destroy_model(model_name)63 await controller.destroy_model(model_name)
63 while model_name in await controller.list_models():64 while model_name in await controller.list_models():
64 await asyncio.sleep(1)65 await asyncio.sleep(1)
6566
6667
67@pytest.fixture(scope='module')68@pytest.fixture(scope="module")
68async def jujutools(controller, model):69async def jujutools(controller, model):
69 """Juju tools."""70 """Juju tools."""
70 tools = JujuTools(controller, model)71 tools = JujuTools(controller, model)
diff --git a/src/tests/functional/juju_tools.py b/src/tests/functional/juju_tools.py
index 5e4a1cc..6ce6f10 100644
--- a/src/tests/functional/juju_tools.py
+++ b/src/tests/functional/juju_tools.py
@@ -37,14 +37,17 @@ class JujuTools:
37 :param target: Unit object or unit name string37 :param target: Unit object or unit name string
38 """38 """
39 python3 = "python3 -c '{}'"39 python3 = "python3 -c '{}'"
40 python_cmd = ('import pickle;'40 python_cmd = (
41 'import base64;'41 "import pickle;"
42 '{}'42 "import base64;"
43 'print(base64.b64encode(pickle.dumps({})), end="")'43 "{}"
44 .format(imports, remote_cmd))44 'print(base64.b64encode(pickle.dumps({})), end="")'.format(
45 imports, remote_cmd
46 )
47 )
45 cmd = python3.format(python_cmd)48 cmd = python3.format(python_cmd)
46 results = await self.run_command(cmd, target)49 results = await self.run_command(cmd, target)
47 return pickle.loads(base64.b64decode(bytes(results['Stdout'][2:-1], 'utf8')))50 return pickle.loads(base64.b64decode(bytes(results["Stdout"][2:-1], "utf8")))
4851
49 async def file_stat(self, path, target):52 async def file_stat(self, path, target):
50 """Run stat on a file.53 """Run stat on a file.
@@ -52,9 +55,8 @@ class JujuTools:
52 :param path: File path55 :param path: File path
53 :param target: Unit object or unit name string56 :param target: Unit object or unit name string
54 """57 """
55 imports = 'import os;'58 imports = "import os;"
56 python_cmd = ('os.stat("{}")'59 python_cmd = 'os.stat("{}")'.format(path)
57 .format(path))
58 print("Calling remote cmd: " + python_cmd)60 print("Calling remote cmd: " + python_cmd)
59 return await self.remote_object(imports, python_cmd, target)61 return await self.remote_object(imports, python_cmd, target)
6062
@@ -64,6 +66,6 @@ class JujuTools:
64 :param path: File path66 :param path: File path
65 :param target: Unit object or unit name string67 :param target: Unit object or unit name string
66 """68 """
67 cmd = 'cat {}'.format(path)69 cmd = "cat {}".format(path)
68 result = await self.run_command(cmd, target)70 result = await self.run_command(cmd, target)
69 return result['Stdout']71 return result["Stdout"]
diff --git a/src/tests/functional/test_logrotate.py b/src/tests/functional/test_logrotate.py
index 936c577..68ecce0 100644
--- a/src/tests/functional/test_logrotate.py
+++ b/src/tests/functional/test_logrotate.py
@@ -6,48 +6,44 @@ import os
6import pytest6import pytest
77
8pytestmark = pytest.mark.asyncio8pytestmark = pytest.mark.asyncio
9SERIES = ['xenial',9SERIES = [
10 'bionic',10 "xenial",
11 'focal',11 "bionic",
12 ]12 "focal",
13]
1314
1415
15############16############
16# FIXTURES #17# FIXTURES #
17############18############
1819
19@pytest.fixture(scope='module',20
20 params=SERIES)21@pytest.fixture(scope="module", params=SERIES)
21async def deploy_app(request, model):22async def deploy_app(request, model):
22 """Deploy the logrotate charm as a subordinate of ubuntu."""23 """Deploy the logrotate charm as a subordinate of ubuntu."""
23 release = request.param24 release = request.param
2425
25 await model.deploy(26 await model.deploy(
26 'ubuntu',27 "ubuntu", application_name="ubuntu-" + release, series=release, channel="stable"
27 application_name='ubuntu-' + release,
28 series=release,
29 channel='stable'
30 )28 )
31 logrotate_app = await model.deploy(29 logrotate_app = await model.deploy(
32 '{}/logrotated'.format(os.getenv('CHARM_BUILD_DIR')),30 "{}/logrotated".format(os.getenv("CHARM_BUILD_DIR")),
33 application_name='logrotate-' + release,31 application_name="logrotate-" + release,
34 series=release,32 series=release,
35 num_units=0,33 num_units=0,
36 )34 )
37 await model.add_relation(35 await model.add_relation("ubuntu-" + release, "logrotate-" + release)
38 'ubuntu-' + release,
39 'logrotate-' + release
40 )
4136
42 await model.block_until(lambda: logrotate_app.status == 'active')37 await model.block_until(lambda: logrotate_app.status == "active")
43 yield logrotate_app38 yield logrotate_app
4439
4540
46@pytest.fixture(scope='module')41@pytest.fixture(scope="module")
47async def unit(deploy_app):42async def unit(deploy_app):
48 """Return the logrotate unit we've deployed."""43 """Return the logrotate unit we've deployed."""
49 return deploy_app.units.pop()44 return deploy_app.units.pop()
5045
46
51#########47#########
52# TESTS #48# TESTS #
53#########49#########
@@ -55,4 +51,4 @@ async def unit(deploy_app):
5551
56async def test_deploy(deploy_app):52async def test_deploy(deploy_app):
57 """Tst the deployment."""53 """Tst the deployment."""
58 assert deploy_app.status == 'active'54 assert deploy_app.status == "active"
diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py
index b4c0517..2bb8eb8 100644
--- a/src/tests/unit/conftest.py
+++ b/src/tests/unit/conftest.py
@@ -12,19 +12,20 @@ import pytest
12def mock_layers(monkeypatch):12def mock_layers(monkeypatch):
13 """Layers mock."""13 """Layers mock."""
14 import sys14 import sys
15 sys.modules['charms.layer'] = mock.Mock()15
16 sys.modules['reactive'] = mock.Mock()16 sys.modules["charms.layer"] = mock.Mock()
17 sys.modules["reactive"] = mock.Mock()
17 # Mock any functions in layers that need to be mocked here18 # Mock any functions in layers that need to be mocked here
1819
19 def options(layer):20 def options(layer):
20 # mock options for layers here21 # mock options for layers here
21 if layer == 'example-layer':22 if layer == "example-layer":
22 options = {'port': 9999}23 options = {"port": 9999}
23 return options24 return options
24 else:25 else:
25 return None26 return None
2627
27 monkeypatch.setattr('lib_logrotate.layer.options', options)28 monkeypatch.setattr("lib_logrotate.layer.options", options)
2829
2930
30@pytest.fixture31@pytest.fixture
@@ -34,38 +35,39 @@ def mock_hookenv_config(monkeypatch):
3435
35 def mock_config():36 def mock_config():
36 cfg = {}37 cfg = {}
37 yml = yaml.load(open('./config.yaml'))38 yml = yaml.load(open("./config.yaml"))
3839
39 # Load all defaults40 # Load all defaults
40 for key, value in yml['options'].items():41 for key, value in yml["options"].items():
41 cfg[key] = value['default']42 cfg[key] = value["default"]
4243
43 # Manually add cfg from other layers44 # Manually add cfg from other layers
44 # cfg['my-other-layer'] = 'mock'45 # cfg['my-other-layer'] = 'mock'
45 return cfg46 return cfg
4647
47 monkeypatch.setattr('lib_logrotate.hookenv.config', mock_config)48 monkeypatch.setattr("lib_logrotate.hookenv.config", mock_config)
4849
4950
50@pytest.fixture51@pytest.fixture
51def mock_remote_unit(monkeypatch):52def mock_remote_unit(monkeypatch):
52 """Remote unit mock."""53 """Remote unit mock."""
53 monkeypatch.setattr('lib_logrotate.hookenv.remote_unit', lambda: 'unit-mock/0')54 monkeypatch.setattr("lib_logrotate.hookenv.remote_unit", lambda: "unit-mock/0")
5455
5556
56@pytest.fixture57@pytest.fixture
57def mock_charm_dir(monkeypatch):58def mock_charm_dir(monkeypatch):
58 """Charm dir mock."""59 """Charm dir mock."""
59 monkeypatch.setattr('lib_logrotate.hookenv.charm_dir', lambda: '/mock/charm/dir')60 monkeypatch.setattr("lib_logrotate.hookenv.charm_dir", lambda: "/mock/charm/dir")
6061
6162
62@pytest.fixture63@pytest.fixture
63def logrotate(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch):64def logrotate(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch):
64 """Logrotate fixture."""65 """Logrotate fixture."""
65 from lib_logrotate import LogrotateHelper66 from lib_logrotate import LogrotateHelper
67
66 helper = LogrotateHelper68 helper = LogrotateHelper
6769
68 # Any other functions that load helper will get this version70 # Any other functions that load helper will get this version
69 monkeypatch.setattr('lib_logrotate.LogrotateHelper', lambda: helper)71 monkeypatch.setattr("lib_logrotate.LogrotateHelper", lambda: helper)
7072
71 return helper73 return helper
diff --git a/src/tests/unit/test_logrotate.py b/src/tests/unit/test_logrotate.py
index 68ed164..b317257 100644
--- a/src/tests/unit/test_logrotate.py
+++ b/src/tests/unit/test_logrotate.py
@@ -1,7 +1,7 @@
1"""Main unit test module."""1"""Main unit test module."""
22
33
4class TestLogrotateHelper():4class TestLogrotateHelper:
5 """Main test class."""5 """Main test class."""
66
7 def test_pytest(self):7 def test_pytest(self):
@@ -11,28 +11,28 @@ class TestLogrotateHelper():
11 def test_daily_retention_count(self, logrotate):11 def test_daily_retention_count(self, logrotate):
12 """Test daily retention count."""12 """Test daily retention count."""
13 logrotate.retention = 9013 logrotate.retention = 90
14 contents = '/var/log/some.log {\n rotate 123\n daily\n}'14 contents = "/var/log/some.log {\n rotate 123\n daily\n}"
15 count = logrotate.calculate_count(contents, logrotate.retention)15 count = logrotate.calculate_count(contents, logrotate.retention)
16 assert count == 9016 assert count == 90
1717
18 def test_weekly_retention_count(self, logrotate):18 def test_weekly_retention_count(self, logrotate):
19 """Test weekly retention count."""19 """Test weekly retention count."""
20 logrotate.retention = 2120 logrotate.retention = 21
21 contents = '/var/log/some.log {\n rotate 123\n weekly\n}'21 contents = "/var/log/some.log {\n rotate 123\n weekly\n}"
22 count = logrotate.calculate_count(contents, logrotate.retention)22 count = logrotate.calculate_count(contents, logrotate.retention)
23 assert count == 323 assert count == 3
2424
25 def test_monthly_retention_count(self, logrotate):25 def test_monthly_retention_count(self, logrotate):
26 """Test monthly retention count."""26 """Test monthly retention count."""
27 logrotate.retention = 6027 logrotate.retention = 60
28 contents = '/var/log/some.log {\n rotate 123\n monthly\n}'28 contents = "/var/log/some.log {\n rotate 123\n monthly\n}"
29 count = logrotate.calculate_count(contents, logrotate.retention)29 count = logrotate.calculate_count(contents, logrotate.retention)
30 assert count == 230 assert count == 2
3131
32 def test_yearly_retention_count(self, logrotate):32 def test_yearly_retention_count(self, logrotate):
33 """Test yearly retention count."""33 """Test yearly retention count."""
34 logrotate.retention = 18034 logrotate.retention = 180
35 contents = '/var/log/some.log {\n rotate 123\n yearly\n}'35 contents = "/var/log/some.log {\n rotate 123\n yearly\n}"
36 count = logrotate.calculate_count(contents, logrotate.retention)36 count = logrotate.calculate_count(contents, logrotate.retention)
37 assert count == 137 assert count == 1
3838
@@ -42,9 +42,15 @@ class TestLogrotateHelper():
42 logrotate.retention = 4242 logrotate.retention = 42
43 logrotate.override = []43 logrotate.override = []
44 logrotate.override_files = []44 logrotate.override_files = []
45 contents = '/log/some.log {\n rotate 123\n daily\n}\n/log/other.log {\n rotate 456\n weekly\n}'45 contents = (
46 "/log/some.log {\n rotate 123\n daily\n}\n"
47 "/log/other.log {\n rotate 456\n weekly\n}"
48 )
46 mod_contents = logrotate.modify_content(logrotate, contents, file_path)49 mod_contents = logrotate.modify_content(logrotate, contents, file_path)
47 expected_contents = '/log/some.log {\n rotate 42\n daily\n}\n\n/log/other.log {\n rotate 6\n weekly\n}\n'50 expected_contents = (
51 "/log/some.log {\n rotate 42\n daily\n}\n\n"
52 "/log/other.log {\n rotate 6\n weekly\n}\n"
53 )
48 assert mod_contents == expected_contents54 assert mod_contents == expected_contents
4955
50 def test_modify_content_override(self, logrotate):56 def test_modify_content_override(self, logrotate):
@@ -53,7 +59,13 @@ class TestLogrotateHelper():
53 logrotate.retention = 4259 logrotate.retention = 42
54 logrotate.override = []60 logrotate.override = []
55 logrotate.override_files = []61 logrotate.override_files = []
56 contents = '/log/some.log {\n rotate 123\n daily\n}\n/log/other.log {\n rotate 456\n weekly\n}'62 contents = (
63 "/log/some.log {\n rotate 123\n daily\n}\n"
64 "/log/other.log {\n rotate 456\n weekly\n}"
65 )
57 mod_contents = logrotate.modify_content(logrotate, contents, file_path)66 mod_contents = logrotate.modify_content(logrotate, contents, file_path)
58 expected_contents = '/log/some.log {\n rotate 42\n daily\n}\n\n/log/other.log {\n rotate 6\n weekly\n}\n'67 expected_contents = (
68 "/log/some.log {\n rotate 42\n daily\n}\n\n"
69 "/log/other.log {\n rotate 6\n weekly\n}\n"
70 )
59 assert mod_contents == expected_contents71 assert mod_contents == expected_contents
diff --git a/src/tox.ini b/src/tox.ini
index 78da1be..2900ead 100644
--- a/src/tox.ini
+++ b/src/tox.ini
@@ -25,7 +25,7 @@ passenv =
25[testenv:lint]25[testenv:lint]
26commands =26commands =
27 flake827 flake8
28#TODO black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .28 black --check --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .
29deps =29deps =
30 black30 black
31 flake831 flake8
@@ -43,12 +43,9 @@ exclude =
43 mod,43 mod,
44 .build44 .build
4545
46#max-line-length = 8846max-line-length = 88
47max-complexity = 1047max-complexity = 10
4848
49# from old tox.ini
50max-line-length = 120
51
52[testenv:black]49[testenv:black]
53commands =50commands =
54 black --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .51 black --exclude "/(\.eggs|\.git|\.tox|\.venv|\.build|dist|charmhelpers|mod)/" .

Subscribers

People subscribed via source and target branches

to all changes: