// 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 #include #include #include #include #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 { 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); }