blob: f0589effbaf15def6d790610ffa03e7b23535eff [file] [log] [blame]
Harald Weltefaa42922019-03-04 18:31:11 +01001module RemsimServer_Tests {
2
3/* Integration Tests for osmo-remsim-server
4 * (C) 2019 by Harald Welte <laforge@gnumonks.org>
5 * All rights reserved.
6 *
7 * Released under the terms of GNU General Public License, Version 2 or
8 * (at your option) any later version.
9 *
10 * SPDX-License-Identifier: GPL-2.0-or-later
11 *
12 * This test suite tests osmo-remsim-server by attaching to the external interfaces
13 * such as RSPRO for simulated clients + bankds and RSRES (REST backend interface).
14 */
15
16import from Osmocom_Types all;
17
18import from RSPRO all;
19import from RSRES all;
20import from RSPRO_Types all;
21import from REMSIM_Tests all;
22
23import from IPA_Emulation all;
24
25import from HTTPmsg_Types all;
26import from HTTPmsg_PortType all;
27import from JSON_Types all;
28
29type component http_CT {
30 port HTTPmsg_PT HTTP;
31 var charstring g_http_host;
32 var integer g_http_port;
33};
34
35function f_http_init(charstring host, integer http_port) runs on http_CT {
36 map(self:HTTP, system:HTTP);
37 g_http_host := host;
38 g_http_port := http_port;
39}
40
41template (value) Connect ts_HTTP_Connect(template (value) charstring hostname,
42 template (value) integer http_port := 80,
43 template (value) boolean use_ssl := false) := {
44 hostname := hostname,
45 portnumber := http_port,
46 use_ssl := use_ssl
47}
48template (value) Close ts_HTTP_Close := { client_id := omit };
49
50template (value) HeaderLines ts_HTTP_Header(charstring body) := {
51 { header_name := "Content-Type", header_value := "application/json" },
52 { header_name := "Content-Length", header_value := int2str(lengthof(body)) }
53}
54
55template (value) HTTPMessage ts_HTTP_Req(charstring url,
56 charstring method := "GET",
57 charstring body := "",
58 integer v_maj := 1, integer v_min := 1) := {
59 request := {
60 client_id := omit,
61 method := method,
62 uri := url,
63 version_major := v_maj,
64 version_minor := v_min,
65 header := ts_HTTP_Header(body),
66 body := body
67 }
68}
69
70template HTTPMessage tr_HTTP_Resp(template integer sts := ?) := {
71 response := {
72 client_id := ?,
73 version_major := ?,
74 version_minor := ?,
75 statuscode := sts,
76 statustext := ?,
77 header := ?,
78 body := ?
79 }
80};
81
82template HTTPMessage tr_HTTP_Resp2xx := tr_HTTP_Resp((200..299));
83
84/* run a HTTP request and return the response */
85function f_http_transact(charstring url, charstring method := "GET",
86 charstring body := "", template HTTPMessage exp := tr_HTTP_Resp2xx)
87runs on http_CT return HTTPMessage {
88 var HTTPMessage resp;
89 timer T := 2.0;
90
91 HTTP.send(ts_HTTP_Connect(g_http_host, g_http_port));
92 //HTTP.receive(Connect_result:?);
93 HTTP.send(ts_HTTP_Req(url, method, body));
94 T.start;
95 alt {
96 [] HTTP.receive(exp) -> value resp {
97 setverdict(pass);
98 }
99 [] HTTP.receive(tr_HTTP_Resp) -> value resp {
100 setverdict(fail, "Unexpected HTTP response ", resp);
101 }
102 [] T.timeout {
103 setverdict(fail, "Timeout waiting for HTTP response");
104 self.stop;
105 }
106 }
107 HTTP.send(ts_HTTP_Close);
108 return resp;
109}
110
111/* run a HTTP GET on specified URL expecting json in RSRES format as response */
112function f_rsres_get(charstring url, template integer exp_sts := 200)
113runs on http_CT return JsRoot {
114 var HTTPMessage http_resp;
115 http_resp := f_http_transact(url, exp := tr_HTTP_Resp(exp_sts));
116 return f_dec_JsRoot(char2oct(http_resp.response.body));
117}
118
119/* run a HTTP PUT to add a new slotmap to the remsim-server */
120function f_rsres_post_slotmap(JsSlotmap slotmap, template integer exp_sts := 201)
121runs on http_CT return HTTPResponse {
122 var charstring body := oct2char(f_enc_JsSlotmap(slotmap));
123 var HTTPMessage http_resp;
124 http_resp := f_http_transact(url := "/api/backend/v1/slotmaps", method := "POST",
125 body := body, exp := tr_HTTP_Resp(exp_sts))
126 return http_resp.response;
127}
128
129/* run a HTTP PUT to add a new slotmap to the remsim-server */
130function f_rsres_post_reset(template integer exp_sts := 200)
131runs on http_CT return HTTPResponse {
132 var HTTPMessage http_resp;
133 http_resp := f_http_transact(url := "/api/backend/v1/global-reset", method := "POST",
134 body := "", exp := tr_HTTP_Resp(exp_sts))
135 return http_resp.response;
136}
137
138
139/* run a HTTP DELETE to remove a slotmap from te remsim-server */
140function f_rsres_delete_slotmap(BankSlot bs, template integer exp_sts := 200)
141runs on http_CT return HTTPResponse {
142 var HTTPMessage http_resp;
143 var integer slotmap_id := bs.bankId * 65536 + bs.slotNr;
144 http_resp := f_http_transact(url := "/api/backend/v1/slotmaps/" & int2str(slotmap_id),
145 method := "DELETE", exp := tr_HTTP_Resp(exp_sts));
146 return http_resp.response;
147}
148
149
150function f_rsres_init() runs on http_CT {
151 f_http_init(mp_server_ip, mp_rsres_port);
152 f_rsres_post_reset();
153}
154
155type component test_CT extends rspro_client_CT, http_CT {
156};
157
158
159testcase TC_connect_and_nothing() runs on rspro_client_CT {
160 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, "foobar"));
161 timer T := 20.0;
162
163 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
164 T.start;
165 /* expect that we're disconnected if we never send a ConnectClientReq */
166 alt {
167 [] RSPRO[0].receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_ACK)) { repeat; }
168 [] RSPRO[0].receive(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN)) {
169 setverdict(pass);
170 }
171 [] T.timeout {
172 setverdict(fail, "Timeout waiting for disconnect");
173 }
174 }
175}
176
177testcase TC_connect_client() runs on test_CT {
178 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, "foobar"));
179 var JsRoot js;
180
181 f_rsres_init();
182 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
183 rspro[0].rspro_client_slot := valueof(ts_ClientSlot(3,4));
184
185 js := f_rsres_get("/api/backend/v1/clients");
186 if (not match(js.clients, JsClients:{})) {
187 setverdict(fail, "Initial state not empty");
188 mtc.stop;
189 }
190 f_rspro_connect_client(0);
191 js := f_rsres_get("/api/backend/v1/clients");
192 if (not match(js.clients[0], tr_JsClient(CONNECTED_CLIENT, rspro[0].rspro_id))) {
193 setverdict(fail, "Non-matching JSON response");
194 mtc.stop;
195 }
196 //as_rspro_cfg_client_id(0, cslot);
197 setverdict(pass);
198}
199
200testcase TC_connect_bank() runs on test_CT {
201 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, "foobar"));
202 var JsRoot js;
203
204 f_rsres_init();
205 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
206 rspro[0].rspro_bank_id := 1;
207 rspro[0].rspro_bank_nslots := 8;
208
209 js := f_rsres_get("/api/backend/v1/banks");
210 if (not match(js.banks, JsBanks:{})) {
211 setverdict(fail, "Initial state not empty");
212 mtc.stop;
213 }
214 f_rspro_connect_client(0);
215 js := f_rsres_get("/api/backend/v1/banks");
216 if (not match(js.banks[0], tr_JsBank(CONNECTED_BANKD, rspro[0].rspro_id, rspro[0].rspro_bank_id,
217 rspro[0].rspro_bank_nslots))) {
218 setverdict(fail, "Non-matching JSON response");
219 mtc.stop;
220 }
221 setverdict(pass);
222}
223
224function f_ensure_slotmaps(template JsSlotmaps maps)
225runs on http_CT {
226 var JsRoot js;
227
228 /* check that it is actually added */
229 js := f_rsres_get("/api/backend/v1/slotmaps");
230 if (match(js.slotmaps, maps)) {
231 setverdict(pass);
232 } else {
233 setverdict(fail, "Unexpected slotmaps: ", js);
234 }
235}
236
237/* verify that exactly only one slotmap exists (the specified one) */
238function f_ensure_slotmap_exists_only(template ClientSlot cslot, template BankSlot bslot,
239 template SlotmapState state := ?)
240runs on http_CT {
241 f_ensure_slotmaps({ tr_JsSlotmap(bslot, cslot, state) } );
242}
243
244/* verify that exactly only one slotmap exists (possibly among others) */
245function f_ensure_slotmap_exists(template ClientSlot cslot, template BankSlot bslot,
246 template SlotmapState state := ?)
247runs on http_CT {
248 f_ensure_slotmaps({ *, tr_JsSlotmap(bslot, cslot, state), * } );
249}
250
251
252/* test adding a single slotmap */
253testcase TC_slotmap_add() runs on test_CT {
254 f_rsres_init();
255
256 var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4)));
257 var HTTPResponse res := f_rsres_post_slotmap(sm);
258
259 /* check that it is actually added */
260 f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW);
261}
262
263/* test adding a slotmap and then connecting a client + bankd */
264testcase TC_slotmap_add_conn_cl_b() runs on test_CT {
265 /* Simulate one client */
266 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, testcasename()));
267 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
268 rspro[0].rspro_client_slot := valueof(ts_ClientSlot(3,4));
269
270 /* Simulate one bankd */
271 var BankSlot bslot := valueof(ts_BankSlot(1,2));
272 var ComponentIdentity rspro_bank_id := valueof(ts_CompId(remsimBankd, testcasename()));
273 f_rspro_init(rspro[1], mp_server_ip, mp_server_port, rspro_bank_id, 1);
274 rspro[1].rspro_bank_id := bslot.bankId;
275 rspro[1].rspro_bank_nslots := 8
276
277 f_rsres_init();
278 var JsSlotmap sm := valueof(ts_JsSlotmap(bslot, rspro[0].rspro_client_slot));
279 var HTTPResponse res;
280
281 /* 1) Create a new slotmap via HTTP */
282 res := f_rsres_post_slotmap(sm);
283
284 /* 2) verify that the slotmap exists and is NEW */
285 f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW);
286
287 /* 3) connect a client for that slotmap */
288 f_rspro_connect_client(0);
289
290 /* 4) connect a bankd for that slotmap */
291 f_rspro_connect_client(1);
292
293 /* 5) verify that the slotmap exists and is UNACKNOWLEDGED */
294 f_ensure_slotmap_exists_only(sm.client, sm.bank, UNACKNOWLEDGED);
295
296 /* 6) expect bankd to receive that mapping */
297 as_rspro_create_mapping(1, sm.client, sm.bank);
298
299 /* 7) verify that the slotmap exists and is ACTIVE */
300 f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE);
301
302 /* 8) expect the client to be configured with bankd side settings */
303 as_rspro_cfg_client_bank(0, bslot, ?);
304}
305
306/* test connecting a client and later adding a slotmap for it */
307testcase TC_conn_cl_b_slotmap_add() runs on test_CT {
308 /* Simulate one client */
309 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimClient, testcasename()));
310 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
311 rspro[0].rspro_client_slot := valueof(ts_ClientSlot(3,4));
312
313 /* Simulate one bankd */
314 var BankSlot bslot := valueof(ts_BankSlot(1,2));
315 var ComponentIdentity rspro_bank_id := valueof(ts_CompId(remsimBankd, testcasename()));
316 f_rspro_init(rspro[1], mp_server_ip, mp_server_port, rspro_bank_id, 1);
317 rspro[1].rspro_bank_id := bslot.bankId;
318 rspro[1].rspro_bank_nslots := 8
319
320 f_rsres_init();
321 var JsSlotmap sm := valueof(ts_JsSlotmap(bslot, rspro[0].rspro_client_slot));
322 var HTTPResponse res;
323
324 /* 1) connect a client for that slotmap */
325 f_rspro_connect_client(0);
326
327 /* 2) Create a new slotmap via HTTP */
328 res := f_rsres_post_slotmap(sm);
329
330 /* 3) verify that the slotmap exists and is NEW */
331 f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW);
332
333 /* 4) connect a bankd for that slotmap */
334 f_rspro_connect_client(1);
335
336 /* 5) verify that the slotmap exists and is UNACKNOWLEDGED */
337 f_ensure_slotmap_exists_only(sm.client, sm.bank, UNACKNOWLEDGED);
338
339 /* 6) expect bankd to receive that mapping */
340 as_rspro_create_mapping(1, sm.client, sm.bank);
341
342 /* 7) verify that the slotmap exists and is ACTIVE */
343 f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE);
344
345 /* 8) expect the client to be configured with bankd IP/port */
346 as_rspro_cfg_client_bank(0, bslot, ?);
347}
348
349/* simple delete of a 'NEW' slotmap */
350testcase TC_slotmap_del_new() runs on test_CT {
351 f_rsres_init();
352
353 var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4)));
354 var HTTPResponse res := f_rsres_post_slotmap(sm);
355 log(res);
356 res := f_rsres_delete_slotmap(sm.bank);
357 log(res);
358}
359
360/* simple delete of a 'UNACKNOWLEDGED' slotmap */
361testcase TC_slotmap_del_unack() runs on test_CT {
362 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, testcasename()));
363 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
364 rspro[0].rspro_bank_id := 1;
365 rspro[0].rspro_bank_nslots := 8;
366
367 f_rsres_init();
368 var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4)));
369 var HTTPResponse res;
370
371 /* Create a new slotmap via HTTP */
372 res := f_rsres_post_slotmap(sm);
373
374 /* verify that the slotmap exists and is NEW */
375 f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW);
376
377 /* connect a bankd for that slotmap */
378 f_rspro_connect_client(0);
379
380 /* expect the slotmap to be pushed to bank but don't ACK it */
381 f_rspro_exp(tr_RSPRO_CreateMappingReq(sm.client, sm.bank));
382
383 /* verify that the slotmap exists and is UNACKNOWLEDGED */
384 f_ensure_slotmap_exists_only(sm.client, sm.bank, UNACKNOWLEDGED);
385
386 /* delete the slotmap via REST */
387 res := f_rsres_delete_slotmap(sm.bank);
388
389 /* verify the slotmap is gone */
390 f_ensure_slotmaps({});
391}
392
393/* simple delete of a 'ACTIVE' slotmap */
394testcase TC_slotmap_del_active() runs on test_CT {
395 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, testcasename()));
396 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
397 rspro[0].rspro_bank_id := 1;
398 rspro[0].rspro_bank_nslots := 8;
399
400 f_rsres_init();
401 var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4)));
402 var HTTPResponse res;
403
404 /* Create a new slotmap via HTTP */
405 res := f_rsres_post_slotmap(sm);
406
407 /* verify that the slotmap exists and is NEW */
408 f_ensure_slotmap_exists_only(sm.client, sm.bank, NEW);
409
410 /* connect a bankd for that slotmap */
411 f_rspro_connect_client(0);
412
413 /* expect the slotmap to be pushed to bank and ACK it */
414 as_rspro_create_mapping(0, sm.client, sm.bank);
415
416 /* verify that the slotmap exists and is ACTIVE */
417 f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE);
418
419 f_sleep(1.0);
420
421 /* delete the slotmap via REST */
422 res := f_rsres_delete_slotmap(sm.bank);
423
424 /* verify the slotmap is gone from REST interface immediately */
425 f_ensure_slotmaps({});
426
427 /* verify the slotmap is removed from bankd */
428 as_rspro_remove_mapping(0, sm.client, sm.bank);
429}
430
431
432/* Add a slotmap to a currently active bank */
433testcase TC_slotmap_add_active_bank() runs on test_CT {
434 var ComponentIdentity rspro_id := valueof(ts_CompId(remsimBankd, testcasename()));
435 f_rspro_init(rspro[0], mp_server_ip, mp_server_port, rspro_id, 0);
436 rspro[0].rspro_bank_id := 1;
437 rspro[0].rspro_bank_nslots := 8;
438
439 f_rsres_init();
440 var JsSlotmap sm := valueof(ts_JsSlotmap(ts_BankSlot(1,2), ts_ClientSlot(3,4)));
441 var HTTPResponse res;
442
443 /* connect a bankd for that slotmap */
444 f_rspro_connect_client(0);
445
446 /* Create a new slotmap via HTTP */
447 res := f_rsres_post_slotmap(sm);
448
449 /* expect the slotmap to be pushed to bank and ACK it */
450 as_rspro_create_mapping(0, sm.client, sm.bank);
451
452 /* verify that the slotmap exists and is ACTIVE */
453 f_ensure_slotmap_exists_only(sm.client, sm.bank, ACTIVE);
454}
455
456
457
458
459/* TODO
460 * - add slotmap, then connect matching client (see if slotmap is sent; check slotmap state)
461 * - connect client w/slotmap; delete slotmap via REST (see if it is deleted)
462 * - don't acknowledge delete from client, disconnect client (see if slotmap is deleted)
463 * - delete non-existing slotmap via REST
464 * - create slotmap with integers out of range via REST
465
466 * - connect from unknown client (name not known, no clientId provisioned?
467 * - add client name/ID mappings from REST API?
468 */
469
470
471control {
472 execute( TC_connect_and_nothing() );
473 execute( TC_connect_client() );
474 execute( TC_connect_bank() );
475 execute( TC_slotmap_add() );
476 execute( TC_slotmap_add_conn_cl_b() );
477 execute( TC_conn_cl_b_slotmap_add() );
478 execute( TC_slotmap_del_new() );
479 execute( TC_slotmap_del_unack() );
480 execute( TC_slotmap_del_active() );
481 execute( TC_slotmap_add_active_bank() );
482}
483
484
485}