Example #1
0
def reset_stats_req():
    '''
    reset all service statistics to default values
    '''

    # acquire lock, reset stats
    with bytes_sent_lock:
        global bytes_sent
        bytes_sent = 0

    with bytes_recvd_lock:
        global bytes_recvd
        bytes_recvd = 0

    with compression_lock:
        global payload_bytes
        payload_bytes = 0

        global compressed_bytes
        compressed_bytes = 0

    print("bytes sent %d & bytes recieved %d" % (bytes_sent, bytes_recvd))
    print("payload bytes %d & compressed bytes %d" %
          (payload_bytes, compressed_bytes))

    # create appropriate response header -- status OK
    header = Header(0, 0)
    headerB = header.serialize()

    return headerB
Example #2
0
def test_bad_magic_val(client):
    '''
    send a ping request with an incorrect magic value
    should result in error 33
    '''

    bad_magic_val = 0x53545250
    payload_len = 0
    req_code = 1

    # serialize header data
    magic_valueB = bad_magic_val.to_bytes(4, byteorder='big', signed=True)
    payload_lenB = payload_len.to_bytes(2, byteorder='big', signed=True)
    req_codeB = req_code.to_bytes(2, byteorder='big', signed=True)

    # manual creation of serialized header
    header = magic_valueB + payload_lenB + req_codeB
    client.sendall(header)
    data = client.recv(1024)

    # create empty header, deserialize data into it
    response_header = Header(0, 0)
    response_header.deserialize(data)

    got = (response_header.payload_len, response_header.code)
    expected = (0, 33)  # expecting status code 33 -- bad magic value error

    assert got == expected
Example #3
0
def ping_req():
    '''
    check service is available and operating normally
    '''

    print("PING!")

    # create appropriate response header -- status OK
    header = Header(0, 0)
    headerB = header.serialize()

    return headerB
Example #4
0
def error(error_code):
    '''
    prints error msg & returns response header with appropriate status code
    '''

    # print error msg for logging purposes
    print("ERROR: " + error_codes.get(error_code))

    header = Header(0, error_code)
    headerB = header.serialize()

    return headerB
Example #5
0
def test_get_stats(client):
    '''
    test get stats request by reseting stats and calling ping 3 times to be able predict output
    '''

    # reset stats (without compression ratio)-- they will now be 8, 8, 0
    test_reset(client)

    i = 0
    while i < 3:
        test_ping(client)
        i += 1

    stats_header = Header(0, 2)
    client.sendall(stats_header.serialize())

    # server response to get stats request
    stats_data = client.recv(1024)

    # create empty header, deserialize data into it
    stats_response_header = Header(0, 0)
    stats_response_header.deserialize(stats_data)

    expected = (9, 0)  # get stat's payload should be 9 bytes
    got = (stats_response_header.payload_len, stats_response_header.code)

    assert got == expected

    ping_bytes = 3 * 8

    # Only one req/rsp of header size since reset.
    expected = (8 + (8 + 9) + ping_bytes, 8 + 8 + ping_bytes, 0)
    got = deserialize_stats(stats_data[8:])

    assert got == expected
Example #6
0
def service_request(data):
    '''
    service a request by putting data received into proper format and calling correct request
    returns response to request based on request type
    also keep track of some statistics
    '''

    # stats -- keep track of bytes received
    with api.bytes_recvd_lock:
        api.bytes_recvd += len(data)

    # initialize header object with empty values
    header = Header(0, 0)

    # deserialize data received
    status_code = header.deserialize(data)

    # problems w/ header
    if status_code == 33 or status_code == 34:
        response = errors.error(status_code)

    # no problems w/ header
    else:
        if header.code == 1:  # ping request
            response = api.ping_req()

        elif header.code == 2:  # get stats request
            response = api.get_stats_req()

        elif header.code == 3:  # reset stats request
            response = api.reset_stats_req()

        elif header.code == 4:  # compress request
            payload = data[PAYLOAD_OFFSET:]
            response = api.compress_req(payload)

        else:
            # unsupported request type
            response = errors.error(3)

    # stats -- keep track of bytes sent
    with api.bytes_sent_lock:
        api.bytes_sent += len(response)

    return response
Example #7
0
def compress_req(payload):
    print(f"payload is {payload} && type {type(payload)}")
    '''
    return a compressed version of payload using a simple prefix compression scheme
    only accepts lowercase ascii strings of a maximum length of MAX_PAYLOAD
    '''

    if len(payload) > MAX_PAYLOAD:
        return errors.error(2)

    # deserialize payload
    try:
        payload = payload.decode('ascii')

    except UnicodeDecodeError:
        print('Error: encountered non ascii characters')
        return errors.error(35)

    # returns compressed version of payload
    compressed = compress(payload)
    print('compressed VALUE is', compressed)
    payload_len = len(compressed)
    # compressedB = compressed.encode('ascii')
    compressedB = bytes(compressed)

    print(f"type is {type(compressedB)}")

    # update metrics to be able to calculate compression ratio
    with compression_lock:
        global payload_bytes
        payload_bytes += len(payload)

        global compressed_bytes
        compressed_bytes += payload_len

    # create appropriate response header -- status OK
    header = Header(payload_len, 0)
    headerB = header.serialize()
    print(f"type of headerB {type(headerB)}")

    return headerB + compressedB
Example #8
0
def get_response(s, code):

    # Receive response
    data = s.recv(9216)
    print("this is the response recieved from server: ", data)  # log?

    # create header & init w/ empty values
    header = Header(0, 0)
    header.deserialize(data)

    # print error msgs
    if header.code in errors.error_codes:
        print('ERROR: ', errors.error_codes.get(header.code))

    else:
        print('payload length = ', header.payload_len)
        print('status code = ', header.code)

        # payload is only present for get stats or compress requests
        if header.code == 2 or header.code == 4:
            payload = data[8:]
            deserialize_payload(payload, code)
