You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
8.4 KiB
335 lines
8.4 KiB
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 Zabbix SIA
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
|
|
#define fopen __real_fopen
|
|
#define fclose __real_fclose
|
|
#define fgets __real_fgets
|
|
#include <stdio.h>
|
|
#undef fopen
|
|
#undef fclose
|
|
#undef fgets
|
|
|
|
#include "zbxmocktest.h"
|
|
#include "zbxmockdata.h"
|
|
#include "zbxmockutil.h"
|
|
|
|
#include "zbxcommon.h"
|
|
|
|
#define ZBX_MOCK_MAX_FILES 16
|
|
|
|
void *mock_streams[ZBX_MOCK_MAX_FILES];
|
|
|
|
static zbx_mock_handle_t fragments;
|
|
|
|
static FILE *(*fopen_mock_callback)(const char *, const char *) = NULL;
|
|
|
|
struct zbx_mock_IO_FILE
|
|
{
|
|
const char *contents;
|
|
};
|
|
|
|
FILE *__wrap_fopen(const char *path, const char *mode);
|
|
int __wrap_fclose(FILE *fp);
|
|
char *__wrap_fgets(char *s, int size, FILE *stream);
|
|
int __wrap_fstat(int __fildes, struct stat *__stat_buf);
|
|
int __wrap_connect(int socket, void *addr, socklen_t address_len);
|
|
ssize_t __wrap_read(int fildes, void *buf, size_t nbyte);
|
|
int __wrap_open(const char *path, int oflag, ...);
|
|
int __wrap_stat(const char *path, struct stat *buf);
|
|
int __wrap___xstat(int ver, const char *pathname, struct stat *buf);
|
|
#ifdef HAVE_FXSTAT
|
|
int __wrap___fxstat(int __ver, int __fildes, struct stat *__stat_buf);
|
|
#endif
|
|
|
|
int __real_open(const char *path, int oflag, ...);
|
|
int __real_stat(const char *path, struct stat *buf);
|
|
int __real_fstat(int __fildes, struct stat *__stat_buf);
|
|
#ifdef HAVE_FXSTAT
|
|
int __real___fxstat(int __ver, int __fildes, struct stat *__stat_buf);
|
|
#endif
|
|
|
|
static int is_profiler_path(const char *path)
|
|
{
|
|
size_t len;
|
|
|
|
len = strlen(path);
|
|
|
|
if ((ZBX_CONST_STRLEN(".gcda") < len && 0 == strcmp(path + len - ZBX_CONST_STRLEN(".gcda"), ".gcda")) ||
|
|
(ZBX_CONST_STRLEN(".gcno") < len &&
|
|
0 == strcmp(path + len - ZBX_CONST_STRLEN(".gcno"), ".gcno")))
|
|
{
|
|
return SUCCEED;
|
|
}
|
|
|
|
return FAIL;
|
|
}
|
|
|
|
static int is_mock_stream(FILE *stream)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ZBX_MOCK_MAX_FILES && NULL != mock_streams[i]; i++)
|
|
{
|
|
if (stream == mock_streams[i])
|
|
return SUCCEED;
|
|
}
|
|
|
|
return FAIL;
|
|
}
|
|
|
|
FILE *__wrap_fopen(const char *path, const char *mode)
|
|
{
|
|
zbx_mock_error_t error;
|
|
zbx_mock_handle_t file_contents;
|
|
const char *contents;
|
|
struct zbx_mock_IO_FILE *file = NULL;
|
|
|
|
/* in case a test needs a custom fopen mock, use callback instead */
|
|
if (NULL != fopen_mock_callback)
|
|
return (*fopen_mock_callback)(path, mode);
|
|
|
|
if (SUCCEED == is_profiler_path(path))
|
|
return __real_fopen(path, mode);
|
|
|
|
if (0 != strcmp(mode, "r"))
|
|
{
|
|
fail_msg("fopen() modes other than \"r\" are not supported.");
|
|
}
|
|
else if (ZBX_MOCK_NO_PARAMETER == (error = zbx_mock_file(path, &file_contents)))
|
|
{
|
|
errno = ENOENT; /* No such file or directory */
|
|
}
|
|
else if (ZBX_MOCK_SUCCESS != error)
|
|
{
|
|
fail_msg("Error while trying to open path \"%s\" from test case data: %s", path,
|
|
zbx_mock_error_string(error));
|
|
}
|
|
else if (ZBX_MOCK_SUCCESS != (error = zbx_mock_string(file_contents, &contents)))
|
|
{
|
|
fail_msg("Error while trying to get contents of file \"%s\" from test case data: %s", path,
|
|
zbx_mock_error_string(error));
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < ZBX_MOCK_MAX_FILES && NULL != mock_streams[i]; i++)
|
|
;
|
|
|
|
if (i < ZBX_MOCK_MAX_FILES)
|
|
{
|
|
file = zbx_malloc(file, sizeof(struct zbx_mock_IO_FILE));
|
|
file->contents = contents;
|
|
mock_streams[i] = file;
|
|
}
|
|
else
|
|
errno = EMFILE; /* The per-process limit on the number of open file descriptors has been reached */
|
|
}
|
|
|
|
return (FILE *)file;
|
|
}
|
|
|
|
int __wrap_fclose(FILE *fp)
|
|
{
|
|
if (SUCCEED != is_mock_stream(fp))
|
|
return __real_fclose(fp);
|
|
|
|
zbx_free(fp);
|
|
return 0;
|
|
}
|
|
|
|
char *__wrap_fgets(char *s, int size, FILE *stream)
|
|
{
|
|
struct zbx_mock_IO_FILE *file = (struct zbx_mock_IO_FILE *)stream;
|
|
int length;
|
|
const char *newline;
|
|
|
|
if (SUCCEED != is_mock_stream(stream))
|
|
return __real_fgets(s, size, stream);
|
|
|
|
assert_non_null(s);
|
|
assert_true(0 < size);
|
|
|
|
if ('\0' == *file->contents)
|
|
return NULL;
|
|
|
|
if (size - 1 < (length = strlen(file->contents)))
|
|
length = size - 1;
|
|
|
|
if (NULL != (newline = strchr(file->contents, '\n')) && newline - file->contents + 1 < length)
|
|
length = newline - file->contents + 1;
|
|
|
|
assert_int_equal(length, zbx_snprintf(s, size, "%.*s", length, file->contents));
|
|
file->contents += length;
|
|
return s;
|
|
}
|
|
|
|
int __wrap_connect(int socket, void *addr, socklen_t address_len)
|
|
{
|
|
zbx_mock_error_t error;
|
|
|
|
ZBX_UNUSED(socket);
|
|
ZBX_UNUSED(addr);
|
|
ZBX_UNUSED(address_len);
|
|
|
|
if (ZBX_MOCK_SUCCESS != (error = zbx_mock_in_parameter("fragments", &fragments)))
|
|
fail_msg("Cannot get fragments handle: %s", zbx_mock_error_string(error));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int __wrap_poll(struct pollfd *pds, int nfds, int timeout)
|
|
{
|
|
int i;
|
|
|
|
ZBX_UNUSED(timeout);
|
|
|
|
for (i = 0; i < nfds; i++)
|
|
pds[i].revents = (POLLIN | POLLOUT);
|
|
|
|
return nfds;
|
|
}
|
|
|
|
int __wrap_open(const char *path, int oflag, ...)
|
|
{
|
|
if (SUCCEED == is_profiler_path(path))
|
|
{
|
|
va_list args;
|
|
int fd;
|
|
|
|
va_start(args, oflag);
|
|
fd = __real_open(path, oflag, va_arg(args, int));
|
|
va_end(args);
|
|
return fd;
|
|
}
|
|
|
|
fragments = zbx_mock_get_parameter_handle("in.fragments");
|
|
|
|
return INT_MAX;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* *
|
|
* Comments: Note that simply wrapping read function will break any compiled *
|
|
* in tool, that would attempt to use read() function. In this case *
|
|
* some safeguards must be added to implement pass-through *
|
|
* functionality like it's done with open/fxstat etc functions for *
|
|
* coverage builds. *
|
|
* *
|
|
******************************************************************************/
|
|
ssize_t __wrap_read(int fildes, void *buf, size_t nbyte)
|
|
{
|
|
static int remaining_length;
|
|
static const char *data;
|
|
zbx_mock_error_t error;
|
|
zbx_mock_handle_t fragment;
|
|
size_t length;
|
|
|
|
ZBX_UNUSED(fildes);
|
|
|
|
if (0 == remaining_length)
|
|
{
|
|
if (ZBX_MOCK_SUCCESS != zbx_mock_vector_element(fragments, &fragment))
|
|
return 0; /* no more data */
|
|
|
|
if (ZBX_MOCK_SUCCESS != (error = zbx_mock_binary(fragment, &data, &length)))
|
|
fail_msg("Cannot read data '%s'", zbx_mock_error_string(error));
|
|
}
|
|
else
|
|
length = remaining_length;
|
|
|
|
if (nbyte < length)
|
|
{
|
|
remaining_length = length - nbyte;
|
|
length = nbyte;
|
|
}
|
|
else
|
|
remaining_length = 0;
|
|
|
|
memcpy(buf, data, length);
|
|
|
|
if (0 != remaining_length)
|
|
data += length;
|
|
|
|
return length;
|
|
}
|
|
|
|
int __wrap_stat(const char *path, struct stat *buf)
|
|
{
|
|
zbx_mock_error_t error;
|
|
zbx_mock_handle_t handle;
|
|
|
|
if (SUCCEED == is_profiler_path(path))
|
|
return __real_stat(path, buf);
|
|
|
|
if (ZBX_MOCK_SUCCESS == (error = zbx_mock_file(path, &handle)))
|
|
{
|
|
buf->st_mode = S_IFMT & S_IFREG;
|
|
return 0;
|
|
}
|
|
|
|
if (ZBX_MOCK_NO_PARAMETER != error)
|
|
fail_msg("Error during path \"%s\" lookup among files: %s", path, zbx_mock_error_string(error));
|
|
|
|
if (0) /* directory lookup is not implemented */
|
|
{
|
|
buf->st_mode = S_IFMT & S_IFDIR;
|
|
return 0;
|
|
}
|
|
|
|
errno = ENOENT; /* No such file or directory */
|
|
return -1;
|
|
}
|
|
|
|
int __wrap_fstat(int __fildes, struct stat *__stat_buf)
|
|
{
|
|
if (__fildes != INT_MAX)
|
|
return __real_fstat(__fildes, __stat_buf);
|
|
|
|
__stat_buf->st_size = zbx_mock_get_parameter_uint64("in.file_len");
|
|
return 0;
|
|
}
|
|
|
|
int __wrap___xstat(int ver, const char *pathname, struct stat *buf)
|
|
{
|
|
ZBX_UNUSED(ver);
|
|
|
|
if (SUCCEED == is_profiler_path(pathname))
|
|
return __real_stat(pathname, buf);
|
|
|
|
return __wrap_stat(pathname, buf);
|
|
}
|
|
|
|
#ifdef HAVE_FXSTAT
|
|
int __wrap___fxstat(int __ver, int __fildes, struct stat *__stat_buf)
|
|
{
|
|
if (__fildes != INT_MAX)
|
|
return __real___fxstat(__ver, __fildes, __stat_buf);
|
|
|
|
__stat_buf->st_size = zbx_mock_get_parameter_uint64("in.file_len");
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void zbx_set_fopen_mock_callback(FILE *(*fopen_callback)(const char *, const char *))
|
|
{
|
|
fopen_mock_callback = fopen_callback;
|
|
}
|