Skip to content
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

[WIP][backend] Added support for plugins. #120

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions netjsonconfig/backends/base/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class BaseBackend(object):
schema = None
FILE_SECTION_DELIMITER = '# ---------- files ---------- #'
list_identifiers = []
plugins = []

def __init__(self, config=None, native=None, templates=None, context=None):
"""
Expand Down Expand Up @@ -49,6 +50,17 @@ def __init__(self, config=None, native=None, templates=None, context=None):
raise ValueError('Expecting either config or native argument to be '
'passed during the initialization of the backend')

@classmethod
def add_plugins(cls, plugins):
for plugin in plugins:
plugin.schema.pop('$schema', None)
if getattr(cls, 'schema'):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as I was saying, we expect backend to always have a schema, therefore if schema is not present we should "fail early and loud"

cls.schema['properties'][plugin.key] = plugin.schema
if getattr(cls, 'converters'):
cls.converters.append(plugin.converter)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's the same here, what's the use case of not having any converter declared? Wouldn't it just be wrong?

else:
cls.converters = [plugin.converter]

def _load(self, config):
"""
Loads config from string or dict
Expand Down
59 changes: 59 additions & 0 deletions tests/openwrt/test_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,34 @@
from netjsonconfig import OpenWrt
from netjsonconfig.exceptions import ValidationError
from netjsonconfig.utils import _TabsMixin
from netjsonconfig.backends.openwrt.converters.base import OpenWrtConverter


class CoovaConverter(OpenWrtConverter):
netjson_key = 'chilli'
_uci_types = ['chilli']

def to_intermediate_loop(self, block, result, index=None):
if block:
block.update({
'.type': 'chilli',
'.name': 'chilli'
})
result['chilli'] = [self.sorted_dict(block)]
return result


class CoovaPlugin(object):
key = 'chilli'
converter = CoovaConverter
schema = {
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"disabled": {"type": "integer"},
"uamsecret": {"type": "string"},
},
}


class TestBackend(unittest.TestCase, _TabsMixin):
Expand All @@ -19,6 +47,37 @@ def test_config_copy(self):
o.validate()
self.assertDictEqual(config, {'interfaces': []})

def test_plugin(self):
config = {
"chilli": {
'disabled': 1,
'uamsecret': 'asd123fghj'
},
}
OpenWrt.add_plugins([CoovaPlugin()])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep in mind that once you do this, the plugin will be enabled during all the tests that are called afterwards (even other test classes), this may have unintended consequences in the future, I think you should do two things:

  • subclass the OpenWrt backend here in this file, redefine the schema and converters attributes to explicitly use a copy (use deepcopy) of OpenWrt.schema and OpenWrt.converters, then use the subclass here in the tests
  • add a tearDown method which cleans up any additional plugin every time a test method terminates execution

o = OpenWrt(config)
self.assertEqual(self._tabs('''package chilli

config chilli 'chilli'
option disabled '1'
option uamsecret 'asd123fghj'
'''), o.render())

def test_bad_plugin_config(self):
config = {
"chilli": {
'disabled': 'wrong_value',
'uamsecret': 'asd123fghj'
},
}
OpenWrt.add_plugins([CoovaPlugin()])
o = OpenWrt(config)
try:
o.render()
self.fail()
except ValidationError as e:
self.assertEqual(e.message, "'wrong_value' is not of type 'integer'")

def test_json_method(self):
config = {
"type": "DeviceConfiguration",
Expand Down