def test_multi_event(self): """Test when two events fit inside on TCP packet""" recorded_events = [] def event_recorder(ctx, event): recorded_events.append(event) return 'OK' num_of_events = 10 events = (nuclio_sdk.Event(_id=i, body='e{}'.format(i)) for i in range(num_of_events)) self._send_events(events) self._wrapper._entrypoint = event_recorder self._wrapper.serve_requests(num_of_events) self.assertEqual(num_of_events, len(recorded_events), 'wrong number of events') for recorded_event_index, recorded_event in enumerate( sorted(recorded_events, key=operator.attrgetter('id'))): self.assertEqual(recorded_event_index, recorded_event.id) response_body = recorded_event.body if sys.version_info[:2] < (3, 0): # blame is on nuclio_sdk/event.py:80 response_body = base64.b64decode(response_body) self.assertEqual('e{}'.format(recorded_event_index), response_body)
def test_single_event(self): reverse_text = 'reverse this' # send the event self._wait_for_socket_creation() t = threading.Thread(target=self._send_event, args=(nuclio_sdk.Event(_id=1, body=reverse_text), )) t.start() self._wrapper.serve_requests(num_requests=1) t.join() # processor start, function log line, response body, duration messages self._wait_until_received_messages(4) # extract the response response = next(message['body'] for message in self._unix_stream_server._messages if message['type'] == 'r') response_body = response['body'][::-1] # blame is on nuclio_sdk/event.py:80 if sys.version_info[:2] < (3, 0): response_body = base64.b64decode(response_body) self.assertEqual(reverse_text, response_body)
def test_call_json_body(self): self._platform = nuclio_sdk.Platform('local', 'somens', self._connection_provider) # prepare an event to send event = nuclio_sdk.Event(method='GET', path='path', body={'a': 'some_body'}) # prepare a responder connection_response = unittest.mock.MagicMock() connection_response.status = http.client.NO_CONTENT connection_response.getheaders = lambda: [('Content-Type', 'application/json')] connection_response.read = unittest.mock.MagicMock(return_value='{"b": "some_response"}') self._mockConnection.getresponse = unittest.mock.MagicMock(return_value=connection_response) # send the event response = self._platform.call_function('function-name', event) self.assertEqual(self._mockConnection.url, 'nuclio-somens-function-name:8080') self._mockConnection.request.assert_called_with(event.method, event.path, body=json.dumps({'a': 'some_body'}), headers={ 'Content-Type': 'application/json', 'X-Nuclio-Target': 'function-name' }) self.assertEqual({'b': 'some_response'}, response.body) self.assertEqual('application/json', response.content_type) self.assertEqual(http.client.NO_CONTENT, response.status_code)
def _event_from_msgpack(self, parsed_data): """Decode event encoded as MessagePack by processor""" trigger = TriggerInfo( parsed_data['trigger']['class'], parsed_data['trigger']['kind'], ) # extract content type, needed to decode body content_type = parsed_data['content_type'] body = self._decode_body(parsed_data['body'], content_type) return nuclio_sdk.Event(body=body, content_type=content_type, trigger=trigger, fields=parsed_data.get('fields'), headers=parsed_data.get('headers'), _id=parsed_data['id'], method=parsed_data['method'], path=parsed_data['path'], size=parsed_data['size'], timestamp=datetime.datetime.utcfromtimestamp( parsed_data['timestamp']), url=parsed_data['url'], _type=parsed_data['type'], type_version=parsed_data['type_version'], version=parsed_data['version'])
def test_face_prediction(): f = open("image.txt", "r") image = f.readline() f.close() logger = nuclio_sdk.Logger(level=logging.INFO) ctx = nuclio_sdk.Context(logger=logger) event = nuclio_sdk.Event(body=image) handler(ctx, event)
def test_api_serving(): f = open("image.txt", "r") image = f.readline() f.close() nuclio_plat = nuclio_sdk.test.Platform() nuclio_plat._call_function_mock.side_effect = chain_call_function_mock event = nuclio_sdk.Event(body=image) nuclio_plat.call_handler(functions.api_serving.handler, event)
def handler(context, event): # parse the given event body event_body = json.loads(event.body) tsdb_event = transform_to_tsdb_event(event_body) # ingest the parsed event to tsdb context.platform.call_function(INGEST_FUNCTION, nuclio_sdk.Event(body=tsdb_event))
def test_non_utf8_headers(self): """ This test validates the expected behavior for a non-utf8 event field contents It sends 3 events, whereas the middle one has non-utf8 contents. Should allow non-utf8 when NOT decoding utf8 and throw exception when trying to decode it :return: """ self._wait_for_socket_creation() self._wrapper._entrypoint = lambda context, event: self._ensure_str( event.body) events = [ json.loads( nuclio_sdk.Event(_id=str(i), body='e{0}'.format(i)).to_json()) for i in range(3) ] # middle event is malformed malformed_event_index = len(events) // 2 events[malformed_event_index]['headers']['x-nuclio'] = b'\xda' # send events t = threading.Thread(target=self._send_events, args=(events, )) t.start() asyncio.get_event_loop().run_until_complete( self._wrapper.serve_requests(num_requests=len(events))) t.join() # processor start # duration # function response # malformed log line (wrapper) # malformed response # duration # function response expected_messages = 7 self._wait_until_received_messages(expected_messages) malformed_response = self._unix_stream_server._messages[-3]['body'] if self._decode_event_strings: # msgpack would fail decoding a non utf8 string when deserializing the event self.assertEqual(http.client.INTERNAL_SERVER_ERROR, malformed_response['status_code']) else: self.assertEqual(http.client.OK, malformed_response['status_code']) self.assertEqual(events[malformed_event_index]['body'], malformed_response['body']) # ensure messages coming after malformed request are still valid last_function_response = self._unix_stream_server._messages[-1]['body'] self.assertEqual(http.client.OK, last_function_response['status_code']) self.assertEqual(events[-1]['body'], last_function_response['body'])
def test_event(self): event = nuclio_sdk.Event(body='reverse this') time.sleep(1) # write the event to the transport line = event.to_json() + '\n' self._unix_stream_server._connection_socket.send(line.encode('utf-8')) # handle one request self._wrapper.serve_requests(num_requests=1) time.sleep(3)
def test_non_utf8_headers(self): self._wait_for_socket_creation() self._wrapper._entrypoint = lambda context, event: event.body events = [ json.loads( nuclio_sdk.Event(_id=str(i), body='e{0}'.format(i)).to_json()) for i in range(3) ] # middle event is malformed events[len(events) // 2]['headers']['x-nuclio'] = b'\xda' # send events t = threading.Thread(target=self._send_events, args=(events, )) t.start() self._wrapper.serve_requests(num_requests=len(events)) t.join() # processor start # if python 2 then: deprecation note # duration # function response # malformed log line (wrapper) # malformed response # duration # function response expected_messages = 7 if nuclio_sdk.helpers.PYTHON2: expected_messages += 1 self._wait_until_received_messages(expected_messages) malformed_response = self._unix_stream_server._messages[-3]['body'] self.assertEqual(httpclient.INTERNAL_SERVER_ERROR, malformed_response['status_code']) # ensure messages coming after malformed request are still valid last_function_response = self._unix_stream_server._messages[-1]['body'] self.assertEqual(httpclient.OK, last_function_response['status_code']) self.assertEqual(events[-1]['body'], last_function_response['body'])
def test_single_event(self): reverse_text = 'reverse this' # send the event self._wait_for_socket_creation() t = threading.Thread(target=self._send_event, args=(nuclio_sdk.Event(_id=1, body=reverse_text),)) t.start() asyncio.get_event_loop().run_until_complete(self._wrapper.serve_requests(num_requests=1)) t.join() # processor start, function log line, response body, duration messages self._wait_until_received_messages(4) # extract the response response = next(message['body'] for message in self._unix_stream_server._messages if message['type'] == 'r') response_body = response['body'][::-1] self.assertEqual(reverse_text, response_body)
def test_bad_function_code(self): def raise_exception(ctx, event): raise RuntimeError(error_message) error_message = 'Im a bad entrypoint' self._wait_for_socket_creation() self._send_event(nuclio_sdk.Event(_id='1')) self._wrapper._entrypoint = raise_exception asyncio.get_event_loop().run_until_complete(self._wrapper.serve_requests(num_requests=1)) # processor start, function log line, response body self._wait_until_received_messages(3) # extract the response response = next(message['body'] for message in self._unix_stream_server._messages if message['type'] == 'r') response_body = response['body'] self.assertIn(error_message, response_body)
def test_multi_event(self): """Test when two events fit inside on TCP packet""" recorded_events = [] def event_recorder(ctx, event): recorded_events.append(event) return 'OK' events = [nuclio_sdk.Event(body='e{}'.format(i)) for i in range(7)] text = '\n'.join(event.to_json() for event in events) + '\n' sock = MockSocket(text.encode('utf-8')) self._wrapper._processor_sock = sock self._wrapper._entrypoint = event_recorder try: self._wrapper.serve_requests() except MockSocket.EOF: pass self.assertEqual(len(events), len(recorded_events), 'wrong number of events')
def test_async_handler(self): """Test function decorated with async and running an event loop""" recorded_events = [] async def event_recorder(context, event): async def append_event(_event): context.logger.debug_with('sleeping', event=repr(_event.id)) await asyncio.sleep(0) context.logger.debug_with('appending event', event=repr(_event.id)) recorded_events.append(_event) await asyncio.sleep(0) # Deprecated. To be removed on nuclio > 1.18 # using `ensure_future` to BC with python:3.6 (on >= 3.7, you will see "create_task") # https://docs.python.org/3/library/asyncio-task.html#asyncio.create_task asyncio.ensure_future(append_event(event), loop=self._loop) return 'ok' num_of_events = 10 events = (nuclio_sdk.Event(_id=i, body='e{}'.format(i)) for i in range(num_of_events)) self._send_events(events) self._wrapper._is_entrypoint_coroutine = True self._wrapper._entrypoint = event_recorder self._wrapper._event_sock.setblocking(False) self._loop.run_until_complete( self._wrapper.serve_requests(num_of_events)) self._loop.run_until_complete(self._loop.shutdown_asyncgens()) self.assertEqual(num_of_events, len(recorded_events), 'wrong number of events') # we expect the event to be ordered since though the function is "asynchronous", it is blocked # by the processor until it gets response. for recorded_event_index, recorded_event in enumerate( sorted(recorded_events, key=operator.attrgetter('id'))): self.assertEqual(recorded_event_index, recorded_event.id) self.assertEqual('e{}'.format(recorded_event_index), self._ensure_str(recorded_event.body))
def test_multi_event(self): """Test when two events fit inside on TCP packet""" recorded_events = [] def event_recorder(ctx, event): recorded_events.append(event) return 'OK' num_of_events = 10 events = ( nuclio_sdk.Event(_id=i, body='e{}'.format(i)) for i in range(num_of_events) ) self._send_events(events) self._wrapper._entrypoint = event_recorder asyncio.get_event_loop().run_until_complete(self._wrapper.serve_requests(num_of_events)) self.assertEqual(num_of_events, len(recorded_events), 'wrong number of events') for recorded_event_index, recorded_event in enumerate(sorted(recorded_events, key=operator.attrgetter('id'))): self.assertEqual(recorded_event_index, recorded_event.id) self.assertEqual('e{}'.format(recorded_event_index), self._ensure_str(recorded_event.body))
def test_blast_events(self): """Test when many >> 10 events are being sent in parallel""" def record_event(recorded_events, ctx, event): recorded_events.add(event.id) recorded_event_ids = set() expected_events_length = 10000 events = (nuclio_sdk.Event(_id=i, body='e{}'.format(i)) for i in range(expected_events_length)) t = threading.Thread(target=self._send_events, args=(events, )) t.start() self._wrapper._entrypoint = functools.partial(record_event, recorded_event_ids) self._wrapper.serve_requests(num_requests=expected_events_length) t.join() # record incoming events self.assertEqual(expected_events_length, len(recorded_event_ids), 'Wrong number of events')
def _send_events(self, num_of_events): self._wait_for_socket_creation() for i in range(num_of_events): self._send_event(nuclio_sdk.Event(_id=i, body='e{}'.format(i)))