vapi_cpp_test.cpp revision 2959d42f
1/*
2 *------------------------------------------------------------------
3 * Copyright (c) 2017 Cisco and/or its affiliates.
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 */
17
18#include <memory>
19#include <stdio.h>
20#include <unistd.h>
21#include <assert.h>
22#include <setjmp.h>
23#include <check.h>
24#include <vapi/vapi.hpp>
25#include <vapi/vpe.api.vapi.hpp>
26#include <vapi/interface.api.vapi.hpp>
27#include <fake.api.vapi.hpp>
28
29DEFINE_VAPI_MSG_IDS_VPE_API_JSON;
30DEFINE_VAPI_MSG_IDS_INTERFACE_API_JSON;
31DEFINE_VAPI_MSG_IDS_FAKE_API_JSON;
32
33static char *app_name = nullptr;
34static char *api_prefix = nullptr;
35static const int max_outstanding_requests = 32;
36static const int response_queue_size = 32;
37
38#define WAIT_FOR_RESPONSE(param, ret)      \
39  do                                       \
40    {                                      \
41      ret = con.wait_for_response (param); \
42    }                                      \
43  while (ret == VAPI_EAGAIN)
44
45using namespace vapi;
46
47void verify_show_version_reply (const Show_version_reply &r)
48{
49  auto &p = r.get_payload ();
50  printf ("show_version_reply: program: `%s', version: `%s', build directory: "
51          "`%s', build date: `%s'\n",
52          vl_api_from_api_string (p.program),
53          vl_api_from_api_string (p.version),
54          vl_api_from_api_string (p.build_directory),
55          vl_api_from_api_string (p.build_date));
56  ck_assert_str_eq ("vpe", (char *)vl_api_from_api_string (p.program));
57}
58
59Connection con;
60
61void setup (void)
62{
63  vapi_error_e rv = con.connect (
64      app_name, api_prefix, max_outstanding_requests, response_queue_size);
65  ck_assert_int_eq (VAPI_OK, rv);
66}
67
68void teardown (void)
69{
70  con.disconnect ();
71}
72
73START_TEST (test_show_version_1)
74{
75  printf ("--- Show version by reading response associated to request ---\n");
76  Show_version sv (con);
77  vapi_error_e rv = sv.execute ();
78  ck_assert_int_eq (VAPI_OK, rv);
79  WAIT_FOR_RESPONSE (sv, rv);
80  ck_assert_int_eq (VAPI_OK, rv);
81  auto &r = sv.get_response ();
82  verify_show_version_reply (r);
83}
84
85END_TEST;
86
87struct Show_version_cb
88{
89  Show_version_cb () : called{0} {};
90  int called;
91  vapi_error_e operator() (Show_version &sv)
92  {
93    auto &r = sv.get_response ();
94    verify_show_version_reply (r);
95    ++called;
96    return VAPI_OK;
97  }
98};
99
100START_TEST (test_show_version_2)
101{
102  printf ("--- Show version by getting a callback ---\n");
103  Show_version_cb cb;
104  Show_version sv (con, std::ref (cb));
105  vapi_error_e rv = sv.execute ();
106  ck_assert_int_eq (VAPI_OK, rv);
107  con.dispatch (sv);
108  ck_assert_int_eq (1, cb.called);
109}
110
111END_TEST;
112
113START_TEST (test_loopbacks_1)
114{
115  printf ("--- Create/delete loopbacks by waiting for response ---\n");
116  const auto num_ifs = 5;
117  u8 mac_addresses[num_ifs][6];
118  memset (&mac_addresses, 0, sizeof (mac_addresses));
119  u32 sw_if_indexes[num_ifs];
120  memset (&sw_if_indexes, 0xff, sizeof (sw_if_indexes));
121  for (int i = 0; i < num_ifs; ++i)
122    {
123      memcpy (&mac_addresses[i], "\1\2\3\4\5\6", 6);
124      mac_addresses[i][5] = i;
125    }
126  for (int i = 0; i < num_ifs; ++i)
127    {
128      Create_loopback cl (con);
129      auto &p = cl.get_request ().get_payload ();
130      memcpy (p.mac_address, mac_addresses[i], sizeof (p.mac_address));
131      auto e = cl.execute ();
132      ck_assert_int_eq (VAPI_OK, e);
133      vapi_error_e rv;
134      WAIT_FOR_RESPONSE (cl, rv);
135      ck_assert_int_eq (VAPI_OK, rv);
136      auto &rp = cl.get_response ().get_payload ();
137      ck_assert_int_eq (0, rp.retval);
138      sw_if_indexes[i] = rp.sw_if_index;
139    }
140  for (int i = 0; i < num_ifs; ++i)
141    {
142      printf ("Created loopback with MAC %02x:%02x:%02x:%02x:%02x:%02x --> "
143              "sw_if_index %u\n",
144              mac_addresses[i][0], mac_addresses[i][1], mac_addresses[i][2],
145              mac_addresses[i][3], mac_addresses[i][4], mac_addresses[i][5],
146              sw_if_indexes[i]);
147    }
148
149  { // new context
150    bool seen[num_ifs] = {0};
151    Sw_interface_dump d (con);
152    auto &p = d.get_request ().get_payload ();
153    p.name_filter_valid = 0;
154    memset (p.name_filter.buf, 0, p.name_filter.length);
155    auto rv = d.execute ();
156    ck_assert_int_eq (VAPI_OK, rv);
157    WAIT_FOR_RESPONSE (d, rv);
158    ck_assert_int_eq (VAPI_OK, rv);
159    auto &rs = d.get_result_set ();
160    for (auto &r : rs)
161      {
162        auto &p = r.get_payload ();
163        for (int i = 0; i < num_ifs; ++i)
164          {
165            if (sw_if_indexes[i] == p.sw_if_index)
166              {
167                ck_assert_int_eq (0, seen[i]);
168                seen[i] = true;
169              }
170          }
171      }
172    for (int i = 0; i < num_ifs; ++i)
173      {
174        ck_assert_int_eq (1, seen[i]);
175      }
176  }
177
178  for (int i = 0; i < num_ifs; ++i)
179    {
180      Delete_loopback dl (con);
181      dl.get_request ().get_payload ().sw_if_index = sw_if_indexes[i];
182      auto rv = dl.execute ();
183      ck_assert_int_eq (VAPI_OK, rv);
184      WAIT_FOR_RESPONSE (dl, rv);
185      ck_assert_int_eq (VAPI_OK, rv);
186      auto &response = dl.get_response ();
187      auto rp = response.get_payload ();
188      ck_assert_int_eq (0, rp.retval);
189      printf ("Deleted loopback with sw_if_index %u\n", sw_if_indexes[i]);
190    }
191
192  { // new context
193    Sw_interface_dump d (con);
194    auto &p = d.get_request ().get_payload ();
195    p.name_filter_valid = 0;
196    memset (p.name_filter.buf, 0, p.name_filter.length);
197    auto rv = d.execute ();
198    ck_assert_int_eq (VAPI_OK, rv);
199    WAIT_FOR_RESPONSE (d, rv);
200    ck_assert_int_eq (VAPI_OK, rv);
201    auto &rs = d.get_result_set ();
202    for (auto &r : rs)
203      {
204        auto &p = r.get_payload ();
205        for (int i = 0; i < num_ifs; ++i)
206          {
207            ck_assert_int_ne (sw_if_indexes[i], p.sw_if_index);
208          }
209      }
210  }
211}
212
213END_TEST;
214
215struct Create_loopback_cb
216{
217  Create_loopback_cb () : called{0}, sw_if_index{0} {};
218  int called;
219  u32 sw_if_index;
220  bool seen;
221  vapi_error_e operator() (Create_loopback &cl)
222  {
223    auto &r = cl.get_response ();
224    sw_if_index = r.get_payload ().sw_if_index;
225    ++called;
226    return VAPI_OK;
227  }
228};
229
230struct Delete_loopback_cb
231{
232  Delete_loopback_cb () : called{0}, sw_if_index{0} {};
233  int called;
234  u32 sw_if_index;
235  bool seen;
236  vapi_error_e operator() (Delete_loopback &dl)
237  {
238    auto &r = dl.get_response ();
239    ck_assert_int_eq (0, r.get_payload ().retval);
240    ++called;
241    return VAPI_OK;
242  }
243};
244
245template <int num_ifs> struct Sw_interface_dump_cb
246{
247  Sw_interface_dump_cb (std::array<Create_loopback_cb, num_ifs> &cbs)
248      : called{0}, cbs{cbs} {};
249  int called;
250  std::array<Create_loopback_cb, num_ifs> &cbs;
251  vapi_error_e operator() (Sw_interface_dump &d)
252  {
253    for (auto &y : cbs)
254      {
255        y.seen = false;
256      }
257    for (auto &x : d.get_result_set ())
258      {
259        auto &p = x.get_payload ();
260        for (auto &y : cbs)
261          {
262            if (p.sw_if_index == y.sw_if_index)
263              {
264                y.seen = true;
265              }
266          }
267      }
268    for (auto &y : cbs)
269      {
270        ck_assert_int_eq (true, y.seen);
271      }
272    ++called;
273    return VAPI_OK;
274  }
275};
276
277START_TEST (test_loopbacks_2)
278{
279  printf ("--- Create/delete loopbacks by getting a callback ---\n");
280  const auto num_ifs = 5;
281  u8 mac_addresses[num_ifs][6];
282  memset (&mac_addresses, 0, sizeof (mac_addresses));
283  for (int i = 0; i < num_ifs; ++i)
284    {
285      memcpy (&mac_addresses[i], "\1\2\3\4\5\6", 6);
286      mac_addresses[i][5] = i;
287    }
288  std::array<Create_loopback_cb, num_ifs> ccbs;
289  std::array<std::unique_ptr<Create_loopback>, num_ifs> clcs;
290  for (int i = 0; i < num_ifs; ++i)
291    {
292      Create_loopback *cl = new Create_loopback (con, std::ref (ccbs[i]));
293      clcs[i].reset (cl);
294      auto &p = cl->get_request ().get_payload ();
295      memcpy (p.mac_address, mac_addresses[i], sizeof (p.mac_address));
296      auto e = cl->execute ();
297      ck_assert_int_eq (VAPI_OK, e);
298    }
299  con.dispatch ();
300  for (int i = 0; i < num_ifs; ++i)
301    {
302      ck_assert_int_eq (1, ccbs[i].called);
303      printf ("Created loopback with MAC %02x:%02x:%02x:%02x:%02x:%02x --> "
304              "sw_if_index %u\n",
305              mac_addresses[i][0], mac_addresses[i][1], mac_addresses[i][2],
306              mac_addresses[i][3], mac_addresses[i][4], mac_addresses[i][5],
307              ccbs[i].sw_if_index);
308    }
309
310  Sw_interface_dump_cb<num_ifs> swdcb (ccbs);
311  Sw_interface_dump d (con, std::ref (swdcb));
312  auto &p = d.get_request ().get_payload ();
313  p.name_filter_valid = 0;
314  memset (p.name_filter.buf, 0, p.name_filter.length);
315  auto rv = d.execute ();
316  ck_assert_int_eq (VAPI_OK, rv);
317  WAIT_FOR_RESPONSE (d, rv);
318  ck_assert_int_eq (VAPI_OK, rv);
319  ck_assert_int_ne (0, swdcb.called);
320  std::array<Delete_loopback_cb, num_ifs> dcbs;
321  std::array<std::unique_ptr<Delete_loopback>, num_ifs> dlcs;
322  for (int i = 0; i < num_ifs; ++i)
323    {
324      Delete_loopback *dl = new Delete_loopback (con, std::ref (dcbs[i]));
325      dlcs[i].reset (dl);
326      auto &p = dl->get_request ().get_payload ();
327      p.sw_if_index = ccbs[i].sw_if_index;
328      dcbs[i].sw_if_index = ccbs[i].sw_if_index;
329      auto e = dl->execute ();
330      ck_assert_int_eq (VAPI_OK, e);
331    }
332  con.dispatch ();
333  for (auto &x : dcbs)
334    {
335      ck_assert_int_eq (true, x.called);
336      printf ("Deleted loopback with sw_if_index %u\n", x.sw_if_index);
337    }
338
339  { // new context
340    Sw_interface_dump d (con);
341    auto &p = d.get_request ().get_payload ();
342    p.name_filter_valid = 0;
343    memset (p.name_filter.buf, 0, p.name_filter.length);
344    auto rv = d.execute ();
345    ck_assert_int_eq (VAPI_OK, rv);
346    WAIT_FOR_RESPONSE (d, rv);
347    ck_assert_int_eq (VAPI_OK, rv);
348    auto &rs = d.get_result_set ();
349    for (auto &r : rs)
350      {
351        auto &p = r.get_payload ();
352        for (int i = 0; i < num_ifs; ++i)
353          {
354            ck_assert_int_ne (ccbs[i].sw_if_index, p.sw_if_index);
355          }
356      }
357  }
358}
359
360END_TEST;
361
362START_TEST (test_unsupported)
363{
364  printf ("--- Unsupported messages ---\n");
365  bool thrown = false;
366  try
367    {
368      Test_fake_msg fake (con);
369    }
370  catch (const Msg_not_available_exception &)
371    {
372      thrown = true;
373      printf ("Constructing unsupported msg not possible - test pass.\n");
374    }
375  ck_assert_int_eq (true, thrown);
376  thrown = false;
377  try
378    {
379      Test_fake_dump fake (con);
380    }
381  catch (const Msg_not_available_exception &)
382    {
383      thrown = true;
384      printf ("Constructing unsupported dump not possible - test pass.\n");
385    }
386  ck_assert_int_eq (true, thrown);
387  thrown = false;
388  try
389    {
390      Event_registration<Test_fake_details> fake (con);
391    }
392  catch (const Msg_not_available_exception &)
393    {
394      thrown = true;
395      printf ("Constructing unsupported event registration not possible - "
396              "test pass.\n");
397    }
398  ck_assert_int_eq (true, thrown);
399}
400
401END_TEST;
402
403Suite *test_suite (void)
404{
405  Suite *s = suite_create ("VAPI test");
406
407  TCase *tc_cpp_api = tcase_create ("C++ API");
408  tcase_set_timeout (tc_cpp_api, 25);
409  tcase_add_checked_fixture (tc_cpp_api, setup, teardown);
410  tcase_add_test (tc_cpp_api, test_show_version_1);
411  tcase_add_test (tc_cpp_api, test_show_version_2);
412  tcase_add_test (tc_cpp_api, test_loopbacks_1);
413  tcase_add_test (tc_cpp_api, test_loopbacks_2);
414  tcase_add_test (tc_cpp_api, test_unsupported);
415  suite_add_tcase (s, tc_cpp_api);
416
417  return s;
418}
419
420int main (int argc, char *argv[])
421{
422  if (3 != argc)
423    {
424      printf ("Invalid argc==`%d'\n", argc);
425      return EXIT_FAILURE;
426    }
427  app_name = argv[1];
428  api_prefix = argv[2];
429  printf ("App name: `%s', API prefix: `%s'\n", app_name, api_prefix);
430
431  int number_failed;
432  Suite *s;
433  SRunner *sr;
434
435  s = test_suite ();
436  sr = srunner_create (s);
437
438  srunner_run_all (sr, CK_NORMAL);
439  number_failed = srunner_ntests_failed (sr);
440  srunner_free (sr);
441  return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
442}
443
444/*
445 * fd.io coding-style-patch-verification: ON
446 *
447 * Local Variables:
448 * eval: (c-set-style "gnu")
449 * End:
450 */
451