Motr  M0
finject.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2011-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 "lib/ub.h"
24 #include "ut/ut.h"
25 #include "lib/finject.h"
26 
27 
28 static const char test_tag[] = "test_fp";
29 
30 /*
31  * Use this pythoc script to caclulate P_ERROR value if you see
32  * test_enable_random() failure:
33  *
34  * @verbatim
35  * #!/usr/bin/env python
36  *
37  * import math
38  *
39  * def nCr(n,r):
40  * f = math.factorial
41  * return f(n) / (f(r) * f(n - r))
42  *
43  * P = 40
44  * P_ERROR = 30
45  * TEST_COUNT = 100
46  * p = P / 100.
47  * total = 0.
48  * for r in range(P - P_ERROR, P + P_ERROR):
49  * total += nCr(TEST_COUNT, r) * pow(p, r) * pow(1 - p, TEST_COUNT - r)
50  * print 1.0 - total
51  * @endverbatim
52  *
53  * It prints probability of test_enable_random() failure.
54  */
55 enum {
56  STATE_DATA_MAGIC = 0xfa57ccd0,
57  TEST_COUNT = 100,
58  N = 7,
59  M = 4,
60  P = 40,
61  P_ERROR = 30,
62 };
63 
64 typedef bool (*target_func_t)(void);
65 
67 {
68  return M0_FI_ENABLED(test_tag);
69 }
70 
71 static bool target_func_fpoint_types(void)
72 {
73  return M0_FI_ENABLED(test_tag);
74 }
75 
76 struct state_data {
77  uint32_t magic;
78  uint32_t n;
79 };
80 
81 /* Returns true and false alternately */
82 static bool state_func(void *data)
83 {
84  struct state_data *d = data;
85 
86  M0_PRE(data != NULL && d->magic == STATE_DATA_MAGIC &&
87  (d->n == 0 || d->n == 1));
88 
89  d->n = d->n ^ 1;
90 
91  return d->n;
92 }
93 
94 static void disable_fp(const char *func_name, const char *tag_name,
95  target_func_t target_func)
96 {
97  /* disable FP and check that it's really OFF */
98  m0_fi_disable(func_name, tag_name);
99  M0_UT_ASSERT(!target_func());
100 }
101 
102 static void test_enable_always(const char *func_name)
103 {
104  int i;
105 
106  /* check that FP is always ON after simple "enable" */
107  m0_fi_enable(func_name, test_tag);
108  for (i = 1; i <= TEST_COUNT; ++i)
110 
112 }
113 
114 static void test_enable_once(const char *func_name)
115 {
116  int i;
117 
118  /* check that FP is ON only once after "enable_once" */
119  m0_fi_enable_once(func_name, test_tag);
120  for (i = 1; i <= TEST_COUNT; ++i)
121  if (i == 1) /* first check, FP should be ON */
123  else /* subsequent checks, FP should be OFF */
125 
127 }
128 
129 static void test_enable_each_nth_time(const char *func_name)
130 {
131  int i;
132 
133  /* check that FP is ON each N-th time after "enable_each_nth_time" */
135  for (i = 1; i <= TEST_COUNT; ++i)
136  if (i % N == 0) /* N-th check, FP should be ON */
138  else /* all other checks, FP should be OFF */
140 
142 }
143 
144 static void test_enable_off_n_on_m(const char *func_name)
145 {
146  int i;
147 
148  /*
149  * check that FP is OFF N times and ON M times after "enable_off_n_on_m"
150  */
151  m0_fi_enable_off_n_on_m(func_name, test_tag, N, M);
152  for (i = 0; i < TEST_COUNT; ++i) {
153  uint32_t check_num = i % (N + M);
154 
155  if (check_num < N) /* FP should be OFF */
157  else /* FP should be ON */
159  }
160 
162 }
163 
164 static void test_enable_random(const char *func_name)
165 {
166  int i;
167  uint32_t on_count;
168 
169  /*
170  * check that FP is ON approximately P percents of times after
171  * "enable_random" including P_ERROR error
172  */
173  m0_fi_enable_random(func_name, test_tag, P);
174  for (i = 0, on_count = 0; i < TEST_COUNT; ++i)
176  on_count++;
177  M0_UT_ASSERT(on_count >= P - P_ERROR && on_count <= P + P_ERROR);
178 
180 }
181 
182 static void test_enable_func(const char *func_name)
183 {
184  int i;
185 
186  struct state_data sdata = {
188  .n = 0,
189  };
190 
191  /*
192  * check that FP's ON/OFF state is really controlled by our custom func
193  */
194  m0_fi_enable_func(func_name, test_tag, state_func, &sdata);
195  for (i = 0; i < TEST_COUNT; ++i)
196  if (i % 2 == 0) /* when i is even FP should be ON */
198  else /* when i is odd FP should be OFF */
200 
202 }
203 
204 static void test_fpoint_types(void)
205 {
206  const char *func_name = "target_func_fpoint_types";
207 
208  /* register FP on first run and check that it disabled initially */
210 
211  test_enable_always(func_name);
212  test_enable_once(func_name);
213  test_enable_each_nth_time(func_name);
214  test_enable_off_n_on_m(func_name);
215  test_enable_random(func_name);
216  test_enable_func(func_name);
217 }
218 
219 static void test_delayed_registration(void)
220 {
221  /* enable FP before it's registered */
222  m0_fi_enable("target_func_delayed_registration", test_tag);
223 
224  /* check that FP is enabled on first run */
226 
227  disable_fp("target_func_delayed_registration", test_tag,
229 }
230 
231 static void test_enable_disable(void)
232 {
233  int i;
234 
235  /* manually create fault point */
236  static struct m0_fi_fault_point fp = {
237  .fp_state = NULL,
238  .fp_module = "UNKNOWN",
239  .fp_file = __FILE__,
240  .fp_line_num = __LINE__,
241  .fp_func = __func__,
242  .fp_tag = test_tag,
243  };
244 
245  enum {
246  TEST_COUNT = 10,
247  };
248 
249  m0_fi_register(&fp);
250  M0_UT_ASSERT(fp.fp_state != NULL);
251 
252  /* check that it's disabled initially */
253  M0_UT_ASSERT(!m0_fi_enabled(fp.fp_state));
254 
255  /* check that FP is really ON after m0_fi_enable() */
256  m0_fi_enable(__func__, test_tag);
257  M0_UT_ASSERT(m0_fi_enabled(fp.fp_state));
258 
259  /* check that FP is really OFF after m0_fi_disable() */
260  m0_fi_disable(__func__, test_tag);
261  M0_UT_ASSERT(!m0_fi_enabled(fp.fp_state));
262 
263  /*
264  * check that there is no harm to enable FP several times in a row
265  * without disabling it
266  */
267  for (i = 0; i < TEST_COUNT; ++i) {
268  m0_fi_enable(__func__, test_tag);
269  M0_UT_ASSERT(m0_fi_enabled(fp.fp_state));
270  }
271 
272  /*
273  * check that there is no harm to disable FP several times in a row
274  * without enabling it
275  */
276  for (i = 0; i < TEST_COUNT; ++i) {
277  m0_fi_disable(__func__, test_tag);
278  M0_UT_ASSERT(!m0_fi_enabled(fp.fp_state));
279  }
280 }
281 
282 void test_finject(void)
283 {
287 }
288 M0_EXPORTED(test_finject);
289 
290 /*
291  * Local variables:
292  * c-indentation-style: "K&R"
293  * c-basic-offset: 8
294  * tab-width: 8
295  * fill-column: 80
296  * scroll-step: 1
297  * End:
298  */
#define M0_PRE(cond)
static void test_enable_once(const char *func_name)
Definition: finject.c:114
#define NULL
Definition: misc.h:38
static void test_enable_disable(void)
Definition: finject.c:231
struct m0_bufvec data
Definition: di.c:40
static void m0_fi_enable_random(const char *func, const char *tag, uint32_t p)
Definition: finject.h:321
void m0_fi_register(struct m0_fi_fault_point *fp)
Definition: finject.c:423
int i
Definition: dir.c:1033
static void test_fpoint_types(void)
Definition: finject.c:204
M0_INTERNAL void m0_fi_disable(const char *fp_func, const char *fp_tag)
Definition: finject.c:485
static void m0_fi_enable_each_nth_time(const char *func, const char *tag, uint32_t n)
Definition: finject.h:366
uint32_t n
Definition: finject.c:78
static void m0_fi_enable(const char *func, const char *tag)
Definition: finject.h:276
static void m0_fi_enable_func(const char *func, const char *tag, m0_fi_fpoint_state_func_t trigger_func, void *data)
Definition: finject.h:387
static bool target_func_fpoint_types(void)
Definition: finject.c:71
static const char test_tag[]
Definition: finject.c:28
bool(* target_func_t)(void)
Definition: finject.c:64
static void test_enable_always(const char *func_name)
Definition: finject.c:102
static void m0_fi_enable_off_n_on_m(const char *func, const char *tag, uint32_t n, uint32_t m)
Definition: finject.h:346
Definition: finject.c:58
static void disable_fp(const char *func_name, const char *tag_name, target_func_t target_func)
Definition: finject.c:94
uint32_t magic
Definition: finject.c:77
static bool state_func(void *data)
Definition: finject.c:82
static void test_enable_each_nth_time(const char *func_name)
Definition: finject.c:129
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
static void test_enable_random(const char *func_name)
Definition: finject.c:164
bool m0_fi_enabled(struct m0_fi_fpoint_state *fps)
Definition: finject.c:445
static void m0_fi_enable_once(const char *func, const char *tag)
Definition: finject.h:301
Definition: finject.c:59
Definition: finject.c:60
void test_finject(void)
Definition: finject.c:282
Definition: rcv_session.c:58
static void test_enable_func(const char *func_name)
Definition: finject.c:182
#define M0_UT_ASSERT(a)
Definition: ut.h:46
static void test_delayed_registration(void)
Definition: finject.c:219
static bool target_func_delayed_registration(void)
Definition: finject.c:66
static void test_enable_off_n_on_m(const char *func_name)
Definition: finject.c:144