Motr  M0
client.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2016-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #include "ut/ut.h" /* M0_UT_ASSERT */
24 #include "motr/ut/client.h"
25 #include "motr/client.h"
26 #include "motr/client_internal.h"
27 
28 /*
29  * Including the c files so we can replace the M0_PRE asserts
30  * in order to test them.
31  */
32 #include "motr/client.c"
33 #include "motr/client_init.c"
34 
35 #include "lib/ub.h"
36 #include "lib/errno.h" /* ETIMEDOUT */
37 #include "lib/timer.h" /* m0_timer_init */
38 #include "lib/finject.h" /* m0_fi_enable_once */
39 #include "conf/objs/common.h"
40 
41 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CLIENT
42 #include "lib/trace.h" /* M0_LOG */
43 
45 static uint32_t ut_launch_cb_pass_count;
46 static uint32_t ut_launch_cb_fail_count;
47 
49 static uint32_t ut_m0_op_fini_cb_count;
50 
53 
56 
57 /* Default Client configuration*/
59 
60 M0_INTERNAL void ut_realm_entity_setup(struct m0_realm *realm,
61  struct m0_entity *ent,
62  struct m0_client *cinst)
63 {
64  struct m0_uint128 id;
65 
67  M0_UT_ASSERT(ent != NULL);
69 
70  M0_SET0(realm);
72 
73  id = M0_ID_APP;
74  id.u_lo++;
75 
76  M0_SET0(ent);
78 }
79 
80 static bool ut_test_floor_tick_cb(struct m0_clink *cl)
81 {
83  return false;
84 }
85 
95  int start_state, int stop_state)
96 {
97  struct m0_clink clink;
98 
99  M0_UT_ASSERT(stop_state >= IL_UNINITIALISED);
100  M0_UT_ASSERT(instance->m0c_initlift_sm.sm_state == start_state);
101 
103 
104  m0_sm_group_lock(&instance->m0c_sm_group);
106  m0_clink_add(&instance->m0c_initlift_sm.sm_chan, &clink);
107  m0_sm_move(&instance->m0c_initlift_sm, 0, stop_state);
110  m0_sm_group_unlock(&instance->m0c_sm_group);
111 
112  if (instance->m0c_initlift_sm.sm_state != IL_UNINITIALISED
113  && instance->m0c_initlift_sm.sm_state != IL_FAILED) {
115  M0_UT_ASSERT(instance->m0c_initlift_sm.sm_state == stop_state);
116  }
117  if (instance->m0c_initlift_direction == STARTUP)
118  M0_UT_ASSERT(instance->m0c_initlift_rc == 0);
119 
120  if(instance->m0c_initlift_sm.sm_state != IL_FAILED)
121  M0_UT_ASSERT(instance->m0c_initlift_sm.sm_rc == 0);
122  else
123  M0_UT_ASSERT(instance->m0c_initlift_sm.sm_rc ==
124  instance->m0c_initlift_rc);
125 }
126 
137  int limit, bool fail)
138 {
139  int i;
140  struct m0_sm *sm = &instance->m0c_initlift_sm;
141 
142  M0_UT_ASSERT(limit <= IL_INITIALISED);
144 
145  M0_UT_ASSERT(instance->m0c_initlift_direction == STARTUP);
146  M0_UT_ASSERT(sm->sm_rc == 0);
148 
149  for (i = IL_UNINITIALISED + 1; i <= limit; i++)
151  sm->sm_state, i);
152  M0_UT_ASSERT(sm->sm_state == limit);
153 
154  if (fail) {
155  /*
156  * Now Reverse direction and shut down
157  *(with a simulated error)
158  */
159  initlift_fail(-EPROTO, instance);
160  M0_UT_ASSERT(instance->m0c_initlift_direction
161  == SHUTDOWN);
162  M0_UT_ASSERT(sm->sm_rc == 0);
163  M0_UT_ASSERT(instance->m0c_initlift_rc == -EPROTO);
164  } else {
165  /* Perform a clean shutdown */
166  instance->m0c_initlift_direction = SHUTDOWN;
167  M0_UT_ASSERT(sm->sm_rc == 0);
168  M0_UT_ASSERT(instance->m0c_initlift_rc == 0);
169  }
170 
171  /*
172  * A failure will always happen in some state, which is expected to
173  * clean up after itself. In this case we triggered a failure from
174  * the outside, so we choose to fudge the current state.
175  *
176  * A clean shutdown would normally only happen from
177  * IL_INITIALISED, we changed direction half way through, so
178  * need to fudge the current state so that we pass through it for
179  * startup and shutdown.
180  */
181  sm->sm_state++;
182 
183  for (i = sm->sm_state - 1; i >= IL_UNINITIALISED; i--)
185  sm->sm_state, i);
186 
187  if (fail) {
188  /*
189  * Check we ended up in IL_FAILED, with sm_rc set
190  * to -EPROTO
191  */
193  M0_UT_ASSERT(sm->sm_rc == -EPROTO);
194  } else {
196  M0_UT_ASSERT(sm->sm_rc == 0);
197  }
198 }
199 
211 static void ut_test_m0_client_init(void)
212 {
213  int i;
214  int rc = 0; /* required */
215  struct m0_client *instance;
216 
217  /* Check -ENOMEM will be returned */
218  m0_fi_enable_once("m0_alloc", "fail_allocation");
219  instance = NULL;
220  rc = INIT(&instance);
221  M0_UT_ASSERT(rc == -ENOMEM);
223 
224  /* Check NULL or 0 for each argument */
232 
233  /*
234  * Cause the initlift to fail during init to check the error is
235  * propagated.
236  */
237  m0_fi_enable_once("initlift_move_next_floor", "failure");
238  rc = INIT(&instance);
239  M0_UT_ASSERT(rc == -EPROTO);
241 
242  m0_fi_enable("initlift_get_next_floor", "ut");
243  m0_fi_enable("initlift_move_next_floor", "immediate_ret");
244  /*
245  * Trigger a failure at each 'floor', to check m0_client_init
246  * can finalise itself if an initialisation phase causes a failure.
247  */
248  /*
249  * The floor after IL_AST_THREAD attempts to contact confd,
250  * which we can't do from a unit-test environment (cyclic dependency
251  * with user-space:confd).
252  */
253  for (i = IL_UNINITIALISED + 1; i <= IL_AST_THREAD; i++) {
254  instance = NULL;
255  rc = INIT(&instance);
256  M0_UT_ASSERT(rc == 0);
258  m0_client_fini(instance, false);
259  }
260 
261  m0_fi_disable("initlift_get_next_floor", "ut");
262  m0_fi_disable("initlift_move_next_floor", "immediate_ret");
263 }
264 
265 M0_INTERNAL int ut_m0_client_init(struct m0_client **instance)
266 {
267  int i;
268  int rc;
269  struct m0_sm *sm;
270  struct m0_fid id;
271  struct m0_pool *pool;
272  struct m0_pool *mdpool;
273  struct m0_pool_version *pv;
274  struct m0_pool_version *mdpv;
275 
276  *instance = NULL;
277  m0_fi_enable_once("initlift_move_next_floor", "immediate_ret");
278  rc = INIT(instance);
279 
280  m0_fi_enable("initlift_get_next_floor", "ut");
281  if (rc == 0) {
282  sm = &(*instance)->m0c_initlift_sm;
283  (*instance)->m0c_initlift_direction = STARTUP;
284 
285  for (i = IL_UNINITIALISED + 1; i <= IL_RPC;
286  /*i <= IL_AST_THREAD;*/ i++) {
288  sm->sm_state,
289  i);
290  }
291 
292  /* Some dummy stuff for pools. */
294  M0_UT_ASSERT(pool != NULL);
295  M0_SET0(&id);
296  m0_pool_init(pool, &id, 0);
297  pools_tlist_init(&(*instance)->m0c_pools_common.pc_pools);
298  pools_tlink_init_at_tail(pool, &((*instance)->m0c_pools_common.pc_pools));
299 
300  M0_ALLOC_PTR(mdpool);
301  M0_UT_ASSERT(mdpool != NULL);
302  id.f_key=1;
303  m0_pool_init(mdpool, &id, 0);
304  pools_tlink_init_at_tail(mdpool, &((*instance)->m0c_pools_common.pc_pools));
305 
306  M0_ALLOC_PTR(pv);
307  M0_UT_ASSERT(pv != NULL);
308  M0_SET0(pv);
309  pv->pv_pool = pool;
310  pool_version_tlink_init_at_tail(pv, &pool->po_vers);
311 
312  (*instance)->m0c_pools_common.pc_cur_pver = pv;
313  (*instance)->m0c_pools_common.pc_confc = (struct m0_confc *)DUMMY_PTR;
314 
315  M0_ALLOC_PTR(mdpv);
316  M0_UT_ASSERT(mdpv != NULL);
317  M0_SET0(mdpv);
318  mdpv->pv_pool = mdpool;
319  pool_version_tlink_init_at_tail(mdpv, &mdpool->po_vers);
320  (*instance)->m0c_pools_common.pc_md_pool = mdpool;
321 
322  (*instance)->m0c_process_fid = M0_FID_TINIT(M0_CONF__PROCESS_FT_ID, 0, 1);
323  }
324  m0_fi_disable("initlift_get_next_floor", "ut");
325 
326  return rc;
327 }
328 
330 M0_INTERNAL void ut_test_m0_client_fini(void)
331 {
332  int i;
333  int rc = 0; /* required */
334  struct m0_client *instance = NULL;
335 
336  m0_fi_enable("initlift_get_next_floor", "ut");
337  m0_fi_enable("initlift_move_next_floor", "immediate_ret");
338  /*
339  * Shutdown from each 'floor' in turn, this catches any
340  * 'can't finalise it' as early as possible. The failure version of
341  * this test occurs in m0_client_init's tests.
342  */
343  for (i = IL_UNINITIALISED + 1; i <= IL_AST_THREAD; i++) {
344  instance = NULL;
345  rc = INIT(&instance);
346  M0_UT_ASSERT(rc == 0);
348  m0_client_fini(instance, false);
349  }
350  m0_fi_disable("initlift_get_next_floor", "ut");
351  m0_fi_disable("initlift_move_next_floor", "immediate_ret");
352 }
353 
354 M0_INTERNAL void ut_m0_client_fini(struct m0_client **instance)
355 {
356  int i;
357  struct m0_sm *sm;
358 
359  m0_fi_enable("initlift_get_next_floor", "ut");
360  if (*instance != NULL) {
361  sm = &(*instance)->m0c_initlift_sm;
362 
363  (*instance)->m0c_initlift_direction = SHUTDOWN;
364 
365  /*
366  * A clean shutdown would normally only happen from
367  * IL_INITIALISED, we changed direction half way through, so
368  * need to fudge the current state so that we pass through it for
369  * startup and shutdown.
370  */
371  sm->sm_state++;
372 
373  for (i = sm->sm_state - 1; i >= IL_UNINITIALISED; i--) {
375  sm->sm_state,
376  i);
377  }
378 
379  }
380  m0_fi_disable("initlift_get_next_floor", "ut");
381 
382  m0_client_fini(*instance, false);
383  *instance = NULL;
384 }
385 
386 /* Don't use INIT after this point */
387 #undef INIT
388 
389 
391 {
392  struct m0_client *instance = NULL;
393  struct m0_entity entity;
394  struct m0_uint128 id;
395  struct m0_container uber_realm;
396  struct m0_sm_group *en_grp;
397 
398  /* initialise client */
402  ut_realm_entity_setup(&uber_realm.co_realm, &entity, instance);
403  en_grp = &entity.en_sm_group;
404  m0_sm_group_init(en_grp);
405 
406  /* we need a valid id */
407  id = M0_ID_APP;
408  id.u_lo++;
409 
410  /* base case: no error */
411  m0_sm_group_lock(en_grp);
413  m0_sm_group_unlock(en_grp);
414 
415  /* Check a bad type is caught, but not asserted */
416  entity.en_type = 42;
417  m0_sm_group_lock(en_grp);
419  m0_sm_group_unlock(en_grp);
420  entity.en_type = M0_ET_OBJ;
421 
422  m0_entity_fini(&entity);
423 
424  /* finalise client */
426 }
427 
434 static void ut_test_m0_entity_init(void)
435 {
436  struct m0_entity entity;
437  struct m0_uint128 id;
438  struct m0_client *instance = NULL;
439  struct m0_container uber_realm;
440 
441  /* initialise client */
444  &M0_UBER_REALM,
445  instance);
446 
447  /* we need a valid id */
448  id = M0_ID_APP;
449  id.u_lo++;
450 
451  /* base case: no error */
452  m0_entity_init(&entity, &uber_realm.co_realm,
453  &id, M0_ET_OBJ);
454 
455  /* finalise client */
457 }
458 
465 static void ut_test_m0_obj_init(void)
466 {
467  struct m0_obj obj;
468  struct m0_uint128 id;
469  struct m0_client *instance = NULL;
470  struct m0_container uber_realm;
471 
472  /* initialise client */
475  &M0_UBER_REALM,
476  instance);
477 
478  /* we need a valid id */
479  id = M0_ID_APP;
480  id.u_lo++;
481 
482  /* base case: no error */
483  M0_SET0(&obj);
484  m0_obj_init(&obj, &uber_realm.co_realm, &id,
486 
487  /* check the initialisation */
488  M0_UT_ASSERT(obj.ob_entity.en_type == M0_ET_OBJ);
489  M0_UT_ASSERT(m0_uint128_cmp(&obj.ob_entity.en_id, &id) == 0);
490  M0_UT_ASSERT(obj.ob_entity.en_realm == &uber_realm.co_realm);
491  M0_UT_ASSERT(obj.ob_attr.oa_bshift == M0_DEFAULT_BUF_SHIFT);
492 
493  /* finalise client */
495 }
496 
502 static void
504 {
505  M0_UT_ASSERT(oc != NULL);
507 
509 
511 }
512 
518 static void
520 {
521  M0_UT_ASSERT(oc != NULL);
523 
525 
526  //m0_sm_move(&oc->oc_op.op_sm, -EINVAL, M0_OS_FAILED);
527 }
528 
530 static void
532  struct m0_entity *ent,
533  void (*cb)(struct m0_op_common *oc))
534 {
535  struct m0_sm_group *grp;
536 
537  M0_SET0(cop);
538 
539  grp = &cop->oc_op.op_sm_group;
543  cop->oc_op.op_entity = ent;
544  cop->oc_op.op_size = sizeof *cop;
545  cop->oc_cb_launch = cb;
546 
547  m0_op_bob_init(&cop->oc_op);
548  m0_op_common_bob_init(cop);
549 }
550 
554 static void ut_test_m0_op_launch_one(void)
555 {
556  struct m0_op_common oc;
557  struct m0_client *instance = NULL;
558  struct m0_entity ent;
559  struct m0_realm realm;
560 
561  /* init */
565 
566  /* base case */
568  m0_op_launch_one(&oc.oc_op);
570 
572 
573  /* finalise client */
575 }
576 
578 static void ut_test_m0_op_launch(void)
579 {
580  struct m0_entity ent;
581  struct m0_op_common cops[2];
582  struct m0_op *p_ops[2];
583  struct m0_realm realm;
584  struct m0_client *instance = NULL;
585 
586  /* initialise client */
588 
589  /* Give ops some sane state */
591  ut_init_fake_op(&cops[0], &ent,
593  ut_init_fake_op(&cops[1], &ent,
595  M0_SET_ARR0(p_ops);
596  p_ops[0] = &cops[0].oc_op;
597  p_ops[1] = &cops[1].oc_op;
598 
599  /* Check our op_launch has a firm foundation */
601  m0_op_launch(p_ops, ARRAY_SIZE(p_ops));
603 
604  /* Check op_launch continues even if an operation fails */
605  ut_init_fake_op(&cops[0], &ent,
607  ut_init_fake_op(&cops[1], &ent,
611  m0_op_launch(p_ops, ARRAY_SIZE(p_ops));
614 
616 
617  /* finalise client */
619 }
620 
625 static void ut_test_op_sm_callme(struct m0_op *op)
626 {
627  M0_UT_ASSERT(op != NULL);
629 }
630 
634 static void ut_test_op_sm_dont_callme(struct m0_op *op)
635 {
636  M0_UT_ASSERT(0);
637 }
638 
647 static void ut_test_op_sm_cbs_helper(struct m0_op_ops *cbs,
648  int executed, int stable,
649  int failed)
650 {
651  M0_UT_ASSERT(cbs != NULL);
652 
653  if (executed)
655  else
657  if (stable)
659  else
661  if (failed)
663  else
665 }
666 
671 static void ut_test_op_sm(void)
672 {
673  /*
674  * Create and move an op sm through all the permisable states.
675  * The sm code will panic if we try an invalid transition.
676  */
677  struct m0_op op;
678  struct m0_op_ops cbs;
679  struct m0_client *instance = NULL;
680  struct m0_sm_group *grp;
681 
682 
683  /* initialise client */
685 
686  M0_SET0(&op);
687  op.op_size = sizeof(struct m0_op_common);
688  op.op_cbs = &cbs;
689  m0_op_bob_init(&op);
690 
691  grp = &op.op_sm_group;
694 
695  /* INIT -> FAILED */
696  ut_test_op_sm_cbs_helper(&cbs, 0, 0, 1);
699  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_INITIALISED);
700  m0_sm_move(&op.op_sm, -EINVAL, M0_OS_FAILED);
701  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_FAILED);
703 
704  /* INIT -> LAUNCHED -> EXECUTED -> STABLE */
705  ut_test_op_sm_cbs_helper(&cbs, 1, 1, 0);
708  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_INITIALISED);
709  m0_sm_move(&op.op_sm, 0, M0_OS_LAUNCHED);
710  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_LAUNCHED);
711  m0_sm_move(&op.op_sm, 0, M0_OS_EXECUTED);
712  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_EXECUTED);
713  m0_sm_move(&op.op_sm, 0, M0_OS_STABLE);
714  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_STABLE);
716 
717  /* INIT -> LAUNCHED -> EXECUTED -> FAILED */
718  ut_test_op_sm_cbs_helper(&cbs, 1, 0, 1);
721  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_INITIALISED);
722  m0_sm_move(&op.op_sm, 0, M0_OS_LAUNCHED);
723  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_LAUNCHED);
724  m0_sm_move(&op.op_sm, 0, M0_OS_EXECUTED);
725  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_EXECUTED);
726  m0_sm_move(&op.op_sm, -EINVAL, M0_OS_FAILED);
727  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_FAILED);
729 
730  /* INIT -> LAUNCHED -> FAILED */
731  ut_test_op_sm_cbs_helper(&cbs, 0, 0, 1);
734  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_INITIALISED);
735  m0_sm_move(&op.op_sm, 0, M0_OS_LAUNCHED);
736  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_LAUNCHED);
737  m0_sm_move(&op.op_sm, -EINVAL, M0_OS_FAILED);
738  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_FAILED);
740 
741  /*
742  * Test a INIT -> LAUNCHEd -> EXECUTED -> STABLE transition
743  * with no callbacks enabled - to check they are optional
744  */
745  M0_SET0(&cbs);
747  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_INITIALISED);
748  m0_sm_move(&op.op_sm, 0, M0_OS_LAUNCHED);
749  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_LAUNCHED);
750  m0_sm_move(&op.op_sm, 0, M0_OS_EXECUTED);
751  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_EXECUTED);
752  m0_sm_move(&op.op_sm, 0, M0_OS_STABLE);
753  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_STABLE);
754 
757 
758  m0_op_bob_fini(&op);
760 }
761 
768 unsigned long ut_test_m0_op_wait_timer(unsigned long data)
769 {
770  struct m0_op *op = (struct m0_op *)data;
771 
772  m0_sm_group_lock(&op->op_sm_group);
773  m0_sm_move(&op->op_sm, 0, M0_OS_EXECUTED);
774  m0_sm_group_unlock(&op->op_sm_group);
775 
776  return 0;
777 }
778 
781 {
782  int rc = 0; /* required */
783  struct m0_op_common cops[2];
784  struct m0_entity ent;
785  struct m0_realm realm;
787  struct m0_op *p_ops[2];
788  struct m0_timer tmr;
789  struct m0_client *instance = NULL;
790 
791  /* initialise client */
793 
794  /* initialise our fake operation */
796  ut_init_fake_op(&cops[0], &ent,
798  ut_init_fake_op(&cops[1], &ent,
800 
801  /* Test the timeout must be in the future */
802  rc = m0_op_wait(&cops[0].oc_op,
805  M0_UT_ASSERT(rc == -ETIMEDOUT);
806 
807  /* Test we time out, and don't wake up early */
808  start = m0_time_now();
809  rc = m0_op_wait(&cops[0].oc_op,
811  m0_time_from_now(1,0));
812  M0_UT_ASSERT(rc == -ETIMEDOUT);
814 
815  /*
816  * Now launch the operation and check wait succeeds.
817  * Wait for operations in the reverse order to the order they
818  * were launched in.
819  */
820  p_ops[0] = &cops[0].oc_op;
821  p_ops[1] = &cops[1].oc_op;
822  m0_op_launch(p_ops, ARRAY_SIZE(p_ops));
823  rc = m0_op_wait(&cops[1].oc_op,
825  m0_time_from_now(1,0));
826  M0_UT_ASSERT(rc == 0);
827  rc = m0_op_wait(&cops[0].oc_op,
829  m0_time_from_now(1,0));
830  M0_UT_ASSERT(rc == 0);
831 
832  /* Test repeated waits don't cause any problems */
833  rc = m0_op_wait(&cops[0].oc_op,
835  m0_time_from_now(1,0));
836  M0_UT_ASSERT(rc == 0);
837  rc = m0_op_wait(&cops[0].oc_op,
839  m0_time_from_now(1,0));
840  M0_UT_ASSERT(rc == 0);
841 
842  /* Use timers to check wait will wake up after a state transition */
845  (unsigned long)p_ops[0]);
846  M0_UT_ASSERT(rc == 0);
847 
848  M0_UT_ASSERT(p_ops[0]->op_sm.sm_state == M0_OS_LAUNCHED);
849  m0_timer_start(&tmr, m0_time_from_now(1, 0));
850  start = m0_time_now();
851  M0_UT_ASSERT(p_ops[0]->op_sm.sm_state == M0_OS_LAUNCHED);
852 
853  /* Wait for longer than the timer */
854  /*
855  * N.B. the wait time has to be exagerated so that this test doesn't
856  * unnecesarily fail in gdb
857  */
858  rc = m0_op_wait(p_ops[0],
860  m0_time_from_now(10,0));
861  M0_UT_ASSERT(rc == 0);
862 
863  /* Check we did wake up early */
866 
867  if (m0_timer_is_started(&tmr))
868  m0_timer_stop(&tmr);
869 
870  m0_timer_fini(&tmr);
871 
873 
874  /* finalise client */
876 }
877 
882 static void ut_test_m0_op_alloc(void)
883 {
884  struct m0_op *op;
885  size_t oc_size = sizeof(struct m0_op_common);
886 
887  /* base case: it works! */
888  op = (struct m0_op *)NULL;
889  m0_op_alloc(&op, oc_size);
890  M0_UT_ASSERT(op != NULL);
891  M0_UT_ASSERT(op->op_size == oc_size);
892 
893  /* avoid leaks */
894  m0_free(op);
895 }
896 
900 static void ut_test_m0_op_init(void)
901 {
902  struct m0_sm_conf conf;
903  struct m0_entity ent;
904  struct m0_realm realm;
905  struct m0_op op;
906  struct m0_op *op_p;
907  struct m0_client *instance = NULL;
908  int rc = 0; /* required */
909 
910  /* Keep gcc quiet during debug build */
911  M0_SET0(&conf);
912 
913  /* initialise client */
915 
917 
918  /* base case: no asserts triggered */
919  op_p = &op;
920  op.op_code = M0_EO_INVALID;
921  rc = m0_op_init(op_p, &m0_op_conf, &ent);
922  M0_UT_ASSERT(rc == 0);
923  M0_UT_ASSERT(op.op_sm.sm_state == M0_OS_INITIALISED);
927 
929 
930  /* finalise client */
932 }
933 
937 static void ut_test_m0_entity_fini(void)
938 {
939  struct m0_uint128 id;
940  struct m0_obj obj;
941  struct m0_entity *ent;
942  struct m0_client *instance = NULL;
943  struct m0_container uber_realm;
944 
945  /* initialise client */
948  &M0_UBER_REALM,
949  instance);
950 
951  /* Create an entity we can use */
952  id = M0_ID_APP;
953  id.u_lo++;
954  M0_SET0(&obj);
955  m0_obj_init(&obj, &uber_realm.co_realm, &id,
957  ent = &obj.ob_entity;
958 
959  /* Base case: m0_entity_fini works */
961 
962  /* Re-initialise */
963  M0_SET0(&obj);
964  m0_obj_init(&obj, &uber_realm.co_realm, &id,
966 
967  /* finalise client */
969 }
970 
974 static void ut_test_m0_obj_fini(void)
975 {
976  struct m0_uint128 id;
977  struct m0_obj obj;
978  struct m0_client *instance = NULL;
979  struct m0_container uber_realm;
980 
981  /* initialise client */
984  &M0_UBER_REALM,
985  instance);
986 
987  /* Create an entity we can use */
988  id = M0_ID_APP;
989  id.u_lo++;
990  M0_SET0(&obj);
991  m0_obj_init(&obj, &uber_realm.co_realm, &id,
993 
994  /* Base case: m0_obj_fini works */
995  m0_obj_fini(&obj);
996 
997  /* Re-initialise */
998  M0_SET0(&obj);
999  m0_obj_init(&obj, &uber_realm.co_realm, &id,
1001 
1002  /* finalise client */
1004 }
1005 
1011 static void
1013 {
1014  M0_PRE(oc != NULL);
1016 }
1017 
1023 static void ut_test_m0_op_fini(void)
1024 {
1025  int rc = 0; /* required */
1026  struct m0_entity ent;
1027  struct m0_realm realm;
1028  struct m0_op *op;
1029  struct m0_op_common *oc;
1030  struct m0_client *instance = NULL;
1031 
1032  /* initialise client */
1034 
1036 
1037  /* Allocate an operation to try and fini */
1038  op = NULL;
1039  rc = m0_op_alloc(&op, sizeof *oc);
1040  M0_UT_ASSERT(rc == 0);
1041  op->op_code = M0_EO_INVALID;
1042  rc = m0_op_init(op, &m0_op_conf, &ent);
1043  M0_UT_ASSERT(rc == 0);
1044  M0_UT_ASSERT(op->op_size >= sizeof *oc);
1045  oc = container_of(op, struct m0_op_common, oc_op);
1046  m0_op_common_bob_init(oc);
1047  m0_sm_group_init(&op->op_sm_group);
1048 
1049  /* test op_fini calls the provided callback */
1052  m0_op_fini(op);
1054  M0_UT_ASSERT(op->op_sm.sm_state == M0_OS_UNINITIALISED);
1055 
1056  /* fini */
1057  m0_op_free(op);
1058  m0_entity_fini(&ent);
1059 
1061 }
1062 
1067 static void ut_test_m0_op_free(void)
1068 {
1069  struct m0_op *op;
1070  struct m0_op_common *oc;
1071  struct m0_op_obj *oo;
1072 
1073  /* base case: m0_op_common */
1074  op = m0_alloc(sizeof *oc);
1075  op->op_size = sizeof *oc;
1076  m0_op_free(op);
1077 
1078  /* base case: m0_op_common */
1079  oc = m0_alloc(sizeof *oc);
1080  oc->oc_op.op_size = sizeof *oc;
1081  m0_op_free(&oc->oc_op);
1082 
1083  /* base case: m0_op_obj */
1084  oo = m0_alloc(sizeof *oo);
1085  oo->oo_oc.oc_op.op_size = sizeof *oo;
1086  m0_op_free(&oo->oo_oc.oc_op);
1087 }
1088 
1092 static void ut_test_m0_op_setup(void)
1093 {
1094  m0_time_t linger;
1095  struct m0_op op;
1096  struct m0_op_ops cbs;
1097  struct m0_client *instance = NULL;
1098 
1099  /* initialise client */
1101 
1102  M0_SET0(&op);
1103  op.op_sm.sm_state = M0_OS_INITIALISED;
1104 
1105  /* Base case: everything works */
1106  m0_op_setup(&op, NULL, 0);
1107 
1108  /* test ops and linger get set, overwriting manual versions */
1109  op.op_cbs = (void *)0xDEADBEEF;
1110  op.op_linger = 0x42;
1111  linger = m0_time_now() + 4ULL * M0_TIME_ONE_SECOND;
1112  m0_op_setup(&op, &cbs, linger);
1113  M0_UT_ASSERT(op.op_cbs == &cbs);
1114  M0_UT_ASSERT(op.op_linger == linger);
1115 
1116  /* finalise client */
1118 }
1119 
1121 static void ut_test_m0_op_kick(void)
1122 {
1123  int rc;
1124  struct m0_op op;
1125  struct m0_op *op_p;
1126  struct m0_entity ent;
1127  struct m0_realm realm;
1128  struct m0_client *instance = NULL;
1129 
1130  /* initialise client */
1132 
1134 
1135  op_p = &op;
1136  op.op_code = M0_EO_INVALID;
1137  rc = m0_op_init(op_p, &m0_op_conf, &ent);
1138  M0_UT_ASSERT(rc == 0);
1139 
1140  /* Base case - kick works */
1141  m0_op_kick(op_p);
1142 
1143  m0_entity_fini(&ent);
1145 }
1146 
1147 #if 0 /* The op state isn't supported yet. */
1148 static void ut_test_m0_op_transaction_committed(void)
1149 {
1150  struct m0_op_common oc;
1151  struct m0_client *instance = NULL;
1152  struct m0_entity ent;
1153  struct m0_realm realm;
1154  struct m0_sm_group *grp;
1155 
1156  /* init */
1160 
1161  /* Test m0_op_transaction_commited. */
1162  grp = &oc.oc_op.op_sm_group;
1164  oc.oc_op.op_sm.sm_state = M0_OS_EXECUTED;
1165  m0_op_transaction_committed(&oc);
1167 
1168  /* finalise client */
1169  m0_entity_fini(&ent);
1171 }
1172 
1173 static void ut_test_m0_op_transaction_failed(void)
1174 {
1175  struct m0_op_common oc;
1176  struct m0_client *instance = NULL;
1177  struct m0_entity ent;
1178  struct m0_realm realm;
1179  struct m0_sm_group *grp;
1180 
1181  /* init */
1185 
1186  /* Test m0_op_transaction_commited. */
1187  grp = &oc.oc_op.op_sm_group;
1189  oc.oc_op.op_sm.sm_state = M0_OS_EXECUTED;
1190  m0_op_transaction_failed(&oc);
1192 
1193  /* finalise client */
1194  m0_entity_fini(&ent);
1196 }
1197 #endif
1198 
1199 #ifndef __KERNEL__
1200 int rand(void);
1202 
1203 
1204 M0_INTERNAL void
1206 {
1207 #ifdef CLVIS_UT_ENABLE_SHUFFLE
1208 
1209  int i;
1210  int num_tests;
1211  struct m0_ut **new_order;
1212  struct m0_ut *real_order = (struct m0_ut *)suite->ts_tests;
1213 
1214  /* Count the tests */
1215  num_tests = 0;
1216  while (suite->ts_tests[num_tests].t_name != NULL)
1217  num_tests++;
1218 
1219  M0_ALLOC_ARR(new_order, num_tests + 1);
1220  M0_ASSERT(new_order != NULL);
1221 
1222  /* Produce a new order */
1223  for (i = 0; i < num_tests; i++) {
1224  int index = rand() % num_tests;
1225 
1226  while (new_order[index] != NULL)
1227  index = (index + 1) % num_tests;
1228 
1229  M0_ALLOC_PTR(new_order[index]);
1230  M0_ASSERT(new_order[index] != NULL);
1231 
1232  *new_order[index] = suite->ts_tests[i];
1233  }
1234 
1235  /* Re-write the test order */
1236  for (i = 0; i < num_tests; i++){
1237  real_order[i] = *new_order[i];
1238  m0_free(new_order[i]);
1239  }
1240  m0_free(new_order);
1241 #endif
1242 }
1243 #endif
1244 
1245 M0_INTERNAL int ut_init(void)
1246 {
1247 
1248 #ifndef __KERNEL__
1250 #endif
1251 
1252  m0_fi_enable("m0__obj_pool_version_get", "fake_pool_version");
1253 
1254  return 0;
1255 }
1256 
1257 M0_INTERNAL int ut_fini(void)
1258 {
1259  m0_fi_disable("m0__obj_pool_version_get", "fake_pool_version");
1260 
1261  return 0;
1262 }
1263 
1264 struct m0_ut_suite ut_suite = {
1265  .ts_name = "client-ut",
1266  .ts_init = ut_init,
1267  .ts_fini = ut_fini,
1268  .ts_tests = {
1269 
1270  /* Initialising client. */
1271  { "m0_client_init", &ut_test_m0_client_init},
1272  { "m0_client_fini", &ut_test_m0_client_fini},
1273  { "client op state machine",
1274  &ut_test_op_sm},
1275 
1276  /* Operations. */
1277  { "m0_op_alloc",
1279  { "m0_op_init",
1281  { "m0_op_launch_one",
1283  { "m0_op_launch",
1285  { "m0_op_fini",
1287  { "m0_op_free",
1289 
1290  /* Entities */
1291  { "m0_entity_init",
1293  { "m0_obj_init",
1295  { "m0_entity_fini",
1297  { "m0_obj_fini",
1299  { "entity_invariant_locked",
1301  { "m0_op_setup",
1303  { "m0_op_wait",
1305  { "m0_op_kick",
1307 #if 0
1308  { "m0_op_transaction_committed",
1309  &ut_test_m0_op_transaction_committed},
1310  { "m0_op_transaction_failed",
1311  &ut_test_m0_op_transaction_failed},
1312 #endif
1313  { NULL, NULL }
1314  }
1315 };
1316 
1317 #undef M0_TRACE_SUBSYSTEM
1318 
1319 /*
1320  * Local variables:
1321  * c-indentation-style: "K&R"
1322  * c-basic-offset: 8
1323  * tab-width: 8
1324  * fill-column: 80
1325  * scroll-step: 1
1326  * End:
1327  */
M0_INTERNAL int m0_uint128_cmp(const struct m0_uint128 *u0, const struct m0_uint128 *u1)
Definition: misc.c:45
uint64_t id
Definition: cob.h:2380
#define M0_PRE(cond)
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
#define INIT(instance)
Definition: client.h:58
void m0_entity_fini(struct m0_entity *entity)
Definition: client.c:438
static uint32_t ut_launch_cb_fail_count
Definition: client.c:46
M0_INTERNAL int ut_fini(void)
Definition: client.c:1257
Definition: client.h:788
struct m0_tl po_vers
Definition: pool.h:84
static void ut_init_fake_op(struct m0_op_common *cop, struct m0_entity *ent, void(*cb)(struct m0_op_common *oc))
Definition: client.c:531
#define NULL
Definition: misc.h:38
struct m0_config default_config
Definition: client.c:58
M0_INTERNAL void m0_clink_init(struct m0_clink *link, m0_chan_cb_t cb)
Definition: chan.c:201
M0_INTERNAL void m0_clink_del(struct m0_clink *link)
Definition: chan.c:267
static uint32_t ut_launch_cb_pass_count
Definition: client.c:45
Definition: sm.h:350
void m0_op_fini(struct m0_op *op)
Definition: client.c:847
static struct m0_sm_group * grp
Definition: bytecount.c:38
struct m0_pool_version * pv
Definition: dir.c:629
uint64_t m0_time_t
Definition: time.h:37
void(* oop_executed)(struct m0_op *op)
Definition: client.h:909
const char * t_name
Definition: ut.h:66
static void ut_test_m0_client_init(void)
Definition: client.c:211
static void ut_launch_cb_fail(struct m0_op_common *oc)
Definition: client.c:519
static struct m0_realm uber_realm
Definition: m0hsm.c:49
void m0_client_fini(struct m0_client *m0c, bool fini_m0)
Definition: client_init.c:1711
struct m0_bufvec data
Definition: di.c:40
static void ut_test_m0_op_launch(void)
Definition: client.c:578
struct m0_op oc_op
M0_INTERNAL int m0_op_init(struct m0_op *op, const struct m0_sm_conf *conf, struct m0_entity *entity)
Definition: client.c:806
uint64_t m0_client_layout_id(const struct m0_client *instance)
Definition: obj.c:859
Definition: conf.py:1
M0_INTERNAL void m0_op_launch_one(struct m0_op *op)
Definition: client.c:686
#define M0_BITS(...)
Definition: misc.h:236
static void ut_test_m0_op_launch_one(void)
Definition: client.c:554
M0_INTERNAL int m0_timer_init(struct m0_timer *timer, enum m0_timer_type type, struct m0_timer_locality *loc, m0_timer_callback_t callback, unsigned long data)
Definition: timer.c:39
#define container_of(ptr, type, member)
Definition: misc.h:33
#define M0_SET0(obj)
Definition: misc.h:64
while(rc==0)
Definition: ut.h:77
const struct m0_uint128 M0_UBER_REALM
Definition: client.c:85
Definition: timer.h:39
struct m0_pool * pv_pool
Definition: pool.h:128
M0_INTERNAL int ut_m0_client_init(struct m0_client **instance)
Definition: client.c:265
static uint32_t ut_m0_op_fini_cb_count
Definition: client.c:49
M0_INTERNAL void m0_sm_group_fini(struct m0_sm_group *grp)
Definition: sm.c:65
static struct foo * obj
Definition: tlist.c:302
static void ut_test_m0_op_kick(void)
Definition: client.c:1121
M0_INTERNAL int m0_pool_init(struct m0_pool *pool, const struct m0_fid *id, enum m0_pver_policy_code pver_policy)
Definition: pool.c:307
const struct m0_uint128 M0_ID_APP
Definition: client.c:92
static void ut_test_m0_client_init_floors(struct m0_client *instance, int limit, bool fail)
Definition: client.c:136
int32_t m0_op_wait(struct m0_op *op, uint64_t bits, m0_time_t to)
Definition: client.c:739
op
Definition: libdemo.c:64
static void ut_test_m0_entity_init(void)
Definition: client.c:434
M0_INTERNAL void m0_timer_fini(struct m0_timer *timer)
Definition: timer.c:65
M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:96
int i
Definition: dir.c:1033
size_t op_size
Definition: client.h:664
#define M0_SET_ARR0(arr)
Definition: misc.h:72
const char * mc_ha_addr
Definition: client.h:935
Definition: client.h:641
M0_INTERNAL void ut_realm_entity_setup(struct m0_realm *realm, struct m0_entity *ent, struct m0_client *cinst)
Definition: client.c:60
static void ut_test_m0_obj_fini(void)
Definition: client.c:974
struct m0_ut ts_tests[M0_UT_SUITE_TESTS_MAX]
Definition: ut.h:119
static bool ut_test_floor_tick_cb(struct m0_clink *cl)
Definition: client.c:80
static void ut_test_m0_op_alloc(void)
Definition: client.c:882
struct m0_sm op_sm
Definition: client.h:656
#define M0_FID_TINIT(type, container, key)
Definition: fid.h:90
struct m0_ut_suite ut_suite
Definition: client.c:1201
M0_INTERNAL void m0_fi_disable(const char *fp_func, const char *fp_tag)
Definition: finject.c:485
void(* oop_stable)(struct m0_op *op)
Definition: client.h:911
M0_INTERNAL void m0_timer_stop(struct m0_timer *timer)
Definition: timer.c:86
static void m0_fi_enable(const char *func, const char *tag)
Definition: finject.h:276
#define M0_ASSERT(cond)
M0_INTERNAL void ut_m0_client_fini(struct m0_client **instance)
Definition: client.c:354
static void ut_test_m0_op_init(void)
Definition: client.c:900
M0_INTERNAL void m0_sm_group_init(struct m0_sm_group *grp)
Definition: sm.c:53
M0_INTERNAL void m0_timer_start(struct m0_timer *timer, m0_time_t expire)
Definition: timer.c:75
#define M0_DEFAULT_EP
Definition: client.h:33
m0_time_t m0_time_now(void)
Definition: time.c:134
void m0_obj_fini(struct m0_obj *obj)
Definition: client.c:467
int rand(void)
void m0_op_launch(struct m0_op **op, uint32_t nr)
Definition: client.c:725
void ut_test_m0_op_wait(void)
Definition: client.c:780
void * m0_alloc(size_t size)
Definition: memory.c:126
M0_INTERNAL void ut_shuffle_test_order(struct m0_ut_suite *suite)
Definition: client.c:1205
M0_INTERNAL int ut_init(void)
Definition: client.c:1245
#define M0_DEFAULT_HA_ADDR
Definition: client.h:34
int32_t sm_rc
Definition: sm.h:336
void(* oc_cb_fini)(struct m0_op_common *oc)
M0_INTERNAL bool m0_timer_is_started(const struct m0_timer *timer)
Definition: timer.c:94
static struct m0_clink clink[RDWR_REQUEST_MAX]
static int ut_test_op_sm_callme_counter
Definition: client.c:52
void(* oop_failed)(struct m0_op *op)
Definition: client.h:910
struct m0_op_common oo_oc
static void ut_test_op_sm(void)
Definition: client.c:671
static struct m0_pool pool
Definition: iter_ut.c:58
static int ut_test_initlift_gnf_counter
Definition: client.c:55
static struct m0_client cinst
Definition: sync.c:84
const char * ts_name
Definition: ut.h:99
static uint8_t fail[DATA_UNIT_COUNT_MAX+PARITY_UNIT_COUNT_MAX]
M0_INTERNAL bool entity_invariant_locked(const struct m0_entity *ent)
Definition: client.c:320
static void ut_test_op_sm_callme(struct m0_op *op)
Definition: client.c:625
struct m0_sm_group en_sm_group
Definition: client.h:734
uint32_t mc_max_rpc_msg_size
Definition: client.h:949
struct m0_sm_group op_sm_group
Definition: client.h:654
const char * mc_local_addr
Definition: client.h:933
static void ut_test_m0_entity_fini(void)
Definition: client.c:937
Definition: fid.h:38
M0_INTERNAL void m0_sm_init(struct m0_sm *mach, const struct m0_sm_conf *conf, uint32_t state, struct m0_sm_group *grp)
Definition: sm.c:313
#define DUMMY_PTR
Definition: client.h:66
static void ut_test_op_sm_cbs_helper(struct m0_op_ops *cbs, int executed, int stable, int failed)
Definition: client.c:647
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
M0_INTERNAL void m0_clink_add(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:228
static struct m0_realm realm
Definition: sync.c:87
struct m0_entity * op_entity
Definition: client.h:660
static void ut_test_m0_op_setup(void)
Definition: client.c:1092
static void ut_m0_op_fini_cb(struct m0_op_common *oc)
Definition: client.c:1012
m0_time_t m0_time_from_now(uint64_t secs, long ns)
Definition: time.c:96
uint32_t mc_tm_recv_queue_min_len
Definition: client.h:944
Definition: sm.h:301
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
M0_INTERNAL void m0_sm_move(struct m0_sm *mach, int32_t rc, int state)
Definition: sm.c:485
M0_INTERNAL void m0_clink_fini(struct m0_clink *link)
Definition: chan.c:208
static void ut_test_m0_client_init_floor_tick(struct m0_client *instance, int start_state, int stop_state)
Definition: client.c:94
void m0_obj_init(struct m0_obj *obj, struct m0_realm *parent, const struct m0_uint128 *id, uint64_t layout_id)
Definition: client.c:403
static struct m0 instance
Definition: main.c:78
#define M0_DEFAULT_PROFILE
Definition: client.h:35
M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:83
static void m0_fi_enable_once(const char *func, const char *tag)
Definition: finject.h:301
M0_INTERNAL int m0_op_alloc(struct m0_op **op, size_t op_size)
Definition: client.c:779
static void ut_test_entity_invariant_locked(void)
Definition: client.c:390
void m0_container_init(struct m0_container *con, struct m0_realm *parent, const struct m0_uint128 *id, struct m0_client *instance)
Definition: realm.c:31
struct m0_client * re_instance
Definition: client.h:873
static void ut_test_m0_op_fini(void)
Definition: client.c:1023
const char * mc_profile
Definition: client.h:938
void m0_op_kick(struct m0_op *op)
Definition: client.c:924
static void ut_test_m0_op_free(void)
Definition: client.c:1067
Definition: pool.h:80
void m0_op_free(struct m0_op *op)
Definition: client.c:885
struct m0_dirent * ent
Definition: dir.c:1029
void(* oc_cb_launch)(struct m0_op_common *oc)
uint64_t u_lo
Definition: types.h:37
M0_INTERNAL void ut_test_m0_client_fini(void)
Definition: client.c:330
unsigned long ut_test_m0_op_wait_timer(unsigned long data)
Definition: client.c:768
void m0_free(void *data)
Definition: memory.c:146
static void initlift_fail(int rc, struct m0_client *m0c)
Definition: client_init.c:388
uint32_t sm_state
Definition: sm.h:307
static void ut_test_op_sm_dont_callme(struct m0_op *op)
Definition: client.c:634
static void ut_launch_cb_pass(struct m0_op_common *oc)
Definition: client.c:503
int32_t rc
Definition: trigger_fop.h:47
M0_INTERNAL void m0_entity_init(struct m0_entity *entity, struct m0_realm *parent, const struct m0_uint128 *id, const enum m0_entity_type type)
Definition: client.c:371
#define ARRAY_SIZE(a)
Definition: misc.h:45
Definition: ut.h:64
enum m0_entity_type en_type
Definition: client.h:706
#define M0_UT_ASSERT(a)
Definition: ut.h:46
struct m0_sm_conf m0_op_conf
Definition: client.c:145
void m0_op_setup(struct m0_op *op, const struct m0_op_ops *cbs, m0_time_t linger)
Definition: client.c:908
static void ut_test_m0_obj_init(void)
Definition: client.c:465
M0_INTERNAL bool m0_sm_invariant(const struct m0_sm *mach)
Definition: sm.c:267