// Copyright(c) 2018-2020, 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.
extern "C" {
#include "error_int.h"
#include "token_list_int.h"
}
#include <opae/error.h>
#include <props.h>
#include <fstream>
#include <string>
#include <cstring>
#include "gtest/gtest.h"
#include "mock/test_system.h"
#include "types_int.h"
#include "sysfs_int.h"
#include "xfpga.h"
extern "C" {
int xfpga_plugin_initialize(void);
int xfpga_plugin_finalize(void);
}
using namespace opae::testing;
const std::string sysfs_fme =
"/sys/class/fpga/intel-fpga-dev.0/intel-fpga-fme.0";
const std::string dev_fme = "/dev/intel-fpga-fme.0";
const std::string sysfs_port =
"/sys/class/fpga/intel-fpga-dev.0/intel-fpga-port.0";
const std::string dev_port = "/dev/intel-fpga-port.0";
class error_c_mock_p : public ::testing::TestWithParam<std::string> {
public:
int delete_errors(std::string, std::string);
protected:
error_c_mock_p() : filter_(nullptr) {}
virtual void SetUp() override {
ASSERT_TRUE(test_platform::exists(GetParam()));
platform_ = test_platform::get(GetParam());
system_ = test_system::instance();
system_->initialize();
system_->prepare_syfs(platform_);
tmpsysfs_ = system_->get_root();
ASSERT_EQ(FPGA_OK, xfpga_plugin_initialize());
if (sysfs_device_count() > 0) {
const sysfs_fpga_device *device = sysfs_get_device(0);
ASSERT_NE(device, nullptr);
if (device->fme) {
sysfs_fme = std::string(device->fme->sysfs_path);
dev_fme = std::string("/dev/") + std::string(device->fme->sysfs_name);
}
if (device->port) {
sysfs_port = std::string(device->port->sysfs_path);
dev_port = std::string("/dev/") + std::string(device->port->sysfs_name);
}
}
memset(&fake_port_token_, 0, sizeof(fake_port_token_));
strncpy(fake_port_token_.sysfspath,
sysfs_port.c_str(), sysfs_port.size() + 1);
strncpy(fake_port_token_.devpath,
dev_port.c_str(), dev_port.size() + 1);
fake_port_token_.magic = FPGA_TOKEN_MAGIC;
fake_port_token_.device_instance = 0;
fake_port_token_.subdev_instance = 0;
fake_port_token_.errors = nullptr;
memset(&fake_fme_token_, 0, sizeof(fake_fme_token_));
strncpy(fake_fme_token_.sysfspath,
sysfs_fme.c_str(), sysfs_fme.size() + 1);
strncpy(fake_fme_token_.devpath,
dev_fme.c_str(), dev_fme.size() + 1);
fake_fme_token_.magic = FPGA_TOKEN_MAGIC;
fake_fme_token_.device_instance = 0;
fake_fme_token_.subdev_instance = 0;
fake_fme_token_.errors = nullptr;
}
virtual void TearDown() override {
if (fake_fme_token_.errors) {
free_error_list(fake_fme_token_.errors);
}
if (fake_port_token_.errors) {
free_error_list(fake_port_token_.errors);
}
if (filter_) {
EXPECT_EQ(fpgaDestroyProperties(&filter_), FPGA_OK);
filter_ = nullptr;
}
token_cleanup();
tmpsysfs_ = "";
xfpga_plugin_finalize();
system_->finalize();
}
void free_error_list(struct error_list *p) {
while (p) {
struct error_list *q = p->next;
free(p);
p = q;
}
}
fpga_properties filter_;
std::string tmpsysfs_;
test_platform platform_;
test_system *system_;
_fpga_token fake_fme_token_;
_fpga_token fake_port_token_;
std::string sysfs_fme;
std::string dev_fme;
std::string sysfs_port;
std::string dev_port;
};
int error_c_mock_p::delete_errors(std::string fpga_type, std::string filename) {
int result;
std::string fme_sysfspath;
std::string port_sysfspath;
std::string cmd;
if (tmpsysfs_.length() < 2) {
fme_sysfspath = tmpsysfs_ + sysfs_fme + "/" + filename;
port_sysfspath = tmpsysfs_ + sysfs_port + "/" + filename;
} else {
fme_sysfspath = tmpsysfs_ + "/" + sysfs_fme + "/" + filename;
port_sysfspath = tmpsysfs_ + "/" + sysfs_port + "/" + filename;
}
if (fpga_type.compare("fme") == 0) {
cmd = "rm -rf " + fme_sysfspath;
goto remove;
} else if (fpga_type.compare("port") == 0) {
cmd = "rm -rf " + port_sysfspath;
goto remove;
} else {
return -1;
}
remove:
result = std::system(cmd.c_str());
(void)result;
return 1;
}
/**
* @test error_01
*
* @brief When passed a valid AFU token, the combination of
* fpgaGetProperties()
* fpgaPropertiesGetNumErrors(), fpgaPropertiesGetErrorInfo() and
* fpgaReadError() is able to print the status of all error
* registers.
*
*/
TEST_P(error_c_mock_p, error_01) {
#ifndef BUILD_ASE
fpga_error_info info;
unsigned int n = 0;
unsigned int i = 0;
uint64_t val = 0;
fpga_token t = &fake_port_token_;
std::string errpath = sysfs_port + "/errors";
build_error_list(errpath.c_str(), &fake_port_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d PORT error registers\n", n);
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
printf("[%u] %s: 0x%016lX%s\n", i, info.name, val,
info.can_clear ? " (can clear)" : "");
}
auto result = delete_errors("port", "errors");
(void)result;
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_EXCEPTION, xfpga_fpgaReadError(t, i, &val));
printf("[%u] %s: 0x%016lX%s\n", i, info.name, val,
info.can_clear ? " (can clear)" : "");
}
#endif
}
/**
* @test error_02
*
* @brief When passed a valid FME token, the combination of
* fpgaGetProperties()
* fpgaPropertiesGetNumErrors(), fpgaPropertiesGetErrorInfo() and
* fpgaReadError() is able to print the status of all error
* registers.
*
*/
TEST_P(error_c_mock_p, error_02) {
#ifndef BUILD_ASE
fpga_error_info info;
unsigned int n = 0;
unsigned int i = 0;
uint64_t val = 0;
fpga_token t = &fake_fme_token_;
std::string errpath = sysfs_fme + "/errors";
build_error_list(errpath.c_str(), &fake_fme_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d FME error registers\n", n);
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
printf("[%u] %s: 0x%016lX%s\n", i, info.name, val,
info.can_clear ? " (can clear)" : "");
}
auto result = delete_errors("fme", "errors");
(void)result;
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_NE(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
printf("[%u] %s: 0x%016lX%s\n", i, info.name, val,
info.can_clear ? " (can clear)" : "");
}
#endif
}
/**
* @test error_03
*
* @brief When passed a valid AFU token for an AFU with PORT errors,
* fpgaReadError() will report the correct error, and
* fpgaClearError() will clear it.
*
*/
TEST_P(error_c_mock_p, error_03) {
std::fstream clear_file;
std::ofstream error_file;
std::string clear_name = tmpsysfs_ + sysfs_port + "/errors/clear";
std::string error_name = tmpsysfs_ + sysfs_port + "/errors/errors";
uint64_t clear_val;
fpga_error_info info;
unsigned int n = 0;
unsigned int i = 0;
uint64_t val = 0;
fpga_token t = &fake_port_token_;
std::string errpath = sysfs_port + "/errors";
build_error_list(errpath.c_str(), &fake_port_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d PORT error registers\n", n);
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
ASSERT_EQ(val, 0);
}
// ------------- MAKE SURE CLEAR FILE IS 0 ------------
clear_file.open(clear_name);
ASSERT_EQ(1, clear_file.is_open());
clear_file >> clear_val;
clear_file.close();
ASSERT_EQ(clear_val, 0);
// ------------- INJECT PORT ERROR --------------------
error_file.open(error_name);
ASSERT_EQ(1, error_file.is_open());
error_file << "0x42" << std::endl;
error_file.close();
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
// if error, try to clear it (and check result)
if (val != 0) {
printf("[%u] %s: 0x%016lX%s\n", i, info.name, val,
info.can_clear ? " (can clear)" : "");
EXPECT_EQ(FPGA_OK, xfpga_fpgaClearError(t, i));
// check if value was written to clear file
clear_file.open(clear_name.c_str());
clear_file >> std::hex >> clear_val;
clear_file.close();
ASSERT_EQ(clear_val, val);
}
}
// --------------- WRITE 0 TO CLEAR AND ERROR FILES (CLEAN UP) -------------
error_file.open(error_name);
error_file << "0x0" << std::endl;
error_file.close();
clear_file.open(clear_name);
clear_file << "0x0" << std::endl;
clear_file.close();
}
/**
* @test error_04
*
* @brief When passed a valid AFU token for an AFU with PORT errors,
* fpgaReadError() will report the correct error, and
* fpgaClearAllErrors() will clear it.
*
*/
TEST_P(error_c_mock_p, error_04) {
std::fstream clear_file;
std::ofstream error_file;
std::string clear_name = tmpsysfs_ + sysfs_port + "/errors/clear";
std::string error_name = tmpsysfs_ + sysfs_port + "/errors/errors";
uint64_t clear_val;
fpga_error_info info;
unsigned int n = 0;
unsigned int i = 0;
uint64_t val = 0;
fpga_token t = &fake_port_token_;
std::string errpath = sysfs_port + "/errors";
build_error_list(errpath.c_str(), &fake_port_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d PORT error registers\n", n);
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
ASSERT_EQ(val, 0);
}
// ------------- MAKE SURE CLEAR FILE IS 0 ------------
clear_file.open(clear_name);
ASSERT_EQ(1, clear_file.is_open());
clear_file >> clear_val;
clear_file.close();
ASSERT_EQ(clear_val, 0);
// ------------- INJECT PORT ERROR --------------------
error_file.open(error_name);
ASSERT_EQ(1, error_file.is_open());
error_file << "0x42" << std::endl;
error_file.close();
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
EXPECT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(t, i, &val));
// if error, try to clear it (and check result)
if (val != 0) {
printf("[%u] %s: 0x%016lX%s\n", i, info.name, val,
info.can_clear ? " (can clear)" : "");
EXPECT_EQ(FPGA_OK, xfpga_fpgaClearAllErrors(t));
// check if value was written to clear file
clear_file.open(clear_name);
clear_file >> std::hex >> clear_val;
clear_file.close();
EXPECT_EQ(clear_val, val);
}
}
// --------------- WRITE 0 TO CLEAR AND ERROR FILES (CLEAN UP) -------------
error_file.open(error_name);
error_file << "0x0" << std::endl;
error_file.close();
clear_file.open(clear_name);
clear_file << "0x0" << std::endl;
clear_file.close();
}
/**
* @test error_05
*
* @brief When passed a valid AFU token for an AFU with PORT errors,
* fpgaReadError() will report the correct error, and
* fpgaClearError() will clear it.
*
*/
TEST_P(error_c_mock_p, error_05) {
unsigned int n = 0;
fpga_token t = &fake_port_token_;
std::string errpath = sysfs_port + "/errors";
build_error_list(errpath.c_str(), &fake_port_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d PORT error registers\n", n);
struct error_list *p = fake_port_token_.errors;
p->info.can_clear = false;
EXPECT_EQ(FPGA_NOT_SUPPORTED, xfpga_fpgaClearError(t, 0));
}
/**
* @test error_06
*
* @brief When passed a valid FME token,
* fpgaReadError() will report the correct error, and
* fpgaClearError() will clear it.
*
*/
TEST_P(error_c_mock_p, error_06) {
fpga_error_info info;
unsigned int n = 0;
unsigned int i = 0;
fpga_token t = &fake_fme_token_;
std::string errpath = sysfs_fme + "/errors";
build_error_list(errpath.c_str(), &fake_fme_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
// ASSERT_EQ(FPGA_OK, xfpga_fpgaPropertiesGetNumErrors(filter_, &n));
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d FME error registers\n", n);
// for each error register, get info and read the current value
for (i = 0; i < n; i++) {
// get info struct for error register
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetErrorInfo(t, i, &info));
// if error, try to clear it (and check result)
if (info.can_clear) {
EXPECT_EQ(FPGA_OK, xfpga_fpgaClearError(t, i));
}
}
free_error_list(fake_fme_token_.errors);
// set error list to null
fake_fme_token_.errors = nullptr;
EXPECT_EQ(FPGA_NOT_FOUND, xfpga_fpgaClearError(t, 0));
}
/**
* @test error_07
*
* @brief When passed a valid FME token,
* and delete error removes errors dir
* fpgaReadError() and fpgaClearError will
* returns FPGA_EXCEPTION
*
*/
TEST_P(error_c_mock_p, error_07) {
fpga_error_info info;
fpga_token t = &fake_fme_token_;
uint32_t num_errors = 0, i = 0;
std::string errpath = sysfs_fme + "/errors";
// build errors and immediately remove errors dir
build_error_list(errpath.c_str(), &fake_fme_token_.errors);
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
ASSERT_EQ(fpgaPropertiesGetNumErrors(filter_, &num_errors), FPGA_OK);
ASSERT_NE(num_errors, 0) << "No errors to clear";
for (i = 0; i < num_errors; i++) {
ASSERT_EQ(xfpga_fpgaGetErrorInfo(t, i, &info), FPGA_OK);
if (info.can_clear) {
auto ret = delete_errors("fme", "errors");
// get the clearable error
if (ret) {
EXPECT_EQ(FPGA_EXCEPTION, xfpga_fpgaClearError(t, i));
}
break;
}
}
EXPECT_NE(i, num_errors) << "Did not attempt to clear errors";
}
/**
* @test error_08
* fpgaReadError() will report the correct error, and
* fpgaClearError() will clear it.
*
*/
TEST_P(error_c_mock_p, error_08) {
unsigned int n = 0;
fpga_token t = &fake_port_token_;
std::string errpath = sysfs_port + "/errors";
build_error_list(errpath.c_str(), &fake_port_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d PORT error registers\n", n);
EXPECT_EQ(FPGA_OK, xfpga_fpgaClearAllErrors(t));
}
/**
* @test error_09
*
* @brief When passed a valid FME token,
* fpgaReadError() will report the correct error, and
* fpgaClearError() will clear it.
*
*/
TEST_P(error_c_mock_p, error_09) {
unsigned int n = 0;
fpga_token t = &fake_fme_token_;
std::string errpath = sysfs_fme + "/errors";
build_error_list(errpath.c_str(), &fake_fme_token_.errors);
// get number of error registers
ASSERT_EQ(FPGA_OK, xfpga_fpgaGetProperties(t, &filter_));
auto _prop = (_fpga_properties *)filter_;
SET_FIELD_VALID(_prop, FPGA_PROPERTY_NUM_ERRORS);
ASSERT_EQ(FPGA_OK, fpgaPropertiesGetNumErrors(filter_, &n));
printf("Found %d PORT error registers\n", n);
EXPECT_EQ(FPGA_OK, xfpga_fpgaClearAllErrors(t));
}
/**
* @test error_12
* @brief When passed an invalid token magic,
* xfpga_fpgaClearAllErrors() should return FPGA_INVALID_PARAM.
*/
TEST_P(error_c_mock_p, error_12) {
auto fme = token_add(sysfs_fme.c_str(), dev_fme.c_str());
ASSERT_NE(fme, nullptr);
auto port = token_add(sysfs_port.c_str(), dev_port.c_str());
ASSERT_NE(port, nullptr);
auto parent = token_get_parent(port);
EXPECT_EQ(parent, fme);
auto tok = (struct _fpga_token *)parent;
tok->magic = FPGA_TOKEN_MAGIC;
EXPECT_EQ(FPGA_OK, xfpga_fpgaClearAllErrors(parent));
tok->magic = 0x123;
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaClearAllErrors(parent));
}
INSTANTIATE_TEST_CASE_P(error_c, error_c_mock_p,
::testing::ValuesIn(test_platform::mock_platforms({ "skx-p","dcp-rc","dcp-vc" })));
class error_c_p : public error_c_mock_p {};
/**
* @test error_10
*
* @brief When passed an invalid token magic,
* xfpga_fpgaReadError() should return FPGA_INVALID_PARAM.
* when token doesn't have errpath
* xfpga_fpgaReadError() should return FPGA_NOT_FOUND.
*
*/
TEST_P(error_c_p, error_10) {
auto fme = token_add(sysfs_fme.c_str(), dev_fme.c_str());
ASSERT_NE(fme, nullptr);
auto port = token_add(sysfs_port.c_str(), dev_port.c_str());
ASSERT_NE(port, nullptr);
auto parent = token_get_parent(port);
EXPECT_EQ(parent, fme);
auto tok = (struct _fpga_token *)parent;
uint64_t val = 0;
tok->magic = 0x123;
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaReadError(parent, 0, &val));
tok->magic = FPGA_TOKEN_MAGIC;
EXPECT_EQ(FPGA_OK, xfpga_fpgaReadError(parent, 0, &val));
EXPECT_EQ(FPGA_NOT_FOUND, xfpga_fpgaReadError(parent, 1000, &val));
}
/**
* @test error_11
*
* @brief When passed an invalid token magic,
* xfpga_fpgaClearError() should return FPGA_INVALID_PARAM.
* when token doesn't have errpath
* xfpga_fpgaClearError() should return FPGA_NOT_FOUND.
*
*/
TEST_P(error_c_p, error_11) {
auto fme = token_add(sysfs_fme.c_str(), dev_fme.c_str());
ASSERT_NE(fme, nullptr);
auto port = token_add(sysfs_port.c_str(), dev_port.c_str());
ASSERT_NE(port, nullptr);
auto parent = token_get_parent(port);
EXPECT_EQ(parent, fme);
auto tok = (struct _fpga_token *)parent;
EXPECT_EQ(FPGA_NOT_FOUND, xfpga_fpgaClearError(parent, 1000));
tok->magic = 0x123;
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaClearError(parent, 0));
}
/**
* @test error_13
* @brief When passed an invalid token magic,
* xfpga_fpgaClearAllErrors() should return FPGA_INVALID_PARAM.
* when token doesn't have errpath
* xfpga_fpgaClearAllErrors() should return FPGA_NOT_FOUND.
*/
TEST_P(error_c_p, error_13) {
auto fme = token_add(sysfs_fme.c_str(), dev_fme.c_str());
ASSERT_NE(fme, nullptr);
auto port = token_add(sysfs_port.c_str(), dev_port.c_str());
ASSERT_NE(port, nullptr);
auto parent = token_get_parent(port);
EXPECT_EQ(parent, fme);
auto tok = (struct _fpga_token *)parent;
struct fpga_error_info info;
tok->magic = FPGA_TOKEN_MAGIC;
EXPECT_EQ(FPGA_NOT_FOUND, xfpga_fpgaGetErrorInfo(parent, 1000, &info));
tok->magic = 0x123;
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaGetErrorInfo(parent, 0, &info));
}
INSTANTIATE_TEST_CASE_P(error_c, error_c_p,
::testing::ValuesIn(test_platform::platforms({ "skx-p","dcp-rc","dcp-vc" })));
/**
* @test error_01
*
* @brief When passed an NULL token
* xfpga_fpgaReadError() should return FPGA_INVALID_PARAM.
* xfpga_fpgaClearError() should return FPGA_INVALID_PARAM.
* xfpga_fpgaClearAllErrors() should return FPGA_INVALID_PARAM.
*
*/
TEST(error_c, error_01) {
fpga_token tok = NULL;
uint64_t val = 0;
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaReadError(tok, 0, &val));
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaClearError(tok, 0));
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaClearAllErrors(tok));
EXPECT_EQ(FPGA_INVALID_PARAM, xfpga_fpgaGetErrorInfo(tok, 0, NULL));
}
/**
* @test error_06
*
* @brief When passed in invalid errors path to build_error_list,
* the function returns 0 for file doesn't exist.
*
*/
TEST(error_c, error_06) {
struct _fpga_token _t;
strncpy(_t.sysfspath, sysfs_port.c_str(), sysfs_port.size() + 1);
strncpy(_t.devpath, dev_port.c_str(), dev_port.size() + 1);
_t.magic = FPGA_TOKEN_MAGIC;
_t.errors = nullptr;
std::string invalid_errpath = sysfs_port + "/errorss";
auto result = build_error_list(invalid_errpath.c_str(), &_t.errors);
EXPECT_EQ(result, 0);
}
/**
* @test error_07
*
* @brief When passed pathname longer than FILENAME_MAX
* build_error_list() should return and not build anything
*
*@note Must set env-variable LIBOPAE_LOG=1 to run this test.
*
*/
TEST(error_c, error_07) {
struct error_list *el = NULL;
std::string lpn(FILENAME_MAX + 1, 'a');
std::string exptout("path too long");
char *loglv = secure_getenv("LIBOPAE_LOG");
if (loglv && atoi(loglv) > 0) {
testing::internal::CaptureStdout();
build_error_list(lpn.c_str(), &el);
std::string actout = testing::internal::GetCapturedStdout();
EXPECT_NE(std::string::npos, actout.find(exptout));
}
EXPECT_EQ(NULL, el);
}