def prepare_client_connection(epoll, client_connections_info, client_requests, client_responses, test_id, request_id=None):
    """
        Description: Prepares the client connection for sending the request
        
        input_param: epoll - poll for the client sockets
        input_type: epoll instance
        input_param: client_connections_info - Client connection information dictionary
        input_type: dict
        input_param: client_requests  - Client requests information dictionary
        input_type: dict
        input_param: client_requests  - Client response information dictionary
        input_type: dict
        input_param: test_id - Test Unit Id
        input_type: int
        input_param: request_id - Unique Request Id
        input_type: int
        
        out_param: 
        out_type: 
        
        sample output:
        
    """
    client_socket = creat_socket()
    new_client_no = client_socket.fileno()
    next_request_info = get_next_request(test_id, request_id)
    if not next_request_info.get('id'):
        return
    request_row = session.query(HttpRequest).filter(HttpRequest.id==int(next_request_info['id'])).first()
    if request_id:
        remaining_requests = session.query(HttpTestResults)\
                                .filter(HttpTestResults.test_id==test_id)\
                                .filter(HttpTestResults.request_id==int(next_request_info['id']))\
                                .filter(HttpTestResults.is_completed==False)\
                                .filter(HttpTestResults.is_running==False).count()
        request_info = {
                    'tot_requests_per_connection' : request_row.total_requests,
                    'remaining_requests' : remaining_requests,
                    'last_accessed_time' : datetime.datetime.now(),
                    'request_id': request_id,
                    'socket': client_socket
                }
    else:
        request_info = {
                    'tot_requests_per_connection' : request_row.total_requests,
                    'remaining_requests' : request_row.total_requests,
                    'last_accessed_time' : datetime.datetime.now(),
                    'request_id': next_request_info['id'],
                    'socket': client_socket
                }
    client_connections_info[new_client_no] = request_info
    client_requests[new_client_no] = intialize_client_request_info(next_request_info['data']) # change the 1 to category id
    client_responses[new_client_no] = intialize_client_response_info()
    connect_with_server(client_connections_info[new_client_no]['socket'], SERVER_HOST, SERVER_PORT)
    register_socket_epoll_event(epoll, new_client_no, select.EPOLLOUT)
    client_connections_info[new_client_no]['remaining_requests'] = client_connections_info[new_client_no]['remaining_requests'] - 1
