Skip to content

Commit

Permalink
Implement update in Block
Browse files Browse the repository at this point in the history
  • Loading branch information
c-mita committed Jun 29, 2016
1 parent a8b7139 commit a22eb1c
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 2 deletions.
29 changes: 29 additions & 0 deletions malcolm/core/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from malcolm.core.serializable import Serializable
from malcolm.core.request import Request
from malcolm.core.response import Response
from malcolm.core.attribute import Attribute
from malcolm.core.method import Method

@contextmanager
def dummy_lock():
Expand Down Expand Up @@ -60,6 +62,33 @@ def add_method(self, method):
self.on_changed([[method.name], method.to_dict()])
self.notify_subscribers()

def update(self, change):
"""Update block given a single change.
Delegates to children update methods if possible.
Args:
change [[path], new value]: Path to changed element and new value
"""
name = change[0][0]
if hasattr(self, name):
# sub-structure exists in block - delegate down
# TODO: handle removal?
getattr(self, name).update([change[0][1:], change[1]])
else:
# sub-structure does not exist - create and add
if len(change[0]) > 1:
raise ValueError("Missing substructure at %s" % name)
obj = Serializable.from_dict(name, change[1])
if isinstance(obj, Method):
self.add_method(obj)
elif isinstance(obj, Attribute):
self.add_attribute(obj)
else:
raise ValueError(
"Change %s deserialized to unknown object %s"
% (change, obj))


def notify_subscribers(self):
if self.parent is not None:
self.parent.notify_subscribers(self.name)
Expand Down
2 changes: 1 addition & 1 deletion malcolm/core/serializable.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,6 @@ def on_changed(self, change, notify=True):
path.insert(0, self.name)
self.parent.on_changed(change, notify)

def update(self, d):
def update(self, change):
raise NotImplementedError(
"Abstract update function must be implemented in child classes")
66 changes: 65 additions & 1 deletion tests/test_core/test_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
from collections import OrderedDict

import unittest
from mock import MagicMock, call
from mock import MagicMock, call, patch

# module imports
from malcolm.core.block import Block
from malcolm.core.attribute import Attribute
from malcolm.core.stringmeta import StringMeta
from malcolm.core.method import Method
from malcolm.core.serializable import Serializable


class TestBlock(unittest.TestCase):
Expand Down Expand Up @@ -68,6 +72,66 @@ def exit_side_effect(*args):
[call.acquire(), call.release(), call.acquire(), call.release()],
lock_methods.method_calls)

class TestUpdates(unittest.TestCase):

def test_simple_update(self):
b = Block("b")
m = MagicMock()
m.name = "m"
b.m = m
change_dict = MagicMock()
change = [["m", "sub_structure"], change_dict]
b.update(change)

m.update.assert_called_with([["sub_structure"], change_dict])

def test_update_adds_attribute(self):
b = Block("b")
b.add_attribute = MagicMock(wrap=b.add_attribute)
b.add_method = MagicMock(wrap=b.add_method)
attr_meta = StringMeta("attr", "desc")
attr = Attribute(attr_meta)
change_dict = attr.to_dict()
change = [["attr"], change_dict]

b.update(change)

added_attr = b.add_attribute.call_args[0][0]
self.assertEquals(Attribute, type(added_attr))
self.assertEquals(change_dict, added_attr.to_dict())
b.add_method.assert_not_called()

def test_update_adds_method(self):
b = Block("b")
b.add_attribute = MagicMock(wrap=b.add_attribute)
b.add_method = MagicMock(wrap=b.add_method)
method = Method("method", "desc")
change_dict = method.to_dict()
change = [["method"], change_dict]

b.update(change)

added_method = b.add_method.call_args[0][0]
self.assertEquals(Method, type(added_method))
self.assertEquals(change_dict, added_method.to_dict())
b.add_attribute.assert_not_called()

def test_update_raises_if_missing_path(self):
b = Block("b")
change = [["missing", "path"], MagicMock()]
with self.assertRaises(
ValueError, msg="Missing substructure at %s" % change[0][0]):
b.update(change)

@patch("malcolm.core.serializable.Serializable.from_dict")
def test_update_raises_if_wrong_object(self, from_dict_mock):
b = Block("b")
change = [["path"], MagicMock()]
with self.assertRaises(
ValueError, msg="Change %s deserializaed to unknown object %s"
% (change, from_dict_mock.return_value)):
b.update(change)

class TestToDict(unittest.TestCase):

def test_returns_dict(self):
Expand Down

0 comments on commit a22eb1c

Please sign in to comment.