def test_exec_function_with_error(self): ''' Attempts to executet a function that raises an error during its execution. Ensures that an error is returned to the user. ''' e_msg = 'This is a broken_function!' def func(_, x): raise ValueError(e_msg) fname = 'func' create_function(func, self.kvs_client, fname) # Put the functin into the KVS and create a function call. call = self._create_function_call(fname, [''], NORMAL) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}, {}) # Retrieve the result from the KVS and ensure that it is the correct # lattice type. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), LWWPairLattice) result = serializer.load_lattice(result) # Check the type and values of the error. self.assertEqual(type(result), tuple) self.assertTrue(e_msg in result[0]) # Unpack the GenericResponse and check its values. response = GenericResponse() response.ParseFromString(result[1]) self.assertEqual(response.success, False) self.assertEqual(response.error, EXECUTION_ERROR)
def test_succesful_pin(self): ''' This test executes a pin operation that is supposed to be successful, and it checks to make sure that that the correct metadata for execution and reporting is generated. ''' # Create a new function in the KVS. fname = 'incr' def func(_, x): return x + 1 create_function(func, self.kvs_client, fname) # Create a pin message and put it into the socket. msg = self.ip + ':' + fname self.socket.inbox.append(msg) # Execute the pin operation. pin(self.socket, self.pusher_cache, self.kvs_client, self.status, self.pinned_functions, self.runtimes, self.exec_counts, self.user_library) # Check that the correct messages were sent and the correct metadata # created. self.assertEqual(len(self.pusher_cache.socket.outbox), 1) response = GenericResponse() response.ParseFromString(self.pusher_cache.socket.outbox[0]) self.assertTrue(response.success) self.assertEqual(func('', 1), self.pinned_functions[fname]('', 1)) self.assertTrue(fname in self.pinned_functions) self.assertTrue(fname in self.runtimes) self.assertTrue(fname in self.exec_counts) self.assertTrue(fname in self.status.functions)
def test_exec_function_causal(self): ''' Tests creating and executing a function in causal mode, ensuring that no messages are sent outside of the system and that the serialized result is as expected. ''' # Create the function and serialize it into a lattice. def func(_, x): return x * x fname = 'square' create_function(func, self.kvs_client, fname, SingleKeyCausalLattice) arg = 2 # Put the function into the KVS and create a function call. call = self._create_function_call(fname, [arg], MULTI) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}, {}) # Assert that there have been 0 messages sent. self.assertEqual(len(self.socket.outbox), 0) # Retrieve the result, ensure it is a MultiKeyCausalLattice, then # deserialize it. Also check to make sure we have an empty vector clock # because this request populated no dependencies. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), MultiKeyCausalLattice) self.assertEqual(result.vector_clock, DEFAULT_VC) result = serializer.load_lattice(result)[0] # Check that the output is equal to a local function execution. self.assertEqual(result, func('', arg))
def test_exec_function_normal(self): ''' Tests creating and executing a function in normal mode, ensuring that no messages are sent outside of the system and that the serialized result is as expected. ''' # Create the function and put it into the KVS. def func(_, x): return x * x fname = 'square' arg = 2 # Put the function into the KVS and create a function call. create_function(func, self.kvs_client, fname) call = self._create_function_call(fname, [arg], NORMAL) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}, {}) # Assert that there have been 0 messages sent. self.assertEqual(len(self.socket.outbox), 0) # Retrieve the result, ensure it is a LWWPairLattice, then deserialize # it. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), LWWPairLattice) result = serializer.load_lattice(result) # Check that the output is equal to a local function execution. self.assertEqual(result, func('', arg))
def test_exec_with_ordered_set(self): ''' Tests a single function execution with an ordered set input as an argument to validate that ordered sets are correctly handled. ''' def func(_, x): return len(x) >= 2 and x[0] < x[1] fname = 'set_order' arg_value = [2, 3] arg_name = 'set' self.kvs_client.put(arg_name, serializer.dump_lattice(arg_value)) # Put the function into the KVS and create a function call. create_function(func, self.kvs_client, fname) call = self._create_function_call( fname, [CloudburstReference(arg_name, True)], NORMAL) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}, {}) # Assert that there have been 0 messages sent. self.assertEqual(len(self.socket.outbox), 0) # Retrieve the result, ensure it is a LWWPairLattice, then deserialize # it. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), LWWPairLattice) result = serializer.load_lattice(result) # Check that the output is equal to a local function execution. self.assertEqual(result, func('', arg_value))
def test_exec_func_with_causal_ref(self): ''' Tests a function execution where the argument is a reference to the KVS in causal mode. Ensures that the result has the correct causal dependencies and metadata. ''' # Create the function and serialize it into a lattice. def func(_, x): return x * x fname = 'square' create_function(func, self.kvs_client, fname, SingleKeyCausalLattice) # Put an argument value into the KVS. arg_value = 2 arg_name = 'key' self.kvs_client.put( arg_name, serializer.dump_lattice(arg_value, MultiKeyCausalLattice)) # Create and serialize the function call. call = self._create_function_call(fname, [DropletReference(arg_name, True)], MULTI) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}) # Assert that there have been 0 messages sent. self.assertEqual(len(self.socket.outbox), 0) # Retrieve the result, ensure it is a MultiKeyCausalLattice, then # deserialize it. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), MultiKeyCausalLattice) self.assertEqual(result.vector_clock, DEFAULT_VC) self.assertEqual(len(result.dependencies.reveal()), 1) self.assertTrue(arg_name in result.dependencies.reveal()) self.assertEqual(result.dependencies.reveal()[arg_name], DEFAULT_VC) result = serializer.load_lattice(result)[0] # Check that the output is equal to a local function execution. self.assertEqual(result, func('', arg_value))
def test_occupied_pin(self): ''' This test attempts to pin a function onto a node where another function is already pinned. We currently only allow one pinned node per machine, so this operation should fail. ''' # Create a new function in the KVS. fname = 'incr' def func(_, x): return x + 1 create_function(func, self.kvs_client, fname) # Create a pin message and put it into the socket. msg = PinFunction(name=fname, response_address=self.ip) self.socket.inbox.append(msg.SerializeToString()) # Add an already pinned_function, so that we reject the request. self.pinned_functions['square'] = lambda _, x: x * x self.runtimes['square'] = [] self.exec_counts['square'] = [] self.status.functions.append('square') # Execute the pin operation. pin(self.socket, self.pusher_cache, self.kvs_client, self.status, self.pinned_functions, self.runtimes, self.exec_counts, self.user_library, False, False) # Check that the correct messages were sent and the correct metadata # created. self.assertEqual(len(self.pusher_cache.socket.outbox), 1) response = GenericResponse() response.ParseFromString(self.pusher_cache.socket.outbox[0]) self.assertFalse(response.success) # Make sure that none of the metadata was corrupted with this failed # pin attempt self.assertTrue(fname not in self.pinned_functions) self.assertTrue(fname not in self.runtimes) self.assertTrue(fname not in self.exec_counts) self.assertTrue(fname not in self.status.functions)
def test_exec_class_function(self): ''' Tests creating and executing a class method in normal mode, ensuring that no messages are sent outside of the system and that the serialized result is as expected. ''' # Create the function and put it into the KVS. class Test: def __init__(self, cloudburst, num): self.num = num def run(self, cloudburst, inp): return inp + self.num fname = 'class' init_arg = 3 arg = 2 # Put the function into the KVS and create a function call. create_function((Test, (init_arg, )), self.kvs_client, fname) call = self._create_function_call(fname, [arg], NORMAL) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}, {}) # Assert that there have been 0 messages sent. self.assertEqual(len(self.socket.outbox), 0) # Retrieve the result, ensure it is a LWWPairLattice, then deserialize # it. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), LWWPairLattice) result = serializer.load_lattice(result) # Check that the output is equal to a local function execution. self.assertEqual(result, Test(None, init_arg).run('', arg))
def test_exec_func_with_ref(self): ''' Tests a function execution where the argument is a reference to the KVS in normal mode. ''' # Create the function and serialize it into a lattice. def func(_, x): return x * x fname = 'square' create_function(func, self.kvs_client, fname) # Put an argument value into the KVS. arg_value = 2 arg_name = 'key' self.kvs_client.put(arg_name, serializer.dump_lattice(arg_value)) # Create and serialize the function call. call = self._create_function_call(fname, [DropletReference(arg_name, True)], NORMAL) self.socket.inbox.append(call.SerializeToString()) # Execute the function call. exec_function(self.socket, self.kvs_client, self.user_library, {}) # Assert that there have been 0 messages sent. self.assertEqual(len(self.socket.outbox), 0) # Retrieve the result, ensure it is a LWWPairLattice, then deserialize # it. result = self.kvs_client.get(self.response_key)[self.response_key] self.assertEqual(type(result), LWWPairLattice) result = serializer.load_lattice(result) # Check that the output is equal to a local function execution. self.assertEqual(result, func('', arg_value))