def start(thread=False): """ This is a convenience function that allows this xapp to run in Docker for "real" (no thread, real SDL), but also easily modified for unit testing (e.g., use_fake_sdl). The defaults for this function are for the Dockerized xapp. """ global rmr_xapp fake_sdl = getenv("USE_FAKE_SDL", True) config_file = getenv("CONFIG_FILE", None) rmr_xapp = RMRXapp(default_handler, config_handler=handle_config_change, rmr_port=4560, post_init=post_init, use_fake_sdl=bool(fake_sdl)) rmr_xapp.run(thread)
def test_config_no_env(monkeypatch): init_config_file() monkeypatch.delenv(Constants.CONFIG_FILE_ENV, raising=False) def default_rmr_handler(self, summary, sbuf): pass config_event_seen = False def config_handler(self, json): nonlocal config_event_seen config_event_seen = True global rmr_xapp_noconfig rmr_xapp_noconfig = RMRXapp(default_rmr_handler, config_handler=config_handler, rmr_port=4652, use_fake_sdl=True) # in unit tests we need to thread here or else execution is not returned! rmr_xapp_noconfig.run(thread=True, rmr_timeout=1) write_config_file() # give the work loop a chance to timeout on RMR and process the config event time.sleep(3) assert not config_event_seen rmr_xapp_noconfig.stop() rmr_xapp_noconfig = None
def test_rmr_healthcheck(): # thanos uses the rmr xapp to healthcheck the rmr xapp # test variables health_pay = None def post_init(self): self.rmr_send(b"", RIC_HEALTH_CHECK_REQ) def default_handler(self, summary, sbuf): pass global rmr_xapp_health rmr_xapp_health = RMRXapp(default_handler, post_init=post_init, rmr_port=4666, use_fake_sdl=True) def health_handler(self, summary, sbuf): nonlocal health_pay health_pay = summary["payload"] self.rmr_free(sbuf) rmr_xapp_health.register_callback(health_handler, RIC_HEALTH_CHECK_RESP) rmr_xapp_health.run( thread=True ) # in unit tests we need to thread here or else execution is not returned! time.sleep(1) assert health_pay == b"OK\n"
def test_custom_config_handler(monkeypatch): # point watcher at the file init_config_file() monkeypatch.setenv(CONFIG_FILE_ENV, config_file_path) def default_handler(self, summary, sbuf): pass startup_config_event = False change_config_event = False def config_handler(self, json): mdc_logger.info("config_handler: json {}".format(json)) nonlocal startup_config_event nonlocal change_config_event if "start" in json: startup_config_event = True if "change" in json: change_config_event = True # listen port is irrelevant, no messages arrive global rmr_xapp_config rmr_xapp_config = RMRXapp(default_handler, config_handler=config_handler, rmr_port=4567, use_fake_sdl=True) assert startup_config_event rmr_xapp_config.run( thread=True, rmr_timeout=1 ) # in unit tests we need to thread here or else execution is not returned! write_config_file() # give the work loop a chance to timeout on RMR and process the config event time.sleep(3) assert change_config_event rmr_xapp_config.stop()
def test_bad_init(): """test that an xapp whose rmr fails to init blows up""" def entry(self): pass with pytest.raises(InitFailed): bad_xapp = Xapp(entrypoint=entry, rmr_port=-1) bad_xapp.run() # we wont get here def defh(self): pass with pytest.raises(InitFailed): bad_xapp = RMRXapp(default_handler=defh, rmr_port=-1) bad_xapp.run() # we wont get here
def test_rmr_init(): # test variables def_pay = None sixty_pay = None # create rmr app def default_handler(self, summary, sbuf): nonlocal def_pay def_pay = json.loads(summary["payload"]) self.rmr_free(sbuf) def sixtythou_handler(self, summary, sbuf): nonlocal sixty_pay sixty_pay = json.loads(summary["payload"]) self.rmr_free(sbuf) global rmr_xapp rmr_xapp = RMRXapp(default_handler, rmr_port=4564, use_fake_sdl=True) rmr_xapp.register_callback(sixtythou_handler, 60000) rmr_xapp.run( thread=True ) # in unit tests we need to thread here or else execution is not returned! time.sleep(1) # create a general xapp that will demonstrate some SDL functionality and launch some requests against the rmr xapp def entry(self): time.sleep(1) self.sdl_set("testns", "mykey", 6) assert self.sdl_get("testns", "mykey") == 6 assert self.sdl_find_and_get("testns", "myk") == {"mykey": 6} assert self.healthcheck() val = json.dumps({"test send 60000": 1}).encode() self.rmr_send(val, 60000) val = json.dumps({"test send 60001": 2}).encode() self.rmr_send(val, 60001) self.sdl_delete("testns", "bogus") global gen_xapp gen_xapp = Xapp(entrypoint=entry, use_fake_sdl=True) gen_xapp.run() time.sleep(1) assert def_pay == {"test send 60001": 2} assert sixty_pay == {"test send 60000": 1}
def start(thread=False): """ This is a convenience function that allows this xapp to run in Docker for "real" (no thread, real SDL), but also easily modified for unit testing (e.g., use_fake_sdl). The defaults for this function are for the Dockerized xapp. """ logger.debug("QP xApp starting") global qp_xapp fake_sdl = os.environ.get("USE_FAKE_SDL", None) qp_xapp = RMRXapp(qp_default_handler, rmr_port=4560, post_init=post_init, use_fake_sdl=bool(fake_sdl)) qp_xapp.register_callback(qp_predict_handler, 30001) qp_xapp.run(thread)
def test_init_rmr_xapp(): def post_init(self): print("hey") def foo(self, _summary, _sbuf): pass rmr_xapp = RMRXapp(foo, post_init=post_init, rmr_wait_for_ready=False, use_fake_sdl=True) # pytest will never return without thread and stop rmr_xapp.run(thread=True) time.sleep(1) rmr_xapp.stop()
def test_rmr_flow(monkeypatch, qpd_to_qp, qp_prediction): """ this flow mocks out the xapps on both sides of QP. It first stands up a mock ts, then it starts up a mock qp-driver which will immediately send requests to the running qp. """ expected_result = {} # define a mock traffic steering xapp that listens on 4563 def mock_ts_default_handler(self, summary, sbuf): pass def mock_ts_prediction_handler(self, summary, sbuf): nonlocal expected_result # closures ftw pay = json.loads(summary["payload"]) expected_result = pay global mock_ts_xapp mock_ts_xapp = RMRXapp(mock_ts_default_handler, rmr_port=4563, use_fake_sdl=True) mock_ts_xapp.register_callback(mock_ts_prediction_handler, 30002) mock_ts_xapp.run(thread=True) time.sleep(1) # define a mock qp driver xapp that sends a message to QP under test def mock_qpd_entry(self): # good traffic steering request val = json.dumps(qpd_to_qp).encode() self.rmr_send(val, 30001) # should trigger the default handler and do nothing val = json.dumps({"test send 60001": 2}).encode() self.rmr_send(val, 60001) global mock_qpd_xapp mock_qpd_xapp = Xapp(entrypoint=mock_qpd_entry, rmr_port=4666, use_fake_sdl=True) mock_qpd_xapp.run() # this will return since entry isn't a loop time.sleep(1) assert main.get_stats() == {"PredictRequests": 1} assert expected_result == qp_prediction
def test_default_config_handler(monkeypatch): """Just for coverage""" init_config_file() monkeypatch.setenv(CONFIG_FILE_ENV, config_file_path) def default_rmr_handler(self, summary, sbuf): pass # listen port is irrelevant, no messages arrive global rmr_xapp_defconfig rmr_xapp_defconfig = RMRXapp(default_rmr_handler, rmr_port=4567, use_fake_sdl=True) # in unit tests we need to thread here or else execution is not returned! rmr_xapp_defconfig.run(thread=True, rmr_timeout=1) write_config_file() # give the work loop a chance to timeout on RMR and process the config event time.sleep(3) rmr_xapp_defconfig.stop()
def post_init(_self): """post init""" print("pong xapp could do some useful stuff here!") def sixtyh(self, summary, sbuf): """callback for 60000""" self.logger.info("pong registered 60000 handler called!") # see comment in ping about this; bytes does not work with the ric mdc logger currently print("pong 60000 handler received: {0}".format(summary)) jpay = json.loads(summary['payload']) self.rmr_rts(sbuf, new_payload=json.dumps({ "ACK": jpay["test_send"] }).encode(), new_mtype=60001, retries=100) self.rmr_free(sbuf) def defh(self, summary, sbuf): """default callback""" self.logger.info("pong default handler called!") print("pong default handler received: {0}".format(summary)) self.rmr_free(sbuf) xapp = RMRXapp(default_handler=defh, post_init=post_init, use_fake_sdl=True) xapp.register_callback(sixtyh, 60000) xapp.run() # will not thread by default
def test_rmr_flow(monkeypatch, qpd_to_qp, qpd_to_qp_bad_cell): """ this flow mocks out the xapps on both sides of QP driver. It first stands up a mock qp, then it starts up a mock ts which will immediately send requests to the running qp driver. """ expected_result = {} # define a mock qp predictor def mock_qp_default_handler(self, summary, sbuf): pass def mock_qp_predict_handler(self, summary, sbuf): nonlocal expected_result # closures ftw pay = json.loads(summary["payload"]) expected_result[pay["PredictionUE"]] = pay global mock_qp_xapp mock_qp_xapp = RMRXapp(mock_qp_default_handler, rmr_port=4666, use_fake_sdl=True) mock_qp_xapp.register_callback(mock_qp_predict_handler, 30001) mock_qp_xapp.run(thread=True) time.sleep(1) # define a mock traffic steering xapp def mock_ts_entry(self): # make sure a bad steering request doesn't blow up in qpd val = "notevenjson".encode() self.rmr_send(val, 30000) val = json.dumps({ "bad": "tothebone" }).encode() # json but missing UEPredictionSet self.rmr_send(val, 30000) # valid request body but missing cell id val = json.dumps({"UEPredictionSet": ["VOIDOFLIGHT"]}).encode() self.rmr_send(val, 30000) # good traffic steering request val = json.dumps({"UEPredictionSet": ["12345", "8675309"]}).encode() self.rmr_send(val, 30000) # should trigger the default handler and do nothing val = json.dumps({"test send 60001": 2}).encode() self.rmr_send(val, 60001) global mock_ts_xapp mock_ts_xapp = Xapp(entrypoint=mock_ts_entry, rmr_port=4564, use_fake_sdl=True) mock_ts_xapp.run() # this will return since entry isn't a loop time.sleep(1) assert expected_result == { "12345": qpd_to_qp, "8675309": qpd_to_qp_bad_cell } assert main.get_stats() == {"DefCalled": 1, "SteeringRequests": 4} # break SDL and send traffic again def sdl_healthcheck_fails(self): return False monkeypatch.setattr("ricxappframe.xapp_sdl.SDLWrapper.healthcheck", sdl_healthcheck_fails) mock_ts_xapp.run() # restore SDL and send traffic once more def sdl_healthcheck_passes(self): return True monkeypatch.setattr("ricxappframe.xapp_sdl.SDLWrapper.healthcheck", sdl_healthcheck_passes) mock_ts_xapp.run()