// Copyright(c) 2017, Intel Corporation
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#ifndef _TEST_SYSTEM_H
#define _TEST_SYSTEM_H
#include <stdio.h>
#include <dirent.h>
#include <unistd.h>
#include <opae/fpga.h>
#include <stddef.h>
#include <sched.h>
#include <map>
#include <string>
#include <vector>
#include <json-c/json.h>
#include <thread>
#include <mutex>
#include <atomic>
#include "platform/fpga_hw.h"
#include <glob.h>
extern "C" {
extern void *__libc_malloc(size_t size);
extern void *__libc_calloc(size_t nmemb, size_t size);
}
typedef struct stat stat_t;
typedef int (*filter_func)(const struct dirent *);
typedef int (*compare_func)(const struct dirent **, const struct dirent **);
namespace opae {
namespace testing {
constexpr size_t KiB(size_t n) { return n * 1024; }
constexpr size_t MiB(size_t n) { return n * 1024 * KiB(1); }
#ifndef UNUSED_PARAM
#define UNUSED_PARAM(x) ((void)x)
#endif // UNUSED_PARAM
class mock_object {
public:
enum type_t { sysfs_attr = 0, fme, afu };
mock_object(const std::string &devpath, const std::string &sysclass,
uint32_t device_id, type_t type = sysfs_attr);
virtual ~mock_object() {}
virtual int ioctl(int request, va_list arg) {
UNUSED_PARAM(request);
UNUSED_PARAM(arg);
throw std::logic_error("not implemented");
return 0;
}
std::string sysclass() const { return sysclass_; }
uint32_t device_id() const { return device_id_; }
type_t type() const { return type_; }
private:
std::string devpath_;
std::string sysclass_;
uint32_t device_id_;
type_t type_;
};
class mock_fme : public mock_object {
public:
mock_fme(const std::string &devpath, const std::string &sysclass,
uint32_t device_id)
: mock_object(devpath, sysclass, device_id, fme) {}
virtual int ioctl(int request, va_list argp) override;
};
class mock_port : public mock_object {
public:
mock_port(const std::string &devpath, const std::string &sysclass,
uint32_t device_id)
: mock_object(devpath, sysclass, device_id, fme) {}
virtual int ioctl(int request, va_list argp) override;
};
template <int _R, long _E>
static int dummy_ioctl(mock_object *, int, va_list) {
errno = _E;
return _R;
}
class test_system {
public:
typedef int (*ioctl_handler_t)(mock_object *, int, va_list);
static test_system *instance();
void set_root(const char *root);
std::string get_root();
std::string get_sysfs_path(const std::string &src);
std::vector<uint8_t> assemble_gbs_header(const test_device &td);
std::vector<uint8_t> assemble_gbs_header(const test_device &td, const char* mdata);
void initialize();
void finalize();
void prepare_syfs(const test_platform &platform);
int remove_sysfs();
int remove_sysfs_dir(const char *path = nullptr);
std::string get_sysfs_claass_path(const std::string &path);
int open(const std::string &path, int flags);
int open(const std::string &path, int flags, mode_t m);
void invalidate_read(uint32_t after=0, const char *when_called_from=nullptr);
ssize_t read(int fd, void *buf, size_t count);
FILE * fopen(const std::string &path, const std::string &mode);
FILE * popen(const std::string &cmd, const std::string &type);
int pclose(FILE *stream);
int close(int fd);
int ioctl(int fd, unsigned long request, va_list argp);
DIR *opendir(const char *name);
ssize_t readlink(const char *path, char *buf, size_t bufsize);
int xstat(int ver, const char *path, stat_t *buf);
int lstat(int ver, const char *path, stat_t *buf);
int scandir(const char *dirp, struct dirent ***namelist, filter_func filter,
compare_func cmp);
int sched_setaffinity(pid_t pid, size_t cpusetsize,
const cpu_set_t *mask);
int glob(const char *pattern, int flags,
int (*errfunc) (const char *epath, int eerrno),
glob_t *pglob);
char *realpath(const char *inp, char *dst);
void hijack_sched_setaffinity(int return_val, uint32_t after=0,
const char *when_called_from=nullptr);
void invalidate_malloc(uint32_t after=0, const char *when_called_from=nullptr);
void invalidate_calloc(uint32_t after=0, const char *when_called_from=nullptr);
bool default_ioctl_handler(int request, ioctl_handler_t);
bool register_ioctl_handler(int request, ioctl_handler_t);
FILE *register_file(const std::string &path);
void normalize_guid(std::string &guid_str, bool with_hyphens = true);
private:
test_system();
std::mutex fds_mutex_;
std::atomic_bool initialized_;
std::string root_;
std::map<int, mock_object *> fds_;
std::map<int, ioctl_handler_t> default_ioctl_handlers_;
std::map<int, ioctl_handler_t> ioctl_handlers_;
std::map<std::string, std::string> registered_files_;
std::map<FILE * , std::string> popen_requests_;
static test_system *instance_;
typedef int (*open_func)(const char *pathname, int flags, ...);
typedef ssize_t (*read_func)(int fd, void *buf, size_t count);
typedef FILE * (*fopen_func)(const char *path, const char *mode);
typedef FILE * (*popen_func)(const char *cmd, const char *type);
typedef int (*pclose_func)(FILE *stream);
typedef int (*close_func)(int fd);
typedef int (*ioctl_func)(int fd, unsigned long request, char *argp);
typedef DIR *(*opendir_func)(const char *name);
typedef ssize_t (*readlink_func)(const char *pathname, char *buf,
size_t bufsiz);
typedef int (*__xstat_func)(int ver, const char *pathname, struct stat *buf);
typedef int (*scandir_func)(const char *, struct dirent ***, filter_func,
compare_func);
typedef int (*sched_setaffinity_func)(pid_t pid, size_t cpusetsize,
const cpu_set_t *mask);
typedef char *(*realpath_func)(const char *, char *);
typedef int (*glob_func)(const char *pattern, int flags,
int (*errfunc)(const char *epath, int eerrno),
glob_t *pglob);
open_func open_;
open_func open_create_;
read_func read_;
fopen_func fopen_;
popen_func popen_;
pclose_func pclose_;
close_func close_;
ioctl_func ioctl_;
opendir_func opendir_;
readlink_func readlink_;
__xstat_func xstat_;
__xstat_func lstat_;
scandir_func scandir_;
sched_setaffinity_func sched_setaffinity_;
glob_func glob_;
realpath_func realpath_;
bool hijack_sched_setaffinity_;
int hijack_sched_setaffinity_return_val_;
uint32_t hijack_sched_setaffinity_after_;
const char * hijack_sched_setaffinity_caller_;
};
} // end of namespace testing
} // end of namespace opae
#endif /* !_TEST_SYSTEM_H */