blob: 7e61cb01e936b41d86a103c8d14b4328985355e7 [file] [log] [blame]
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""module for generating mock classes/objects for testing purposes"""
import socket
from heron.instance.src.python.network import (REQID, OutgoingPacket,
IncomingPacket, StatusCode,
SocketOptions)
from heron.instance.src.python.network import HeronClient
import heron.instance.tests.python.mock_protobuf as mock_protobuf
# pylint: disable=missing-docstring
# pylint: disable=unused-argument
# Python's primitive type list
prim_list = [1000, -234, 0.00023, "string",
["abc", "def", "ghi"], True, False,
("tuple", 123, True), None, {}]
def convert_to_incoming_packet(reqid, message):
"""Convert (reqid, message) pair to IncomingPacket object"""
raw = OutgoingPacket.create_packet(reqid, message).raw
dispatcher = MockDispatcher()
dispatcher.prepare_with_raw(raw)
packet = IncomingPacket()
packet.read(dispatcher)
packet.data = packet.data
return packet
# Returns a list of mock request packets (REQID is non-zero)
def get_mock_requst_packets(is_message):
"""Returns a list of valid IncomingPackets with non-zero REQID and the corresponding raw data"""
pkt_list = []
raw_list = []
message_list = [mock_protobuf.get_mock_register_response(),
mock_protobuf.get_mock_config(),
mock_protobuf.get_mock_bolt(),
mock_protobuf.get_mock_topology()]
# normal packet (PhysicalPlan as request)
for message in message_list:
if is_message:
reqid = REQID.generate_zero()
else:
reqid = REQID.generate()
normal_pkt = convert_to_incoming_packet(reqid, message)
pkt_list.append(normal_pkt)
raw_list.append((reqid, message))
return pkt_list, raw_list
def get_a_mock_request_packet_and_raw():
"""Returns a tuple of mock (IncomingPacket, REQID, RegisterResponse message)"""
reqid = REQID.generate()
message = mock_protobuf.get_mock_register_response()
pkt = convert_to_incoming_packet(reqid, message)
return pkt, reqid, message
def get_a_mock_message_list_and_builder():
"""Get a list of IncomingPackets, the corresponding mock messages, builder and typename"""
pkt_list = []
raw_list = mock_protobuf.get_many_mock_pplans()
for msg in raw_list:
reqid = REQID.generate_zero()
pkt = convert_to_incoming_packet(reqid, msg)
pkt_list.append(pkt)
builder, typename = mock_protobuf.get_pplan_builder_and_typename()
return pkt_list, raw_list, builder, typename
def get_fail_packet():
"""Returns an incomplete IncomingPacket object"""
raw = OutgoingPacket.create_packet(REQID.generate(), mock_protobuf.get_mock_pplan()).raw
packet = IncomingPacket.create_packet(raw[:4], raw[4:])
packet.is_complete = False
return packet
class MockDispatcher(object):
"""Mock asyncore.dispatcher class, supporting only recv() and send() method
This dispatcher provides several options as to how to prepare its receive buffer.
"""
PARTIAL_DATA_SIZE = 4
def __init__(self):
self.to_be_received = ""
self.eagain_test = False
self.fatal_error_test = False
def prepare_with_raw(self, raw):
"""the content of ``raw`` will be prepared in the recv buffer"""
self.to_be_received = raw
def prepare_valid_response(self):
"""a number of valid packets will be prepared in the recv buffer"""
pkt_list, _ = get_mock_requst_packets(is_message=False)
for pkt in pkt_list:
self.to_be_received += pkt.convert_to_raw()
def prepare_header_only(self):
"""a packet with just a header (incomplete packet) will be prepared in the recv buffer"""
pkt = get_mock_requst_packets(is_message=False)[0][0]
self.to_be_received = pkt.header
def prepare_partial_data(self):
"""a partial data packet will be prepared in the recv buffer"""
pkt = get_mock_requst_packets(is_message=False)[0][0]
self.to_be_received = pkt.header + pkt.data[:self.PARTIAL_DATA_SIZE]
def prepare_eagain(self):
"""prepare so that EAGAIN error is raised when recv() is called """
self.eagain_test = True
def prepare_fatal(self):
"""prepare so that RuntimeError is raised when recv() is called"""
self.fatal_error_test = True
def recv(self, numbytes):
"""reads ``numbytes`` from the recv buffer"""
if self.fatal_error_test:
raise RuntimeError("Fatal Error Test")
elif self.eagain_test:
raise socket.error(socket.errno.EAGAIN, "EAGAIN Test")
ret = self.to_be_received[:numbytes]
self.to_be_received = self.to_be_received[numbytes:]
return ret
# pylint: disable=no-self-use
def send(self, buf):
"""mock sends the content of a given buffer"""
return len(buf)
class MockHeronClient(HeronClient):
HOST = '127.0.0.1'
PORT = 9090
def __init__(self):
socket_options = SocketOptions(32768, 16, 32768, 16, 1024000, 1024000)
HeronClient.__init__(self, None, self.HOST, self.PORT, {}, socket_options)
self.on_connect_called = False
self.on_response_status = None
self.called_handle_packet = False
self.dispatcher = MockDispatcher()
self.incoming_msg = None
self.on_error_called = False
def on_connect(self, status):
if status == StatusCode.OK:
self.on_connect_called = True
def on_response(self, status, context, response):
self.on_response_status = status
def on_error(self):
self.on_error_called = True
def on_incoming_message(self, message):
self.incoming_msg = message
def recv(self, numbytes):
return self.dispatcher.recv(numbytes)
def _handle_packet(self, packet):
# should only be called when packet is complete
self.called_handle_packet = True
HeronClient._handle_packet(self, packet)
def _handle_close(self):
pass