Updated documentation for mock a1 tool
[ric-app/admin.git] / test / unit_test_admission_policy.cc
1 /*
2 ==================================================================================
3
4         Copyright (c) 2018-2019 AT&T Intellectual Property.
5
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9
10        http://www.apache.org/licenses/LICENSE-2.0
11
12    Unless required by applicable law or agreed to in writing, software
13    distributed under the License is distributed on an "AS IS" BASIS,
14    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15    See the License for the specific language governing permissions and
16    limitations under the License.
17 ==================================================================================
18 */
19
20 /* Author : Ashwin Sridharan
21    Date   : Sept 2019
22 */
23
24 #define CATCH_CONFIG_MAIN
25 #include <catch2/catch.hpp>
26
27
28 #include <admission_policy.hpp>
29
30 #define SCHEMA_FILE "../schemas/rate-control-policy.json"
31 #define SAMPLE_FILE "../schemas/samples.json"
32 #define VES_FILE  "../schemas/ves_schema.json"
33 #define INVALID_JSON "./test-data/invalid.json"
34 #define VALID_JSON "./test-data/valid.json"
35
36 bool report_mode_only = false;
37
38 TEST_CASE("Admission Policy Wrapper", "[acxapp]"){
39
40   mdclog_attr_t *attr;
41   mdclog_attr_init(&attr);
42   mdclog_attr_set_ident(attr, "UNIT TEST MESSAGE PROCESSOR ");
43   mdclog_init(attr);
44   mdclog_level_set(MDCLOG_DEBUG);
45   mdclog_attr_destroy(attr);
46
47   std::string xapp_id = "ac-xapp-test123";
48   
49   SECTION("Invalid number of instances requested"){
50     REQUIRE_THROWS( admission(SCHEMA_FILE,  SAMPLE_FILE, VES_FILE, 0, xapp_id));
51     REQUIRE_THROWS( admission(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, -1, xapp_id));
52     REQUIRE_THROWS( admission(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, 1000, xapp_id));
53   }
54   
55   SECTION("Invalid AC xAPP  Schema file "){
56     REQUIRE_THROWS( admission("hello there", SAMPLE_FILE, VES_FILE, 1, xapp_id));
57   }
58   
59   SECTION("Invalid sample file"){
60     REQUIRE_THROWS(admission(SCHEMA_FILE, "hello there", VES_FILE, 1, xapp_id));
61   }
62
63   SECTION("Invalid VES schema file "){
64     REQUIRE_THROWS(admission(SCHEMA_FILE, SAMPLE_FILE, "hello there", 1, xapp_id));
65   }
66
67   SECTION("Invalid JSON in a schema"){
68     REQUIRE_THROWS(admission(INVALID_JSON, SAMPLE_FILE, VES_FILE, 1, xapp_id));
69   }
70
71   SECTION("Valid JSON, but no valid schema key"){
72     REQUIRE_THROWS(admission(VALID_JSON, SAMPLE_FILE, VES_FILE, 1, xapp_id));
73     REQUIRE_THROWS(admission(SCHEMA_FILE, VALID_JSON, VES_FILE, 1, xapp_id));
74
75   }
76   
77   SECTION("Test policy schema validation"){
78     bool res;
79     std::string response;
80     
81     std::string valid_policy = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"CREATE\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10, \"class\":14}}";
82
83     std::string invalid_policy1 = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"CREATE\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10, \"class\":5000}}";
84     
85     std::string invalid_policy2 = "{\"policy_instance_id\":\"hello-there\", \"operation\":\"CREATE\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10, \"class\":14}}";
86
87     std::string invalid_policy3 = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"CREATED\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10, \"class\":14}}";
88
89     std::string invalid_policy4 = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"CREATE\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10}}";
90
91     std::string invalid_policy5 = "hello-there";
92     
93     admission adm_plugin(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, 1, xapp_id);
94
95     REQUIRE_THAT(adm_plugin.getName(), Catch::Matchers::Equals("admission control policy"));
96     
97     res = adm_plugin.setPolicy(invalid_policy1.c_str(), invalid_policy1.length(), response);
98     REQUIRE(res == false);
99
100     res = adm_plugin.setPolicy(invalid_policy2.c_str(), invalid_policy2.length(), response);
101     REQUIRE(res == false);
102
103     res = adm_plugin.setPolicy(invalid_policy3.c_str(), invalid_policy3.length(), response);
104     REQUIRE(res == false);
105
106     res = adm_plugin.setPolicy(invalid_policy4.c_str(), invalid_policy4.length(), response);
107     REQUIRE(res == false);
108
109     res = adm_plugin.setPolicy(invalid_policy5.c_str(), invalid_policy5.length(), response);
110     REQUIRE(res == false);
111
112     res = adm_plugin.setPolicy(valid_policy.c_str(), valid_policy.length(), response);
113     REQUIRE(res == true);
114
115     
116   }
117   
118   SECTION("Test Set/configure/delete policy"){
119     std::string policy = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"CREATE\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10, \"class\":14}}";
120     std::string delete_policy = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"DELETE\"}";  
121
122     
123     bool res;
124     std::string response, test_policy, policy_instance_id;
125     rapidjson::Document doc;
126     rapidjson::StringBuffer s_buffer;
127     rapidjson::Writer<rapidjson::StringBuffer> writer(s_buffer);
128
129     int num_policies = 10;
130     admission adm_plugin(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, 1, xapp_id);
131     doc.Parse(policy.c_str());
132     for(int i = 1; i <= num_policies; i++){
133       policy_instance_id = "rate_control_policy_" + std::to_string(i);
134       rapidjson::SetValueByPointer(doc, "/policy_instance_id", policy_instance_id.c_str());
135       rapidjson::SetValueByPointer(doc, "/payload/class", i);
136       s_buffer.Clear();
137       writer.Reset(s_buffer);
138       doc.Accept(writer);
139       test_policy.assign(s_buffer.GetString(), s_buffer.GetLength());
140       
141       // valid policy should succeed
142       res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
143       std::cout <<"Response1 = " << response << std::endl;
144       REQUIRE(res == true);
145     
146       // trying to add policy with same class as before should also return true
147       res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
148       REQUIRE(res == true);
149
150     }
151     
152     REQUIRE(adm_plugin.get_num_policies() == num_policies);
153     
154     // configure existing policy should work
155     rapidjson::SetValueByPointer(doc, "/operation", "UPDATE");
156     for(int i = 1; i <= num_policies; i++){
157       policy_instance_id = "rate_control_policy_" + std::to_string(i);
158       rapidjson::SetValueByPointer(doc, "/policy_instance_id", policy_instance_id.c_str());
159       rapidjson::SetValueByPointer(doc, "/payload/class", i);
160       rapidjson::SetValueByPointer(doc, "/payload/blocking_rate", 55.0);
161       s_buffer.Clear();
162       writer.Reset(s_buffer);
163       doc.Accept(writer);
164       test_policy.assign(s_buffer.GetString(), s_buffer.GetLength());
165       
166       // valid policy should succeed
167       res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
168       REQUIRE(res == true);
169       
170     }
171     
172     // configure non-existing policy should fail
173     policy_instance_id = "rate_control_policy_" + std::to_string(1000);
174     rapidjson::SetValueByPointer(doc, "/policy_instance_id", policy_instance_id.c_str());
175     s_buffer.Clear();
176     writer.Reset(s_buffer);
177     doc.Accept(writer);
178     test_policy.assign(s_buffer.GetString(), s_buffer.GetLength());
179     res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
180     REQUIRE(res == false);
181
182     // configure exsting policy but with non-existing class should fail
183     policy_instance_id = "rate_control_policy_" + std::to_string(1);
184     rapidjson::SetValueByPointer(doc, "/policy_instance_id", policy_instance_id.c_str());
185     rapidjson::SetValueByPointer(doc, "/payload/class", 200);
186     s_buffer.Clear();
187     writer.Reset(s_buffer);
188     doc.Accept(writer);
189     test_policy.assign(s_buffer.GetString(), s_buffer.GetLength());
190     res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
191     REQUIRE(res == false);
192
193     // delete existing policy should work
194     doc.Parse(delete_policy.c_str());
195     for(int i = 1; i <= num_policies; i++){
196       std::string policy_instance_id = "rate_control_policy_" + std::to_string(i);
197       rapidjson::SetValueByPointer(doc, "/policy_instance_id", policy_instance_id.c_str());
198       s_buffer.Clear();
199       writer.Reset(s_buffer);
200       doc.Accept(writer);
201       test_policy.assign(s_buffer.GetString(), s_buffer.GetLength());
202       
203       // delete policy should succeed since these policies were created
204       res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
205       REQUIRE(res == true);
206     }
207
208     REQUIRE(adm_plugin.get_num_policies() == 0);
209
210     //delete non-existing policy should fail
211     res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
212     REQUIRE(res == false);
213
214
215     
216   }
217
218   // SECTION("Get policy"){
219
220   //   std::string valid_policy = "{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10}";
221   //   bool res;
222   //   std::string response;
223
224   //   // first apply policy
225   //   admission adm_plugin(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, 1, xapp_id);
226   //   res = adm_plugin.setPolicy(valid_policy.c_str(), valid_policy.length(), response);
227   //   std::cout <<"Response = " << response << std::endl;
228   //   REQUIRE(res == true);
229   //   REQUIRE_THAT(response, Catch::Matchers::Contains("SUCCESS"));
230  
231
232   //   // now retreive policy and check
233   //   res = adm_plugin.getPolicy(valid_policy.c_str(), valid_policy.length(), response);
234   //   REQUIRE(res == true);
235
236   //   REQUIRE_THAT(response, Catch::Matchers::Contains("\"trigger_threshold\":10"));
237
238   // }
239
240   SECTION("Metrics"){
241
242     std::string policy = "{\"policy_type_id\":21000, \"policy_instance_id\":\"hello-there\", \"operation\":\"CREATE\", \"payload\":{\"blocking_rate\":20, \"enforce\":true, \"window_length\":50, \"trigger_threshold\":10, \"class\":14}}";
243
244     bool res;
245     std::string response, test_policy, policy_instance_id;
246     rapidjson::Document doc;
247     rapidjson::StringBuffer s_buffer;
248     rapidjson::Writer<rapidjson::StringBuffer> writer(s_buffer);
249
250     int num_policies = 10;
251     admission adm_plugin(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, 1, xapp_id);
252     doc.Parse(policy.c_str());
253     // Add some policies first 
254     for(int i = 1; i <= num_policies; i++){
255       policy_instance_id = "rate_control_policy_" + std::to_string(i);
256       rapidjson::SetValueByPointer(doc, "/policy_instance_id", policy_instance_id.c_str());
257       rapidjson::SetValueByPointer(doc, "/payload/class", i);
258       s_buffer.Clear();
259       writer.Reset(s_buffer);
260       doc.Accept(writer);
261       test_policy.assign(s_buffer.GetString(), s_buffer.GetLength());
262       
263       // valid policy should succeed
264       res = adm_plugin.setPolicy(test_policy.c_str(), test_policy.length(), response);
265       REQUIRE(res == true);
266       //REQUIRE_THAT(response, Catch::Matchers::Contains("SUCCESS"));    
267     }
268     
269
270     // now get metrics
271     // First time, measurementInterval should be zero
272     std::vector<std::string> metrics;
273     adm_plugin.getMetrics(metrics);
274     REQUIRE(metrics.size() == num_policies + 1);
275     for(auto const e : metrics){
276       std::cout << e<< std::endl;
277       REQUIRE_THAT(e, Catch::Matchers::Contains("\"Class Id\""));
278       REQUIRE_THAT(e, Catch::Matchers::Contains("\"measurementInterval\":\"0\""));
279     }
280
281     int interval = 5;
282     // wait for 'x' seconds and try again
283     std::this_thread::sleep_for(std::chrono::seconds(interval));
284     rapidjson::Pointer int_ref("/event/measurementFields/measurementInterval");
285     
286     metrics.clear();
287     adm_plugin.getMetrics(metrics);
288     REQUIRE(metrics.size() == num_policies + 1);
289     for(auto const e : metrics){
290       REQUIRE(doc.Parse(e.c_str()).HasParseError() == 0);
291       std::cout << e<< std::endl;
292       REQUIRE_THAT(e, Catch::Matchers::Contains("\"Class Id\""));
293       // extract measurement interval
294       rapidjson::Value *interval_val = int_ref.Get(doc);
295       REQUIRE(interval_val != NULL);
296       double read_interval_approx = atof(interval_val->GetString());
297       REQUIRE(read_interval_approx == Approx(interval).margin(1));
298     }
299
300     
301   }
302
303 SECTION("Get plugin"){
304     admission adm_plugin(SCHEMA_FILE, SAMPLE_FILE, VES_FILE, 1, xapp_id);
305     protector * p = NULL;
306     p = adm_plugin.get_protector_instance(100);
307     REQUIRE( p == NULL);
308
309     p = adm_plugin.get_protector_instance(0);
310     REQUIRE(p != NULL);
311     REQUIRE(p->get_requests(0) == 0);
312   }
313       
314       
315 }
316