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