9473bc200ed9c306dce7c9648a956d35f3044669
[ric-app/qp.git] / tests / test_qp.py
1 # ==================================================================================
2 #       Copyright (c) 2020 AT&T Intellectual Property.
3 #
4 #   Licensed under the Apache License, Version 2.0 (the "License");
5 #   you may not use this file except in compliance with the License.
6 #   You may obtain a copy of the License at
7 #
8 #          http://www.apache.org/licenses/LICENSE-2.0
9 #
10 #   Unless required by applicable law or agreed to in writing, software
11 #   distributed under the License is distributed on an "AS IS" BASIS,
12 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 #   See the License for the specific language governing permissions and
14 #   limitations under the License.
15 # ==================================================================================
16 import json
17 import time
18 from contextlib import suppress
19 from qp import main
20 from ricxappframe.xapp_frame import Xapp, RMRXapp
21
22 mock_qp_xapp = None
23 mock_ts_xapp = None
24
25 """
26  these tests are not currently parallelizable (do not use this tox flag)
27  I would use setup_module, however that can't take monkeypatch fixtures
28  Currently looking for the best way to make this better:
29  https://stackoverflow.com/questions/60886013/python-monkeypatch-in-pytest-setup-module
30 """
31
32
33 def test_init_xapp(monkeypatch):
34
35     # monkeypatch post_init to set the data we want
36     def fake_post_init(self):
37         self.predict_requests = 0
38
39     # patch
40     monkeypatch.setattr("qp.main.post_init", fake_post_init)
41
42     # start qp
43     main.start(thread=True)
44
45
46 def test_predict(monkeypatch, ts_to_qp):
47     main.predict(ts_to_qp)
48
49
50 def test_rmr_flow(monkeypatch, ts_to_qp, qp_prediction):
51     """
52     this flow mocks out the xapps on both sides of QP.
53     It first stands up a mock ts, then it starts up a mock qp-driver
54     which will immediately send requests to the running qp.
55     """
56
57     expected_result = {}
58
59     # define a mock traffic steering xapp that listens on 4563
60     def mock_ts_default_handler(self, summary, sbuf):
61         pass
62
63     def mock_ts_prediction_handler(self, summary, sbuf):
64         nonlocal expected_result  # closures ftw
65         pay = json.loads(summary["payload"])
66         expected_result = pay
67
68     global mock_ts_xapp
69     mock_ts_xapp = RMRXapp(mock_ts_default_handler, rmr_port=4563, use_fake_sdl=True)
70     mock_ts_xapp.register_callback(mock_ts_prediction_handler, 30002)
71     mock_ts_xapp.run(thread=True)
72
73     time.sleep(1)
74
75     # define a mock qp xapp that listens on 4560
76     def mock_qp_entry(self):
77
78         # good traffic steering request
79         val = json.dumps(ts_to_qp).encode()
80         self.rmr_send(val, 30000)
81
82         # should trigger the default handler and do nothing
83         val = json.dumps({"test send 60001": 2}).encode()
84         self.rmr_send(val, 60001)
85
86     global mock_qp_xapp
87     mock_qp_xapp = Xapp(entrypoint=mock_qp_entry, rmr_port=4560, use_fake_sdl=True)
88     mock_qp_xapp.run()  # this will return since entry isn't a loop
89
90
91 def teardown_module():
92     """
93     this is like a "finally"; the name of this function is pytest magic
94     safer to put down here since certain failures above can lead to pytest never returning
95     for example if an exception gets raised before stop is called in any test function above,
96     pytest will hang forever
97     """
98     with suppress(Exception):
99         mock_ts_xapp.stop()
100     with suppress(Exception):
101         mock_qp_xapp.stop()
102     with suppress(Exception):
103         main.stop()