pacemaker 2.1.7-2.1.7
Scalable High-Availability cluster resource manager
Loading...
Searching...
No Matches
mock.c
Go to the documentation of this file.
1/*
2 * Copyright 2021-2023 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10#include <crm_internal.h>
11
12#include <errno.h>
13#include <pwd.h>
14#include <stdarg.h>
15#include <stdbool.h>
16#include <stddef.h>
17#include <stdint.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <setjmp.h>
22#include <sys/types.h>
23#include <sys/utsname.h>
24#include <unistd.h>
25#include <grp.h>
26
27#include <cmocka.h>
28#include "mock_private.h"
29
30/* This file is only used when running "make check". It is built into
31 * libcrmcommon_test.a, not into libcrmcommon.so. It is used to support
32 * constructing mock versions of library functions for unit testing.
33 *
34 * HOW TO ADD A MOCKED FUNCTION:
35 *
36 * - In this file, declare a bool pcmk__mock_X variable, and define a __wrap_X
37 * function with the same prototype as the actual function that performs the
38 * desired behavior if pcmk__mock_X is true and calls __real_X otherwise.
39 * You can use cmocka's mock_type() and mock_ptr_type() to pass extra
40 * information to the mocked function (see existing examples for details).
41 *
42 * - In mock_private.h, add declarations for extern bool pcmk__mock_X and the
43 * __real_X and __wrap_X function prototypes.
44 *
45 * - In mk/tap.mk, add the function name to the WRAPPED variable.
46 *
47 * HOW TO USE A MOCKED FUNCTION:
48 *
49 * - #include "mock_private.h" in your test file.
50 *
51 * - Write your test cases using pcmk__mock_X and cmocka's will_return() as
52 * needed per the comments for the mocked function below. See existing test
53 * cases for examples.
54 */
55
56// LCOV_EXCL_START
57/* calloc()
58 *
59 * If pcmk__mock_calloc is set to true, later calls to calloc() will return
60 * NULL and must be preceded by:
61 *
62 * expect_*(__wrap_calloc, nmemb[, ...]);
63 * expect_*(__wrap_calloc, size[, ...]);
64 *
65 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
66 */
67
68bool pcmk__mock_calloc = false;
69
70void *
71__wrap_calloc(size_t nmemb, size_t size)
72{
73 if (!pcmk__mock_calloc) {
74 return __real_calloc(nmemb, size);
75 }
76 check_expected(nmemb);
77 check_expected(size);
78 return NULL;
79}
80
81
82/* getenv()
83 *
84 * If pcmk__mock_getenv is set to true, later calls to getenv() must be preceded
85 * by:
86 *
87 * expect_*(__wrap_getenv, name[, ...]);
88 * will_return(__wrap_getenv, return_value);
89 *
90 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
91 */
92
93bool pcmk__mock_getenv = false;
94
95char *
96__wrap_getenv(const char *name)
97{
98 if (!pcmk__mock_getenv) {
99 return __real_getenv(name);
100 }
101 check_expected_ptr(name);
102 return mock_ptr_type(char *);
103}
104
105
106/* setenv()
107 *
108 * If pcmk__mock_setenv is set to true, later calls to setenv() must be preceded
109 * by:
110 *
111 * expect_*(__wrap_setenv, name[, ...]);
112 * expect_*(__wrap_setenv, value[, ...]);
113 * expect_*(__wrap_setenv, overwrite[, ...]);
114 * will_return(__wrap_setenv, errno_to_set);
115 *
116 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
117 *
118 * The mocked function will return 0 if errno_to_set is 0, and -1 otherwise.
119 */
120bool pcmk__mock_setenv = false;
121
122int
123__wrap_setenv(const char *name, const char *value, int overwrite)
124{
125 if (!pcmk__mock_setenv) {
126 return __real_setenv(name, value, overwrite);
127 }
128 check_expected_ptr(name);
129 check_expected_ptr(value);
130 check_expected(overwrite);
131 errno = mock_type(int);
132 return (errno == 0)? 0 : -1;
133}
134
135
136/* unsetenv()
137 *
138 * If pcmk__mock_unsetenv is set to true, later calls to unsetenv() must be
139 * preceded by:
140 *
141 * expect_*(__wrap_unsetenv, name[, ...]);
142 * will_return(__wrap_setenv, errno_to_set);
143 *
144 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
145 *
146 * The mocked function will return 0 if errno_to_set is 0, and -1 otherwise.
147 */
149
150int
152{
153 if (!pcmk__mock_unsetenv) {
154 return __real_unsetenv(name);
155 }
156 check_expected_ptr(name);
157 errno = mock_type(int);
158 return (errno == 0)? 0 : -1;
159}
160
161
162/* getpid()
163 *
164 * If pcmk__mock_getpid is set to true, later calls to getpid() must be preceded
165 * by:
166 *
167 * will_return(__wrap_getpid, return_value);
168 */
169
170bool pcmk__mock_getpid = false;
171
172pid_t
174{
175 return pcmk__mock_getpid? mock_type(pid_t) : __real_getpid();
176}
177
178
179/* setgrent(), getgrent() and endgrent()
180 *
181 * If pcmk__mock_grent is set to true, getgrent() will behave as if the only
182 * groups on the system are:
183 *
184 * - grp0 (user0, user1)
185 * - grp1 (user1)
186 * - grp2 (user2, user1)
187 */
188
189bool pcmk__mock_grent = false;
190
191// Index of group that will be returned next from getgrent()
192static int group_idx = 0;
193
194// Data used for testing
195static const char* grp0_members[] = {
196 "user0", "user1", NULL
197};
198
199static const char* grp1_members[] = {
200 "user1", NULL
201};
202
203static const char* grp2_members[] = {
204 "user2", "user1", NULL
205};
206
207/* An array of "groups" (a struct from grp.h)
208 *
209 * The members of the groups are initalized here to some testing data, casting
210 * away the consts to make the compiler happy and simplify initialization. We
211 * never actually change these variables during the test!
212 *
213 * string literal = const char* (cannot be changed b/c ? )
214 * vs. char* (it's getting casted to this)
215 */
216static const int NUM_GROUPS = 3;
217static struct group groups[] = {
218 {(char*)"grp0", (char*)"", 0, (char**)grp0_members},
219 {(char*)"grp1", (char*)"", 1, (char**)grp1_members},
220 {(char*)"grp2", (char*)"", 2, (char**)grp2_members},
221};
222
223// This function resets the group_idx to 0.
224void
226 if (pcmk__mock_grent) {
227 group_idx = 0;
228 } else {
230 }
231}
232
233/* This function returns the next group entry in the list of groups, or
234 * NULL if there aren't any left.
235 * group_idx is a global variable which keeps track of where you are in the list
236 */
237struct group *
239 if (pcmk__mock_grent) {
240 if (group_idx >= NUM_GROUPS) {
241 return NULL;
242 }
243 return &groups[group_idx++];
244 } else {
245 return __real_getgrent();
246 }
247}
248
249void
251 if (!pcmk__mock_grent) {
253 }
254}
255
256
257/* fopen()
258 *
259 * If pcmk__mock_fopen is set to true, later calls to fopen() must be
260 * preceded by:
261 *
262 * expect_*(__wrap_fopen, pathname[, ...]);
263 * expect_*(__wrap_fopen, mode[, ...]);
264 * will_return(__wrap_fopen, errno_to_set);
265 *
266 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
267 *
268 * This has two mocked functions, since fopen() is sometimes actually fopen64().
269 */
270
271bool pcmk__mock_fopen = false;
272
273FILE *
274__wrap_fopen(const char *pathname, const char *mode)
275{
276 if (pcmk__mock_fopen) {
277 check_expected_ptr(pathname);
278 check_expected_ptr(mode);
279 errno = mock_type(int);
280
281 if (errno != 0) {
282 return NULL;
283 } else {
284 return __real_fopen(pathname, mode);
285 }
286
287 } else {
288 return __real_fopen(pathname, mode);
289 }
290}
291
292#ifdef HAVE_FOPEN64
293FILE *
294__wrap_fopen64(const char *pathname, const char *mode)
295{
296 if (pcmk__mock_fopen) {
297 check_expected_ptr(pathname);
298 check_expected_ptr(mode);
299 errno = mock_type(int);
300
301 if (errno != 0) {
302 return NULL;
303 } else {
304 return __real_fopen64(pathname, mode);
305 }
306
307 } else {
308 return __real_fopen64(pathname, mode);
309 }
310}
311#endif
312
313/* getpwnam_r()
314 *
315 * If pcmk__mock_getpwnam_r is set to true, later calls to getpwnam_r() must be
316 * preceded by:
317 *
318 * expect_*(__wrap_getpwnam_r, name[, ...]);
319 * expect_*(__wrap_getpwnam_r, pwd[, ...]);
320 * expect_*(__wrap_getpwnam_r, buf[, ...]);
321 * expect_*(__wrap_getpwnam_r, buflen[, ...]);
322 * expect_*(__wrap_getpwnam_r, result[, ...]);
323 * will_return(__wrap_getpwnam_r, return_value);
324 * will_return(__wrap_getpwnam_r, ptr_to_result_struct);
325 *
326 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
327 */
328
330
331int
332__wrap_getpwnam_r(const char *name, struct passwd *pwd, char *buf,
333 size_t buflen, struct passwd **result)
334{
336 int retval = mock_type(int);
337
338 check_expected_ptr(name);
339 check_expected_ptr(pwd);
340 check_expected_ptr(buf);
341 check_expected(buflen);
342 check_expected_ptr(result);
343 *result = mock_ptr_type(struct passwd *);
344 return retval;
345
346 } else {
347 return __real_getpwnam_r(name, pwd, buf, buflen, result);
348 }
349}
350
351/*
352 * If pcmk__mock_readlink is set to true, later calls to readlink() must be
353 * preceded by:
354 *
355 * expect_*(__wrap_readlink, path[, ...]);
356 * expect_*(__wrap_readlink, buf[, ...]);
357 * expect_*(__wrap_readlink, bufsize[, ...]);
358 * will_return(__wrap_readlink, errno_to_set);
359 * will_return(__wrap_readlink, link_contents);
360 *
361 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
362 *
363 * The mocked function will return 0 if errno_to_set is 0, and -1 otherwise.
364 */
365
367
368ssize_t
369__wrap_readlink(const char *restrict path, char *restrict buf,
370 size_t bufsize)
371{
373 const char *contents = NULL;
374
375 check_expected_ptr(path);
376 check_expected_ptr(buf);
377 check_expected(bufsize);
378 errno = mock_type(int);
379 contents = mock_ptr_type(const char *);
380
381 if (errno == 0) {
382 strncpy(buf, contents, bufsize - 1);
383 return strlen(contents);
384 }
385 return -1;
386
387 } else {
388 return __real_readlink(path, buf, bufsize);
389 }
390}
391
392
393/* strdup()
394 *
395 * If pcmk__mock_strdup is set to true, later calls to strdup() will return
396 * NULL and must be preceded by:
397 *
398 * expect_*(__wrap_strdup, s[, ...]);
399 *
400 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
401 */
402
403bool pcmk__mock_strdup = false;
404
405char *
406__wrap_strdup(const char *s)
407{
408 if (!pcmk__mock_strdup) {
409 return __real_strdup(s);
410 }
411 check_expected_ptr(s);
412 return NULL;
413}
414
415
416/* uname()
417 *
418 * If pcmk__mock_uname is set to true, later calls to uname() must be preceded
419 * by:
420 *
421 * expect_*(__wrap_uname, buf[, ...]);
422 * will_return(__wrap_uname, return_value);
423 * will_return(__wrap_uname, node_name_for_buf_parameter_to_uname);
424 *
425 * expect_* functions: https://api.cmocka.org/group__cmocka__param.html
426 */
427
428bool pcmk__mock_uname = false;
429
430int
431__wrap_uname(struct utsname *buf)
432{
433 if (pcmk__mock_uname) {
434 int retval = 0;
435 char *result = NULL;
436
437 check_expected_ptr(buf);
438 retval = mock_type(int);
439 result = mock_ptr_type(char *);
440
441 if (result != NULL) {
442 strcpy(buf->nodename, result);
443 }
444 return retval;
445
446 } else {
447 return __real_uname(buf);
448 }
449}
450
451// LCOV_EXCL_STOP
const char * path
Definition cib.c:28
const char * name
Definition cib.c:26
#define restrict
Definition config.h:1035
uint32_t size
Definition cpg.c:4
int __wrap_setenv(const char *name, const char *value, int overwrite)
Definition mock.c:123
char * __wrap_strdup(const char *s)
Definition mock.c:406
bool pcmk__mock_getpid
Definition mock.c:170
pid_t __wrap_getpid(void)
Definition mock.c:173
bool pcmk__mock_getenv
Definition mock.c:93
bool pcmk__mock_calloc
Definition mock.c:68
bool pcmk__mock_getpwnam_r
Definition mock.c:329
bool pcmk__mock_fopen
Definition mock.c:271
bool pcmk__mock_unsetenv
Definition mock.c:148
char * __wrap_getenv(const char *name)
Definition mock.c:96
void __wrap_endgrent(void)
Definition mock.c:250
bool pcmk__mock_setenv
Definition mock.c:120
int __wrap_uname(struct utsname *buf)
Definition mock.c:431
int __wrap_unsetenv(const char *name)
Definition mock.c:151
bool pcmk__mock_strdup
Definition mock.c:403
bool pcmk__mock_readlink
Definition mock.c:366
void * __wrap_calloc(size_t nmemb, size_t size)
Definition mock.c:71
bool pcmk__mock_uname
Definition mock.c:428
bool pcmk__mock_grent
Definition mock.c:189
void __wrap_setgrent(void)
Definition mock.c:225
int __wrap_getpwnam_r(const char *name, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result)
Definition mock.c:332
struct group * __wrap_getgrent(void)
Definition mock.c:238
ssize_t __wrap_readlink(const char *restrict path, char *restrict buf, size_t bufsize)
Definition mock.c:369
FILE * __wrap_fopen(const char *pathname, const char *mode)
Definition mock.c:274
ssize_t __real_readlink(const char *restrict path, char *restrict buf, size_t bufsize)
void __real_endgrent(void)
void __real_setgrent(void)
pid_t __real_getpid(void)
FILE * __real_fopen(const char *pathname, const char *mode)
int __real_uname(struct utsname *buf)
char * __real_getenv(const char *name)
int __real_getpwnam_r(const char *name, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result)
char * __real_strdup(const char *s)
int __real_unsetenv(const char *name)
int __real_setenv(const char *name, const char *value, int overwrite)
void * __real_calloc(size_t nmemb, size_t size)
struct group * __real_getgrent(void)
pcmk__action_result_t result
Definition pcmk_fence.c:35