From: Tommy Carpenter Date: Fri, 23 Aug 2019 18:24:40 +0000 (-0400) Subject: Complete rmr test coverage, restructure get_meid to be correct. X-Git-Tag: 1.4.0~1 X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F92%2F792%2F3;p=ric-plt%2Flib%2Frmr.git Complete rmr test coverage, restructure get_meid to be correct. Change-Id: I5d327d58f3059189d357e5c890c016ec3279811b Signed-off-by: Tommy Carpenter --- diff --git a/src/bindings/rmr-python/docs/Changelog.rst b/src/bindings/rmr-python/docs/Changelog.rst index e758354..87ed3ab 100644 --- a/src/bindings/rmr-python/docs/Changelog.rst +++ b/src/bindings/rmr-python/docs/Changelog.rst @@ -7,6 +7,15 @@ The format is based on `Keep a Changelog `__ and this project adheres to `Semantic Versioning `__. +[0.12.0] - 8/23/2019 +-------------------- + +:: + * Add final unit tests for rmr.py; unit test coverage for rmr python is about 95%. The remaining functions are dangerous to unit test directly, e.g., rcv which may block forever + * Fix a bug where meid was being intepreted as bytes (but then cast into a string); the correct interpretation is a string, so now it will truncate after a null byte. + * Removes access to the raw function rmr_get_meid(ptr, dest) in favor of just rmr_get_meid(ptr). Also get_meid is now rmr_get_meid since it wasn't consistent with the naming. + + [0.11.0] - 8/21/2019 -------------------- diff --git a/src/bindings/rmr-python/rmr/rmr.py b/src/bindings/rmr-python/rmr/rmr.py index 7e5d493..b666299 100644 --- a/src/bindings/rmr-python/rmr/rmr.py +++ b/src/bindings/rmr-python/rmr/rmr.py @@ -312,23 +312,36 @@ def rmr_bytes2meid(ptr_mbuf, src, length): # this is an alias to rmr_bytes2meid using familiar set/get terminoloigy rmr_set_meid = rmr_bytes2meid - # CAUTION: Some of the C functions expect a mutable buffer to copy the bytes into; # if there is a get_* function below, use it to set up and return the # buffer properly. - +# extern unsigned char* rmr_get_meid(rmr_mbuf_t* mbuf, unsigned char* dest); +# we don't provide direct access to this function (unless it is asked for) because it is not really useful to provide your own buffer. +# Rather, rmr_get_meid does this for you, and just returns the string. _rmr_get_meid = rmr_c_lib.rmr_get_meid _rmr_get_meid.argtypes = [POINTER(rmr_mbuf_t), c_char_p] _rmr_get_meid.restype = c_char_p -def rmr_get_meid(ptr_mbuf, dest): +def rmr_get_meid(ptr_mbuf): """ - Refer to the rmr C documentation for rmr_get_meid - extern unsigned char* rmr_get_meid(rmr_mbuf_t* mbuf, unsigned char* dest); + Get the managed equipment ID (meid) from the message header. + + Parameters + ---------- + ptr_mbuf: ctypes c_void_p + Pointer to an rmr message buffer + + Returns + ------- + string: + meid """ - return _rmr_get_meid(ptr_mbuf, dest) + sz = _get_constants().get("RMR_MAX_MEID", 64) # size for buffer to fill + buf = create_string_buffer(sz) + _rmr_get_meid(ptr_mbuf, buf) + return buf.value.decode() # decode turns into a string _rmr_get_src = rmr_c_lib.rmr_get_src @@ -404,10 +417,6 @@ def message_summary(ptr_mbuf): if ptr_mbuf.contents.len > RMR_MAX_RCV_BYTES: return "Malformed message: message length is greater than the maximum possible" - meid = get_meid(ptr_mbuf) - if meid == "\000" * _get_constants().get("RMR_MAX_MEID", 32): # special case all nils - meid = None - return { "payload": get_payload(ptr_mbuf), "payload length": ptr_mbuf.contents.len, @@ -417,7 +426,7 @@ def message_summary(ptr_mbuf): "message state": ptr_mbuf.contents.state, "message status": _state_to_status(ptr_mbuf.contents.state), "payload max size": rmr_payload_size(ptr_mbuf), - "meid": meid, + "meid": rmr_get_meid(ptr_mbuf), "message source": get_src(ptr_mbuf), "errno": ptr_mbuf.contents.tp_state, } @@ -454,27 +463,6 @@ def generate_and_set_transaction_id(ptr_mbuf): memmove(ptr_mbuf.contents.xaction, uu_id, sz) -def get_meid(ptr_mbuf): - """ - | Get the managed equipment ID (meid) from the message header. - | This is a 32 byte field and RMr returns all 32 bytes which if the sender did not set will be garbage. - - Parameters - ---------- - ptr_mbuf: ctypes c_void_p - Pointer to an rmr message buffer - - Returns - ------- - string: - meid - """ - sz = _get_constants().get("RMR_MAX_MEID", 64) # size for buffer to fill - buf = create_string_buffer(sz) - rmr_get_meid(ptr_mbuf, buf) - return buf.raw.decode() - - def get_src(ptr_mbuf): """ Get the message source (likely host:port) @@ -487,7 +475,7 @@ def get_src(ptr_mbuf): Returns ------- string: - meid + message source """ sz = _get_constants().get("RMR_MAX_SRC", 64) # size to fill buf = create_string_buffer(sz) diff --git a/src/bindings/rmr-python/rmr/rmr_mocks/rmr_mocks.py b/src/bindings/rmr-python/rmr/rmr_mocks/rmr_mocks.py index 239ac2b..315536f 100644 --- a/src/bindings/rmr-python/rmr/rmr_mocks/rmr_mocks.py +++ b/src/bindings/rmr-python/rmr/rmr_mocks/rmr_mocks.py @@ -126,5 +126,5 @@ def patch_rmr(monkeypatch): monkeypatch.setattr("rmr.rmr.generate_and_set_transaction_id", fake_generate_and_set_transaction_id) monkeypatch.setattr("rmr.rmr.get_payload", fake_get_payload) monkeypatch.setattr("rmr.rmr.get_src", fake_get_src) - monkeypatch.setattr("rmr.rmr.get_meid", fake_get_meid) + monkeypatch.setattr("rmr.rmr.rmr_get_meid", fake_get_meid) monkeypatch.setattr("rmr.rmr.rmr_payload_size", fake_rmr_payload_size) diff --git a/src/bindings/rmr-python/setup.py b/src/bindings/rmr-python/setup.py index ebdc471..f3de5b8 100644 --- a/src/bindings/rmr-python/setup.py +++ b/src/bindings/rmr-python/setup.py @@ -32,7 +32,7 @@ def _long_descr(): setup( name="rmr", - version="0.11.0", + version="0.12.0", packages=find_packages(), author="Tommy Carpenter, E. Scott Daniels", description="Python wrapper for RIC RMR", diff --git a/src/bindings/rmr-python/tests/fixtures/test_local.rt b/src/bindings/rmr-python/tests/fixtures/test_local.rt index 4f09782..6250c45 100644 --- a/src/bindings/rmr-python/tests/fixtures/test_local.rt +++ b/src/bindings/rmr-python/tests/fixtures/test_local.rt @@ -1,3 +1,3 @@ newrt|start -rte|10001|localhost:4562 +rte|0|localhost:4563 newrt|end diff --git a/src/bindings/rmr-python/tests/test_rmr.py b/src/bindings/rmr-python/tests/test_rmr.py index f3d0b75..6687c81 100644 --- a/src/bindings/rmr-python/tests/test_rmr.py +++ b/src/bindings/rmr-python/tests/test_rmr.py @@ -20,18 +20,31 @@ from rmr import rmr SIZE = 256 -MRC = None +MRC_SEND = None +MRC_RCV = None def setup_module(): - global MRC - MRC = rmr.rmr_init(b"4562", rmr.RMR_MAX_RCV_BYTES, 0x00) - while rmr.rmr_ready(MRC) == 0: + """ + test_rmr module setup + """ + global MRC_SEND + MRC_SEND = rmr.rmr_init(b"4562", rmr.RMR_MAX_RCV_BYTES, 0x00) + while rmr.rmr_ready(MRC_SEND) == 0: + time.sleep(1) + + global MRC_RCV + MRC_RCV = rmr.rmr_init(b"4563", rmr.RMR_MAX_RCV_BYTES, 0x00) + while rmr.rmr_ready(MRC_RCV) == 0: time.sleep(1) def teardown_module(): - rmr.rmr_close(MRC) + """ + test rmr module teardown + """ + rmr.rmr_close(MRC_SEND) + rmr.rmr_close(MRC_RCV) def _assert_new_sbuf(sbuf): @@ -44,7 +57,7 @@ def _assert_new_sbuf(sbuf): assert summary["transaction id"] == b"" assert summary["message state"] == 0 assert summary["message status"] == "RMR_OK" - assert summary["meid"] is None + assert summary["meid"] == "" assert summary["errno"] == 0 @@ -65,23 +78,34 @@ def test_get_mapping_dict(expected_states): assert rmr._state_to_status(666) == "UNKNOWN STATE" -def test_meid_prettify(): +def test_meid(): """ - test the printing of meid based on it's value + test meid stringification """ - # TODO?? weirdness: setting it takes bytes, but getting it returns a string. This does NOT happen for payload; bytes in, bytes come out. - sbuf = rmr.rmr_alloc_msg(MRC, SIZE) + sbuf = rmr.rmr_alloc_msg(MRC_SEND, SIZE) + + rmr.rmr_set_meid(sbuf, b"\x01\x02", 2) + assert rmr.rmr_get_meid(sbuf) == rmr.message_summary(sbuf)["meid"] == "\x01\x02" + assert len(rmr.rmr_get_meid(sbuf)) == 2 + rmr.rmr_set_meid(sbuf, b"\x00" * 32, 32) - summary = rmr.message_summary(sbuf) - assert summary["meid"] is None # summary does a pretty print" of 32 null bytes - assert rmr.get_meid(sbuf) == "\x00" * 32 # real underlying value + assert rmr.rmr_get_meid(sbuf) == rmr.message_summary(sbuf)["meid"] == "" # NULL bytes get truncated + + rmr.rmr_set_meid(sbuf, b"6" * 32, 32) + assert rmr.rmr_get_meid(sbuf) == rmr.message_summary(sbuf)["meid"] == "6" * 32 # string in string out + + rmr.rmr_set_meid(sbuf, b"\x01\x02", 2) + assert ( + rmr.rmr_get_meid(sbuf) == rmr.message_summary(sbuf)["meid"] == "\x01\x02" + "6" * 30 + ) # bytes in string out, 6s left over + assert len(rmr.rmr_get_meid(sbuf)) == 32 def test_rmr_set_get(): """ test set functions """ - sbuf = rmr.rmr_alloc_msg(MRC, SIZE) + sbuf = rmr.rmr_alloc_msg(MRC_SEND, SIZE) _assert_new_sbuf(sbuf) # test payload @@ -100,9 +124,60 @@ def test_rmr_set_get(): assert len(summary["transaction id"]) == 32 # test meid - assert rmr.get_meid(sbuf) == "\x00" * 32 - assert summary["meid"] is None # the summary printing function shows the above horridness as None - rmr.rmr_set_meid(sbuf, b"666", 3) + assert rmr.rmr_get_meid(sbuf) == summary["meid"] == "" + rmr.rmr_set_meid(sbuf, b"666\x01\x00\x01", 6) summary = rmr.message_summary(sbuf) - # TODO?? weirdness: setting it takes bytes, but getting it returns a string. This does NOT happen for payload; bytes in, bytes come out. - assert rmr.get_meid(sbuf) == summary["meid"] == "666" + "\x00" * 29 + assert rmr.rmr_get_meid(sbuf) == summary["meid"] == "666\x01" + assert (len(summary["meid"])) == 4 + + +def test_rcv_timeout(): + """ + test torcv; this is a scary test because if it fails... it doesn't fail, it will run forever! + We recieve a message (though nothing has been sent) and make sure the function doesn't block forever. + + There is no unit test for rmr_rcv_msg; too dangerous, that is a blocking call that may never return. + """ + sbuf_rcv = rmr.rmr_alloc_msg(MRC_RCV, SIZE) + sbuf_rcv = rmr.rmr_torcv_msg(MRC_RCV, sbuf_rcv, 50) # should time out after 50ms + summary = rmr.message_summary(sbuf_rcv) + assert summary["message state"] == 12 + assert summary["message status"] == "RMR_ERR_TIMEOUT" + + +def test_send_rcv(): + """ + test send and receive + """ + pay = b"\x01\x00\x80" + + # send a message + sbuf_send = rmr.rmr_alloc_msg(MRC_SEND, SIZE) + _assert_new_sbuf(sbuf_send) + rmr.set_payload_and_length(pay, sbuf_send) + sbuf_send.contents.mtype = 0 + sbuf_send = rmr.rmr_send_msg(MRC_SEND, sbuf_send) + send_summary = rmr.message_summary(sbuf_send) + + # receive it in other context + sbuf_rcv = rmr.rmr_alloc_msg(MRC_RCV, SIZE) + sbuf_rcv = rmr.rmr_torcv_msg(MRC_RCV, sbuf_rcv, 2000) + rcv_summary = rmr.message_summary(sbuf_rcv) + assert rcv_summary["payload"] == pay + assert rcv_summary["message type"] == 0 + assert send_summary["message state"] == rcv_summary["message state"] == 0 + assert send_summary["message status"] == rcv_summary["message status"] == "RMR_OK" + + # send an ACK back + ack_pay = b"message recieved" + rmr.set_payload_and_length(ack_pay, sbuf_rcv) + sbuf_rcv = rmr.rmr_rts_msg(MRC_RCV, sbuf_rcv) + rcv_ack_summary = rmr.message_summary(sbuf_rcv) + + # have the sender recieve it + sbuf_send = rmr.rmr_torcv_msg(MRC_SEND, sbuf_send, 2000) + send_ack_summary = rmr.message_summary(sbuf_send) + + assert send_ack_summary["payload"] == ack_pay + assert send_ack_summary["message state"] == rcv_ack_summary["message state"] == 0 + assert send_ack_summary["message status"] == rcv_ack_summary["message status"] == "RMR_OK"