def handle_client_socket_events(test_id, epoll, client_connections_info, client_requests, client_responses):
    """
        Description: Handles all the events happens in client side sockets
        
        input_param: epoll - Epoll listener bucket for the client socket
        input_type: epoll
        
        out_param:
        out_type:
        
        sample output: None
    """
    try:
        while True:
            parallel_clients = len(client_connections_info.keys())
            if parallel_clients == 0:
                logger.debug("Test Completed Id : " + str(test_id))
                test = session.query(HttpTest).get(test_id)
                test.completed=True
                test.running=False
                test.completed_time=datetime.datetime.now()
                session.commit()
                break
            events = epoll.poll(parallel_clients)
            for fileno, event in events:
                conn_info = client_connections_info[fileno]
                resp_info = client_responses[fileno]
                req_info = client_requests[fileno]
                conn_info['last_accessed_time'] = datetime.datetime.now()
                if event & select.EPOLLERR:
                    logger.error("EPOLL ERROR in client response handling")
                if event & select.EPOLLIN:
                    new_data = None
                    read_err = None
                    # Receive the response from server
                    if resp_info['resp_start'] or resp_info['rem_bytes_to_read']:
                        new_data = read_data(client_connections_info[fileno]['socket'])
                        # If any read failure happens
                        if not new_data:
                            logger.error("Read failed so closing the socket\n")
                            read_err = True
                            resp_info['rem_bytes_to_read'] = 1
                            modify_socket_epoll_event(epoll, fileno, 0)
                            shut_down_socket(conn_info['socket'])
                        # Before receiving the all response headers
                        if new_data and not resp_info.get('full_header_received'):
                            resp_info['resp_start'] = False
                            resp_info['header_data'] = resp_info['header_data'] + new_data
                            if resp_info['header_data'].find(EOL1) != -1 or resp_info['header_data'].find(EOL2) != -1:
                                logger.debug("Full Header Received\n")
                                client_responses[fileno] = handle_server_response_data(resp_info)
                                resp_info = client_responses[fileno]
                                resp_info['full_header_received'] = True
                        # After receiving the all the response headers
                        # And when the response data is not chunked
                        elif new_data and resp_info.get('full_header_received') and not resp_info['is_chunked']:
                            resp_info['received_bytes'] = resp_info['received_bytes'] + len(new_data)
                            resp_info['rem_bytes_to_read'] = resp_info['rem_bytes_to_read'] - len(new_data)
                            resp_info['data'] = resp_info['data'] + new_data
                    # Once all response is received, verify the data
                    if not resp_info['rem_bytes_to_read'] and not read_err:
                        logger.info('-'*40 + '\n' + resp_info['header_data'])
                        logger.info(resp_info['data'])
                        verify_server_response(req_info, resp_info)
                        # For a non-persistent connection
                        if resp_info['not_persistent']:
                            logger.debug("Not Persistent Connection, So closing it\n")
                            modify_socket_epoll_event(epoll, fileno, 0)
                            shut_down_socket(conn_info['socket'])
                        else:
                            # For persistent connection, if there is any 
                            # sub-requests pending. Re-set the previous request, response dats
                            if conn_info['remaining_requests']:
                                logger.debug("Starting new request in persistent connection\n")
                                modify_socket_epoll_event(epoll, fileno, select.EPOLLOUT)
                                next_request_info = get_next_request(test_id, conn_info['request_id'])
                                conn_info['remaining_requests'] = conn_info['remaining_requests'] - 1
                                client_requests[fileno] = intialize_client_request_info(next_request_info['data'])
                                client_responses[fileno] = intialize_client_response_info()
                            else:
                                # For new request set, start the request sending in 
                                # already opened persistent connection
                                logger.debug("All Sub Request have completed for the request " + (conn_info['request_id']))
                                next_request_info = get_next_request(test_id)
                                # If any request set is pending for the test, start it
                                if next_request_info.get('id'):
                                    logger.debug("Opening New Request in persistent Connection \n")
                                    request_info = session.query(HttpRequest).filter(HttpRequest.id==int(next_request_info['id'])).first()
                                    conn_info['tot_requests_per_connection'] = request_info.total_requests
                                    conn_info['remaining_requests'] = request_info.total_requests
                                    conn_info['last_accessed_time'] = datetime.datetime.now(),
                                    conn_info['request_id'] =  next_request_info['id']
                                    client_requests[fileno] = intialize_client_request_info(next_request_info['data']) # change the 1 to category id
                                    client_responses[fileno] = intialize_client_response_info()
                                    client_connections_info[fileno]['remaining_requests'] = client_connections_info[new_client_no]['remaining_requests'] - 1
                                    modify_socket_epoll_event(epoll, fileno, select.EPOLLOUT)
                                else:
                                    # If there is not any request for test, close the connection
                                    modify_socket_epoll_event(epoll, fileno, 0)
                                    shut_down_socket(conn_info['socket'])
                elif event & select.EPOLLOUT:
                    # Send the Request to server
                    if req_info.get('rem_bytes_to_send'):
                        tot_sent = req_info['sent_bytes']
                        tot_sent = tot_sent + send_data(conn_info['socket'], req_info['request_data'][tot_sent:])
                        req_info['sent_bytes'] = tot_sent
                        req_info['rem_bytes_to_send'] = req_info['tot_bytes_to_send'] - req_info['sent_bytes']
                    else:
                        modify_socket_epoll_event(epoll, fileno, select.EPOLLIN)
                elif event & select.EPOLLHUP:
                    logger.warning("EPOLLHUP from client\n")
                    set_test_completion(test_id, conn_info['request_id'])
                    # If there is any remaining sub-request on closing socket
                    # open the new socket and assign closing socket's
                    # request set properties to it.
                    if conn_info['remaining_requests']:
                        prepare_client_connection(epoll, client_connections_info, client_requests, client_responses, test_id, conn_info['request_id'])
                    else:
                        prepare_client_connection(epoll, client_connections_info, client_requests, client_responses, test_id)
                    close_socket(epoll, fileno, client_connections_info)
                    del client_requests[fileno]
                    del client_responses[fileno]
    except:
        epoll.close()
        raise