def test_update_squashing(self): # set some data self.block["attr"] = Dummy() self.block.attr["value"] = 32 self.block["attr2"] = Dummy() self.block.attr2["value"] = "st" # subscribe once and check initial response r1 = Subscribe(path=["b"], delta=True) r1.set_callback(Mock()) r2 = Subscribe(path=["b"]) r2.set_callback(Mock()) self.handle_subscribe(r1) self.handle_subscribe(r2) expected = OrderedDict() expected["attr"] = dict(value=32) expected["attr2"] = dict(value="st") self.assert_called_with(r1.callback, Delta(changes=[[[], expected]])) self.assert_called_with(r2.callback, Update(value=expected)) r1.callback.reset_mock() r2.callback.reset_mock() # squash two changes together with self.o.changes_squashed: self.block.attr["value"] = 33 self.o.add_squashed_change(["b", "attr", "value"], 33) assert self.block.attr.value == 33 self.block.attr2["value"] = "tr" self.o.add_squashed_change(["b", "attr2", "value"], "tr") assert self.block.attr2.value == "tr" self.assert_called_with( r1.callback, Delta( changes=[[["attr", "value"], 33], [["attr2", "value"], "tr"]])) expected["attr"]["value"] = 33 expected["attr2"]["value"] = "tr" self.assert_called_with(r2.callback, Update(value=expected))
def test_Delta(self): context = Mock() changes = [[["path"], "value"]] r = Delta(123, context, changes) self.assertEquals(123, r.id_) self.assertEquals(context, r.context) self.assertEquals(changes, r.changes) r.set_changes([[["path"], "value2"]]) self.assertEquals([[["path"], "value2"]], r.changes)
def test_2_subscribes(self): # set some data self.block["attr"] = Dummy() self.block.attr["value"] = 32 # subscribe once and check initial response r1 = Subscribe(path=["b", "attr", "value"], delta=False) r1.set_callback(Mock()) self.handle_subscribe(r1) self.assert_called_with(r1.callback, Update(value=32)) r1.callback.reset_mock() # subscribe again and check initial response r2 = Subscribe(path=["b"], delta=True) r2.set_callback(Mock()) self.handle_subscribe(r2) self.assert_called_with( r2.callback, Delta(changes=[[[], dict(attr=dict(value=32))]]) ) r2.callback.reset_mock() # set some data and check only second got called self.block["attr2"] = Dummy() with self.o.changes_squashed: self.block.attr2["value"] = "st" self.o.add_squashed_change(["b", "attr2"], self.block.attr2) r1.callback.assert_not_called() self.assert_called_with( r2.callback, Delta(changes=[[["attr2"], dict(value="st")]]) ) r2.callback.reset_mock() # delete the first and check calls with self.o.changes_squashed: self.block.data.pop("attr") self.o.add_squashed_delete(["b", "attr"]) self.assert_called_with(r1.callback, Update(value=None)) r1.callback.reset_mock() self.assert_called_with(r2.callback, Delta(changes=[[["attr"]]])) r2.callback.reset_mock() # add it again and check updates self.block["attr"] = Dummy() with self.o.changes_squashed: self.block.attr["value"] = 22 self.o.add_squashed_change(["b", "attr"], self.block.attr) self.assert_called_with(r1.callback, Update(value=22)) self.assert_called_with( r2.callback, Delta(changes=[[["attr"], dict(value=22)]]) )
def respond_with_delta(self, changes): """ Create a Delta Response object to handle the request Args: changes (list): list of [[path], value] pairs for changed values """ response = Delta(self.id, self.context, changes=changes) self.response_queue.put(response)
def test_callback_unexpected(self): t = Task("testTask", self.proc) resp = Delta(0, None, None) t.q.put(resp) t.stop() t.subscribe(self.attr, self._callback, 3, 5) f1 = Future(t) t._futures = {1: f1} self.assertRaises(ValueError, t.wait_all, f1, 0)
def test_respond_with_delta(self): changes = [[["path"], "value"]] self.subscribe.respond_with_delta(changes) call_arg = self.response_queue.put.call_args_list[0][0][0].to_dict() expected_response = Delta(self.subscribe.id_, self.subscribe.context, changes=changes).to_dict() self.assertEqual(call_arg, expected_response)
def test_send_to_client(self): self.PVA = PvaServerComms(self.p) self.PVA._update_cache = MagicMock() rpc_mock1 = MagicMock() rpc_mock2 = MagicMock() self.PVA._rpcs[1] = rpc_mock1 self.PVA._rpcs[2] = rpc_mock2 response1 = Return(id_=1) self.PVA.send_to_client(response1) rpc_mock1.notify_reply.assert_has_calls([call(response1)]) response2 = Error(id_=2) self.PVA.send_to_client(response2) rpc_mock2.notify_reply.assert_has_calls([call(response2)]) response3 = Delta(id_=3) self.PVA.send_to_client(response3) self.PVA._update_cache.assert_has_calls([call(response3)])
def test_update_cache(self): self.PVA = PvaServerComms(self.p) self.PVA._add_new_pva_channel = MagicMock() request = Delta(id_=1, changes=[[["block1"], 1], [["block2"], 2], [["block3"], 3]]) self.PVA._update_cache(request) calls = [call("block1"), call("block2"), call("block3")] self.PVA._add_new_pva_channel.assert_has_calls(calls, any_order=True) self.assertEqual(self.PVA._cache, { "block1": 1, "block2": 2, "block3": 3 })
def _handle_block_notify(self, request): """Update subscribers with changes and applies stored changes to the cached structure""" # update cached dict for delta in self._last_changes.setdefault(request.name, []): self._block_state_cache.delta_update(delta) for subscription in self._subscriptions.setdefault(request.name, []): endpoint = subscription.endpoint # find stuff that's changed that is relevant to this subscriber changes = [] for change in self._last_changes[request.name]: change_path = change[0] # look for a change_path where the beginning matches the # endpoint path, then strip away the matching part and add # to the change set i = 0 for (cp_element, ep_element) in zip(change_path, endpoint): if cp_element != ep_element: break i += 1 else: # change has matching path, so keep it # but strip off the end point path filtered_change = [change_path[i:]] + change[1:] changes.append(filtered_change) if len(changes) > 0: if subscription.delta: # respond with the filtered changes response = Delta(subscription.id_, subscription.context, changes) else: # respond with the structure of everything # below the endpoint d = self._block_state_cache.walk_path(endpoint) response = Update(subscription.id_, subscription.context, d) self.log_debug("Responding to subscription %s", response) subscription.response_queue.put(response) self._last_changes[request.name] = []
def test_wait_all(self): t = Task("testTask", self.proc) f1 = Future(t) f2 = Future(t) f3 = Future(t) f0 = Future(t) t._futures = {0: f0, 1: f1, 2: f2, 3: f3} f_wait1 = [f2, f0] self.assertRaises(queue.Empty, t.wait_all, f_wait1, 0) resp0 = Return(0, None, None) resp0.set_value('testVal') resp2 = Error(2, None, None) t.q.put(resp0) t.q.put(resp2) self.assertRaises(ValueError, t.wait_all, f_wait1, 0) self.assertEqual(t._futures, {1: f1, 3: f3}) self.assertEqual(f0.done(), True) self.assertEqual(f1.done(), False) self.assertEqual(f2.done(), True) self.assertEqual(f3.done(), False) self.assertEqual(self.proc.q.qsize(), 0) resp3 = Delta(3, None, None) t.q.put(resp3) f_wait1 = [f3] self.assertRaises(ValueError, t.wait_all, f_wait1, 0.01) t.stop() self.assertRaises(StopIteration, t.wait_all, f_wait1, 0.01) resp1 = Return(1, None, None) resp1.set_value('testVal') t.q.put(resp1) self.assertRaises(queue.Empty, t.wait_all, f_wait1, 0.01) self.assertEqual(t._futures, {}) t._futures = {0: f0, 1: f1, 2: f2} t.q.put(resp1) t.q.put(Spawnable.STOP) self.assertEqual(f1.result(), 'testVal')
def test_update_exist_and_nonexist_sub(self): d = dict(d=dict(a=32)) r = Delta(changes=[[["d", "b", "x"], 3]]) r.apply_changes_to(d) assert d == dict(d=dict(a=32, b=dict(x=3)))
def test_Delta(self): changes = [[["state", "value"], "Running"]] r = Delta(123, changes) assert r.typeid == "malcolm:core/Delta:1.0" assert r.id == 123 assert r.changes == changes
def test_respond_with_delta(self): changes = [[["path"], "value"]] cb, response = self.o.delta_response(changes) assert cb == self.callback assert response.to_dict() == Delta(id=11, changes=changes).to_dict()
def test_handle_response_unknown(self): response = Delta(None, None, []) self.assertRaises(TypeError, self.item.handle_response, response)
def test_update_nonexisting_sub_key(self): d = dict(d=dict(a=32)) r = Delta(changes=[[["c", "a"], 3]]) r.apply_changes_to(d) assert d == dict(d=dict(a=32), c=dict(a=3))
def test_update_nonexisting_key(self): d = dict(a=32) r = Delta(changes=[[["b"], 3]]) r.apply_changes_to(d) assert d == dict(a=32, b=3)
def test_update_root(self): d = dict(a=32) r = Delta(changes=[[[], dict(b=3, c=4)]]) r.apply_changes_to(d) assert d == dict(b=3, c=4)
def test_handle_response_unknown(self): response = Delta(changes=[]) with self.assertRaises(TypeError): self.item.handle_response(response)
def test_send_to_client(self): self.PVA = PvaServerComms(self.p) self.PVA._update_cache = MagicMock() rpc_mock1 = MagicMock() rpc_mock2 = MagicMock() self.PVA._rpcs[1] = rpc_mock1 self.PVA._rpcs[2] = rpc_mock2 response1 = Return(id_=1) self.PVA.send_to_client(response1) rpc_mock1.notify_reply.assert_has_calls([call(response1)]) response2 = Error(id_=2) self.PVA.send_to_client(response2) rpc_mock2.notify_reply.assert_has_calls([call(response2)]) response3 = Return(id_=3) self.PVA.send_to_client(response3) rpc_mock1.notify_reply.assert_has_calls([call(response1)]) rpc_mock2.notify_reply.assert_has_calls([call(response2)]) # Gets get_mock1 = MagicMock() get_mock2 = MagicMock() self.PVA._gets[3] = get_mock1 self.PVA._gets[4] = get_mock2 response1 = Return(id_=3) self.PVA.send_to_client(response1) get_mock1.notify_reply.assert_has_calls([call(response1)]) response2 = Error(id_=4) self.PVA.send_to_client(response2) get_mock2.notify_reply.assert_has_calls([call(response2)]) response3 = Return(id_=5) self.PVA.send_to_client(response3) get_mock1.notify_reply.assert_has_calls([call(response1)]) get_mock2.notify_reply.assert_has_calls([call(response2)]) # Puts put_mock1 = MagicMock() put_mock2 = MagicMock() self.PVA._puts[5] = put_mock1 self.PVA._puts[6] = put_mock2 response1 = Return(id_=5) self.PVA.send_to_client(response1) put_mock1.notify_reply.assert_has_calls([call(response1)]) response2 = Error(id_=6) self.PVA.send_to_client(response2) put_mock2.notify_reply.assert_has_calls([call(response2)]) response3 = Return(id_=7) self.PVA.send_to_client(response3) put_mock1.notify_reply.assert_has_calls([call(response1)]) put_mock2.notify_reply.assert_has_calls([call(response2)]) # Monitors mon_mock1 = MagicMock() mon_mock2 = MagicMock() self.PVA._monitors[7] = mon_mock1 self.PVA._monitors[8] = mon_mock2 response1 = Return(id_=7) self.PVA.send_to_client(response1) mon_mock1.notify_reply.assert_has_calls([call(response1)]) response2 = Error(id_=8) self.PVA.send_to_client(response2) mon_mock2.notify_reply.assert_has_calls([call(response2)]) response3 = Return(id_=9) self.PVA.send_to_client(response3) mon_mock1.notify_reply.assert_has_calls([call(response1)]) mon_mock2.notify_reply.assert_has_calls([call(response2)]) # Delta mon_mock3 = MagicMock() self.PVA._monitors[9] = mon_mock3 response3 = Delta(id_=9) self.PVA.send_to_client(response3) mon_mock3.update.assert_has_calls([call(response3["changes"])]) # Updates self.PVA._update_local_block_list = MagicMock() self.PVA._update_remote_block_list = MagicMock() response4 = Update(id_=self.PVA._local_block_id) response5 = Update(id_=self.PVA._remote_block_id) self.PVA.send_to_client(response4) self.PVA._update_local_block_list.assert_called_once() self.PVA.send_to_client(response5) self.PVA._update_remote_block_list.assert_called_once()