Example #9
0
def get_stats_req():
    '''
    returns total bytes sent, total bytes received, and compression ratio
    from service uptime or last reset
    '''

    # serialize stats
    with bytes_sent_lock:
        sentB = bytes_sent.to_bytes(4, byteorder='big')
    with bytes_recvd_lock:
        recvdB = bytes_recvd.to_bytes(4, byteorder='big')

    # calculate & serialize compression ratio
    with compression_lock:
        if payload_bytes != 0:
            compression_ratio = int((compressed_bytes / payload_bytes) * 100)
        else:  # avoid division by 0
            compression_ratio = 0

    compression_ratioB = compression_ratio.to_bytes(
        1, byteorder='big')  # should this be inside lock?

    # print for logging purposes --> log
    print("bytes sent %d and bytes recieved %d" % (bytes_sent, bytes_recvd))

    print('payload bytes %d and compressed bytes %d' %
          (payload_bytes, compressed_bytes))
    print('compression ratio is', compression_ratio)

    payload = sentB + recvdB + compression_ratioB
    payload_len = len(payload)

    # create appropriate response header -- status OK
    header = Header(payload_len, 0)
    headerB = header.serialize()

    return headerB + payload
Example #10
0
def test_compress(client):

    string = b'go go go go gophers gopher gophers'

    payload_len = len(string)
    compress_header = Header(payload_len, 4)

    client.sendall(compress_header.serialize() + string)
    compress_resp = client.recv(1024)

    # create empty header, deserialize data into it
    compress_response_header = Header(0, 0)
    compress_response_header.deserialize(compress_resp)
    compressed = compress_resp[8:]

    expected = b'-\xf6r\xd0\xb9\xd9K\x95\xc2@\x0c\x02t\xe9\xd3\xa6\xcb\xca\xe9\xb2\xf3\xa6\xcb\xca'

    assert compressed == expected
Example #11
0
def test_unexpected_payload_len(client):
    '''
    testing error 34 where payload length specified in header does not match
    payload length receive
    '''

    ping_header = Header(5, 1)
    client.sendall(ping_header.serialize())
    data = client.recv(1024)

    # create empty header, deserialize data into it
    response_header = Header(0, 0)
    response_header.deserialize(data)

    got = (response_header.payload_len, response_header.code)
    expected = (0, 34)

    assert got == expected
Example #12
0
def test_ping(client):
    '''
    testing ping request function
    should receive response header with status 0 -- OK
    '''

    ping_header = Header(0, 1)
    client.sendall(ping_header.serialize())
    data = client.recv(1024)

    # create empty header, deserialize data into it
    response_header = Header(0, 0)
    response_header.deserialize(data)

    got = (response_header.payload_len, response_header.code)
    expected = (0, 0)

    assert got == expected
Example #13
0
def test_unsupported_req(client):
    '''
    create a header with an unsupported request code/type
    should result in error 3
    '''

    header = Header(0, 5)
    client.sendall(header.serialize())
    data = client.recv(1024)

    # create empty header, deserialize data into it
    response_header = Header(0, 0)
    response_header.deserialize(data)

    got = (response_header.payload_len, response_header.code)
    expected = (0, 3)  # expecting status code 3 -- unsupported request error

    assert got == expected
Example #14
0
def send_request(socket, code):

    # compression request requires payload
    if code == 4:
        payload = input('enter a string to compress: ')
        payloadB = payload.encode('ascii')
        payload_len = len(payloadB)

        # create request header, serialize it, and send it
        header = Header(payload_len, code)
        socket.sendall(header.serialize() + payloadB)

    else:
        header = Header(0, code)
        socket.sendall(header.serialize())
Example #15
0
def test_compress_req_max(client):
    '''
    give compress request a string with length more than max payload
    should result in error 2 -- message too large
    '''

    # Test Max payload
    max_payload = b'a' * 8193
    compress_header = Header(8193, 4)
    client.sendall(compress_header.serialize() + max_payload)
    compress_data = client.recv(1024)

    # create empty header, deserialize data into it
    compress_response_header = Header(0, 0)
    compress_response_header.deserialize(compress_data)

    expected = (0, 2)
    got = (compress_response_header.payload_len, compress_response_header.code)

    assert got == expected
Example #16
0
def test_reset(client):
    '''
    test reset stats request by calling reset stats and check reset stats result by calling get stats
    expected value is 8, 8, 0 because we also call get stats
    '''

    # testing reset_stas
    reset_header = Header(0, 3)
    client.sendall(reset_header.serialize())
    reset_data = client.recv(1024)  # server response to rest stats request

    # create empty header, deserialize data into it -- bytes_recvd += 8
    reset_response_header = Header(0, 0)
    reset_response_header.deserialize(reset_data)

    got = (reset_response_header.payload_len, reset_response_header.code)
    expected = (0, 0)

    assert got == expected  # checking that server returned OK

    # call get stats request to check reset stats actually works -- bytes_sent += 8
    stats_header = Header(0, 2)
    client.sendall(stats_header.serialize())

    # server response to get stats request
    stats_data = client.recv(1024)

    # create empty header, deserialize data into it
    stats_response_header = Header(0, 0)
    stats_response_header.deserialize(stats_data)

    expected = (9, 0)  # get stat's payload should be 9 bytes
    got = (stats_response_header.payload_len, stats_response_header.code)

    assert got == expected

    expected = (8, 8, 0)  # Only one req/rsp of header size since reset.
    got = deserialize_stats(stats_data[8:])

    assert got == expected