def _get_watcher(self, path, callback=None): """Creates a Watcher object for the supplid path. Creates a Watcher object for the supplied path and returns the object. Triggers callbacks immediately. This is broken into its own function so that it can leverage the @_health_check decorator. This function should never be called from outside of this class. Args: path: A string representing the path to the servers. callback: (optional) reference to function to call if the path changes. Returns: nd_service_registry.Watcher object """ # Ok, so the cache is missing the key. Lets look for it in Zookeeper log.debug('[%s] Creating Watcher object...' % path) watcher = Watcher(self._zk, path, watch_children=True, callback=callback) # Always register our dictionary saver callback, in addition to # whatever our user has supplied watcher.add_callback(self._save_watcher_to_dict) return watcher
def __init__(self, zk, path, data=None, state=False, ephemeral=False): # Set our local variables self._ephemeral = ephemeral self._zk = zk self._path = path self._state = state # Store both encdoed-string and decoded-dict versions of our 'data' # for comparison purposes later. self._data = data self._encoded_data = funcs.encode(data) self._decoded_data = funcs.decode(self._encoded_data) # Set a default watcher without a callback. self._watcher = Watcher(self._zk, path=self._path, watch_children=False)
def test_watch_on_nonexistent_path_with_multiple_data_changes(self): path = '%s/nonexistent-path-%s' % (self.sandbox, uuid.uuid4().hex) watch = Watcher(zk=self.zk, path=path) # In order to track the number of callbacks that are registered, # we register a mocked method in the callbacks. callback_checker = mock.Mock() callback_checker.test.return_value = True watch.add_callback(callback_checker.test) # Initially, we expect the data, children count and stat data # to be None because the node doesn't exist. self.assertEquals(None, watch.get()['data']) self.assertEquals(None, watch.get()['stat']) self.assertEquals([], watch.get()['children']) # Now register a child node under the path, and expect the # data to change child_path = '%s/my_child_test' % path self.zk.create(child_path, makepath=True) # Wait until the children list changes def get_children(): return watch.get()['children'] waituntil(get_children, [], timeout=5) # Now verify that the data has been updated in our Watcher self.assertTrue('my_child_test' in watch.get()['children']) # Now make a series of data changes and wait for each one to # take effect before moving on to the next one. def get_data(): return watch.get()['data'] for i in range(1, 5): self.zk.set(path, value=('%s' % i).encode('UTF-8')) waituntil(get_data, {'string_value': '%s' % i}, timeout=5, mode=2) # The right number of calls is 6. There are a few upfront calls when # the Watcher object is initialized, and after that there are a few # calls for the updated node-data when new children are added. The # call count would be MUCH higher (11++) if we were recursively # creating Watches though. self.assertEquals(6, len(callback_checker.test.mock_calls))
def test_watch_on_nonexistent_path_with_children_change(self): path = '%s/nonexistent-path-%s' % (self.sandbox, uuid.uuid4().hex) watch = Watcher(zk=self.zk, path=path) # Initially, we expect the data, children count and stat data # to be None because the node doesn't exist. self.assertEquals(None, watch.get()['data']) self.assertEquals(None, watch.get()['stat']) self.assertEquals([], watch.get()['children']) # Now register a child node under the path, and expect the # data to change child_path = '%s/my_child_test' % path self.zk.create(child_path, makepath=True) # Wait until the children list changes def get_children(): return watch.get()['children'] waituntil(get_children, [], timeout=5) # Now verify that the data has been updated in our Watcher self.assertTrue('my_child_test' in watch.get()['children'])
def test_watch_on_nonexistent_path_with_data_change(self): path = '%s/nonexistent-path-%s' % (self.sandbox, uuid.uuid4().hex) watch = Watcher(zk=self.zk, path=path) # Initially, we expect the data, children count and stat data # to be None because the node doesn't exist. self.assertEquals(None, watch.get()['data']) self.assertEquals(None, watch.get()['stat']) self.assertEquals([], watch.get()['children']) # Now, lets go and set the data path with something. We expect the # watcher now to actually register the change. Use the waituntil() # method to wait until the data has been updated. def get_data(): return watch.get()['data'] self.zk.create(path, value=b"{'foo': 'bar'}", makepath=True) waituntil(get_data, None, timeout=5, mode=1) # Now verify that the data has been updated in our Watcher self.assertEquals({'string_value': "{'foo': 'bar'}"}, watch.get()['data']) self.assertNotEquals(None, watch.get()['stat']) self.assertEquals([], watch.get()['children'])
def test_watch_on_existing_path(self): path = '%s/existing-path-%s' % (self.sandbox, uuid.uuid4().hex) self.zk.create(path, makepath=True) watch = Watcher(zk=self.zk, path=path) # We expect there to be valid data... self.assertEquals(None, watch.get()['data']) self.assertNotEquals(None, watch.get()['stat']) self.assertEquals([], watch.get()['children']) # Now register a child node, and expect the data to change child_path = '%s/my_child_test' % path self.zk.create(child_path) # Before progressing, wait for Zookeeper to have kicked off # all of its notifications to the client. def get_children(): print("got: %s" % watch.get()['children']) return watch.get()['children'] waituntil(get_children, [], timeout=5) # Now expect the watch to be kicked off self.assertTrue('my_child_test' in watch.get()['children'])
def test_deleting_node_watcher_is_watching(self): # Create our test path path = '%s/path-to-be-deleted-%s' % (self.sandbox, uuid.uuid4().hex) self.zk.create(path, makepath=True) # Watch it and verify that we got back the proper stat data for # the existing node. watch = Watcher(zk=self.zk, path=path) self.assertTrue(watch.get()['stat'] is not None) # Now, delete it self.zk.delete(path) # Now, wait until the Zookeeper callback has been executed, at which # point, our Watcher object should cleanly update itself indicating # that the path no longer exists. expected_get_results = { 'path': path, 'stat': None, 'data': None, 'children': [] } waituntil(watch.get, expected_get_results, 5, mode=2) self.assertEquals(expected_get_results, watch.get())