-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactoring for testing #18
base: master
Are you sure you want to change the base?
Conversation
This prepares the overall code structure for entry points including removal of the shell script. Managing the cron-script is not functional yet. Nothing has been tested either. Committing so I can sync with a box where I can test.
Passing script-path is also no longer required.
No longer need the "vendor" copy
Should play niced with virtualenvs (removes the risk of a name-clash).
Having the CRON commands in a separate module reduces the "contact area" between our application and the external dependency. This makes both testing and replacing the dependency easier in the future.
These tests surfaced two bugs which have been fixed with this commit as well.
It was running under the namespace "InfluxdbClient" yet it had nothing to do with it. This makes it more veratile and removed a dependency on InfluxdbClient from `grafana.py`
Using a string literal here leads to incorrect exception messages when the key "group_fields" does not exist (or any other exception on the preceding line). Using a proper code-comment remedies this.
the existing code does not do anything useful.
@@ -1,33 +0,0 @@ | |||
#!/usr/bin/env bash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This shell shript has been replaced with munininfluxdb/main.py
@@ -0,0 +1,110 @@ | |||
from __future__ import print_function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of the subcommands of the main command. It is loaded in munininfluxdb/main.py
. In this particular case, it contains the cron
code which I extracted from the other files. This way, the cron installation and deinstallation can be run separately (as also mentioned in the readme file).
@@ -0,0 +1,80 @@ | |||
import logging |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of the subcommands of the main command. It is loaded in munininfluxdb/main.py
.
@@ -1,31 +1,22 @@ | |||
#!/usr/bin/env python |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of the subcommands of the main command. It is loaded in munininfluxdb/main.py
.
|
||
try: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before touching munin-influxdb
I also sent a PR for storable
which makes the module available on pypi. This has been accepted and we can install it via setup.py dependencies. The vendor
folder is no longer needed.
try: | ||
pwd.getpwnam('munin') | ||
except KeyError: | ||
CRON_USER = 'root' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cron
has been extracted to a separate sub-command. So all cron related stuff has been removed from this file and moved to commands/cron.py
@@ -108,22 +91,15 @@ def main(args): | |||
print("Then we're good! Have a nice day!") | |||
|
|||
|
|||
if __name__ == "__main__": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "main" part of the commands is handled in munininfluxdb/main.py
@@ -112,7 +111,7 @@ def process_graph_types(self, fields): | |||
if hasArea: | |||
self.fill = 5 | |||
self.linewidth = 0 | |||
if hasArea: | |||
if hasStack: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was a bug which surfaced through the unit-tests.
@@ -381,7 +380,7 @@ def create_dashboard(self, dashboardJson): | |||
r.raise_for_status() | |||
|
|||
|
|||
if __name__ == "__main__": | |||
if __name__ == "__main__": # pragma: no cover |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case you have not worked with the coverage module yet: pragma: no cover
prevents lines from being checked for coverage. There were some cases where this made sense to add (lines which are deliberately left out from unit-testing).
self.client, self.valid = None, False | ||
if not silent: | ||
print(" {0} Could not connect to database: {1}".format(Symbol.WARN_YELLOW, e)) | ||
except Exception as e: | ||
LOG.debug(str(e), exc_info=True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not logging anything made debugging very difficult here. This helps a bit.
@@ -107,10 +112,6 @@ def list_columns(self, series="/.*/"): | |||
|
|||
return res | |||
|
|||
@staticmethod |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
extracted for easier mocking/patching.
| ... | | | | | | ||
+----------------------+-------+----------+----------+-----------+ | ||
""" | ||
# In "group_fields" mode, all fields of a same plugin (ex: system, user, nice, idle... of CPU usage) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced the string-literal with comments. Otherwise it's included in coverage which does not make sense.
import os | ||
import sys | ||
import pprint | ||
|
||
from utils import ProgressBar, Symbol | ||
from settings import Settings | ||
|
||
from vendor import storable | ||
import storable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, storable
is now available in pypi and has been added to the setup.py dependencies.
|
||
def discover_from_datafile(settings): | ||
DataFileLine = namedtuple( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a helper to make the code more readable (less use of indices).
'plugin value domain host field property') | ||
|
||
|
||
def parse_datafile_line(line): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted this block of code as separate function which allows us to test it separately.
return DataFileLine(plugin, value, domain, host, field, property) | ||
|
||
|
||
def populate_settings(settings, datafile): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sane thing. Makes testing easier.
This is a large PR. Sorry for the size but I wanted to submit something coherent. I'll try to add line-comments here on GitHub once I created the PR. I hope it's possible.
Most of the code is adding unit-tests. I tried to refrain from making changes to the codes, but there are some exceptions:
I've done my best to keep the commit messages helpful and make atomic commits so it should be a bit easier to follow.
If you have any questions, feel free to ask.