// Copyright(c) 2018, 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.
#include <opae/fpga.h>
extern "C" {
#include <json-c/json.h>
#include <uuid/uuid.h>
struct UserClkCommandLine
{
int segment;
int bus;
int device;
int function;
int socket;
int freq_high;
int freq_low;
};
extern struct UserClkCommandLine userclkCmdLine;
void UserClkAppShowHelp(void);
void print_err(const char *s, fpga_result res);
int ParseCmds(struct UserClkCommandLine *userclkCmdLine, int argc, char *argv[]);
int userclk_main(int argc, char *argv[]);
}
#include <config.h>
#include <iostream>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <errno.h>
#include <unistd.h>
#include "gtest/gtest.h"
#include "mock/test_system.h"
using namespace opae::testing;
class userclk_c_p : public ::testing::TestWithParam<std::string> {
protected:
userclk_c_p() {}
virtual void SetUp() override {
std::string platform_key = GetParam();
ASSERT_TRUE(test_platform::exists(platform_key));
platform_ = test_platform::get(platform_key);
system_ = test_system::instance();
system_->initialize();
system_->prepare_syfs(platform_);
EXPECT_EQ(fpgaInitialize(NULL), FPGA_OK);
optind = 0;
cmd_line_ = userclkCmdLine;
}
virtual void TearDown() override {
userclkCmdLine = cmd_line_;
fpgaFinalize();
system_->finalize();
}
struct UserClkCommandLine cmd_line_;
test_platform platform_;
test_system *system_;
};
/**
* @test help
* @brief Test: UserClkAppShowHelp
* @details UserClkAppShowHelp displays the application help message.<br>
*/
TEST_P(userclk_c_p, help) {
UserClkAppShowHelp();
}
/**
* @test print_err
* @brief Test: print_err
* @details print_err prints the given string and<br>
* the decoded representation of the fpga_result<br>
* to stderr.<br>
*/
TEST_P(userclk_c_p, print_err) {
print_err("msg", FPGA_OK);
}
/**
* @test parse_cmd0
* @brief Test: ParseCmds
* @details When passed an invalid command option,<br>
* ParseCmds prints a message and<br>
* returns a negative value.<br>
*/
TEST_P(userclk_c_p, parse_cmd0) {
struct UserClkCommandLine cmd;
char zero[20];
char one[20];
strcpy(zero, "userclk");
strcpy(one, "-Y");
char *argv[] = { zero, one };
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
}
/**
* @test parse_cmd1
* @brief Test: ParseCmds
* @details When called with "-h",<br>
* ParseCmds prints the app help and<br>
* returns a negative value.<br>
*/
TEST_P(userclk_c_p, parse_cmd1) {
struct UserClkCommandLine cmd;
char zero[20];
char one[20];
strcpy(zero, "userclk");
strcpy(one, "-h");
char *argv[] = { zero, one };
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
}
/**
* @test parse_cmd2
* @brief Test: ParseCmds
* @details When given a command option that requires a param,<br>
* omitting the required param causes ParseCmds to<br>
* return a negative value.<br>
*/
TEST_P(userclk_c_p, parse_cmd2) {
struct UserClkCommandLine cmd;
char zero[20];
char one[20];
strcpy(zero, "userclk");
char *argv[] = { zero, one };
strcpy(one, "--segment");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-B");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-D");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-F");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-S");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-P");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-H");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
optind = 0;
strcpy(one, "-L");
EXPECT_LT(ParseCmds(&cmd, 2, argv), 0);
}
/**
* @test parse_cmd3
* @brief Test: ParseCmds
* @details When given valid command options,<br>
* ParseCmds populates the given UserClkCommandLine,<br>
* returning zero.<br>
*/
TEST_P(userclk_c_p, parse_cmd3) {
struct UserClkCommandLine cmd = cmd_line_;
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
char thirteen[20];
char fourteen[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
strcpy(two, "0x1234");
strcpy(three, "-B");
strcpy(four, "3");
strcpy(five, "-D");
strcpy(six, "4");
strcpy(seven, "-F");
strcpy(eight, "5");
strcpy(nine, "-S");
strcpy(ten, "6");
strcpy(eleven, "-H");
strcpy(twelve, "8");
strcpy(thirteen, "-L");
strcpy(fourteen, "9");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve, thirteen, fourteen };
EXPECT_EQ(ParseCmds(&cmd, 15, argv), 0);
EXPECT_EQ(cmd.segment, 0x1234);
EXPECT_EQ(cmd.bus, 3);
EXPECT_EQ(cmd.device, 4);
EXPECT_EQ(cmd.function, 5);
EXPECT_EQ(cmd.socket, 6);
EXPECT_EQ(cmd.freq_high, 8);
EXPECT_EQ(cmd.freq_low, 9);
}
/**
* @test invalid_cmd_characters_02
* @brief Test: ParseCmds, userclk_main
* @details When given invalid command options,<br>
* ParseCmds populates the given UserClkCommandLine,<br>
* returning FPGA_INVALID_PARAM.<br>
*/
TEST_P(userclk_c_p, invalid_cmd_characters_01) {
struct UserClkCommandLine cmd = cmd_line_;
char zero[32];
char one[32];
char two[32];
char three[32];
char four[32];
char five[48];
char six[32];
char seven[32];
char eight[32];
char nine[32];
char ten[32];
char eleven[32];
char twelve[32];
char thirteen[32];
char fourteen[32];
strcpy(zero, "userclk_+*(^> ");
strcpy(one, "--segm ent");
strcpy(two, "0x1234");
strcpy(three, "-Bus");
strcpy(four, "3");
strcpy(five, "-Devi +_( \v -0923198 (*)& ces");
strcpy(six, "4");
strcpy(seven, "-Fun\t\nction");
strcpy(eight, "5");
strcpy(nine, "-Sockett\e \'\?//tttttt \b");
strcpy(ten, "6");
strcpy(eleven, "- High");
strcpy(twelve, "-100");
strcpy(thirteen, " ---Low");
strcpy(fourteen, "-200");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve, thirteen, fourteen };
EXPECT_NE(ParseCmds(&cmd, 15, argv), 0);
EXPECT_NE(userclk_main(15, argv), 0);
}
/**
* @test invalid_cmd_characters_02
* @brief Test: ParseCmds, userclk_main
* @details When given invalid command options,<br>
* ParseCmds populates the given UserClkCommandLine,<br>
* returning zero. Userclk_main returns FPGA_INVALID_PARAM.<br>
*/
TEST_P(userclk_c_p, invalid_cmd_characters_02) {
struct UserClkCommandLine cmd;
char zero[32];
char one[32];
char two[48];
char three[32];
char four[32];
char five[32];
char six[32];
char seven[32];
char eight[48];
char nine[32];
char ten[32];
char eleven[32];
char twelve[32];
char thirteen[32];
char fourteen[32];
strcpy(zero, "");
strcpy(one, "--segment");
strcpy(two, "0x0123897349 *(^%$%^$%@^?><? 6121234");
strcpy(three, " --B");
strcpy(four, "334987238689 \x01\x05\x0a\x15");
strcpy(five, "-D");
strcpy(six, "41278991 02a8974913");
strcpy(seven, "-F");
strcpy(eight, "529378190 \t 3haskfhahhi\\ | // o=1-21");
strcpy(nine, "-S");
strcpy(ten, " 6`1238 \n -349287419=-0;");
strcpy(eleven, "-H");
strcpy(twelve, "400000000000000000000000000");
strcpy(thirteen, "-L");
strcpy(fourteen, "9.999");
char *argv[] = { zero, one, two, three, four,
eleven, twelve, thirteen, fourteen,
five, six, seven, eight, nine, ten};
EXPECT_EQ(ParseCmds(&cmd, 15, argv), 0);
EXPECT_NE(userclk_main(15, argv), 0);
}
/**
* @test main0
* @brief Test: userclk_main
* @details When given no command options,<br>
* userclk_main displays the app help message,<br>
* and the fn returns non-zero.<br>
*/
TEST_P(userclk_c_p, main0) {
char zero[20];
strcpy(zero, "userclk");
char *argv[] = { zero };
EXPECT_NE(userclk_main(1, argv), 0);
}
/**
* @test main1
* @brief Test: userclk_main
* @details When given "-h",<br>
* userclk_main displays the app help message,<br>
* and the fn returns non-zero.<br>
*/
TEST_P(userclk_c_p, main1) {
char zero[20];
char one[20];
strcpy(zero, "userclk");
strcpy(one, "-h");
char *argv[] = { zero, one };
EXPECT_NE(userclk_main(2, argv), 0);
}
/**
* @test main2
* @brief Test: userclk_main
* @details When given valid command parameters,<br>
* but no device is identified by those parameters,<br>
* userclk_main displays an error message,<br>
* and the fn returns non-zero.<br>
*/
TEST_P(userclk_c_p, main2) {
char zero[20];
char one[20];
char two[20];
strcpy(zero, "userclk");
strcpy(one, "-B");
strcpy(two, "99");
char *argv[] = { zero, one, two };
EXPECT_NE(userclk_main(3, argv), 0);
}
INSTANTIATE_TEST_CASE_P(userclk_c, userclk_c_p,
::testing::ValuesIn(test_platform::platforms({})));
class userclk_c_hw_p : public userclk_c_p{
protected:
userclk_c_hw_p() {};
};
/**
* @test main3
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if --freq-low is not given,<br>
* then low is calculated from high,<br>
* and the fn returns zero.<br>
*/
TEST_P(userclk_c_hw_p, main3) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
strcpy(eleven, "-H");
strcpy(twelve, "400");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve };
EXPECT_EQ(userclk_main(13, argv), FPGA_OK);
}
/**
* @test main4
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if --freq-high is not given,<br>
* then high is calculated from low,<br>
* and the fn returns zero.<br>
*/
TEST_P(userclk_c_hw_p, main4) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
strcpy(eleven, "-L");
strcpy(twelve, "200");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve };
EXPECT_EQ(userclk_main(13, argv), FPGA_OK);
}
/**
* @test main5
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if both --freq-high (-H) and --freq-low (-L) are given,<br>
* then high must equal 2 * low,<br>
* or else the fn returns FPGA_INVALID_PARAM.<br>
*/
TEST_P(userclk_c_hw_p, main5) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
char thirteen[20];
char fourteen[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
strcpy(eleven, "-H");
strcpy(twelve, "300");
strcpy(thirteen, "-L");
strcpy(fourteen, "100");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve, thirteen, fourteen };
EXPECT_EQ(userclk_main(15, argv), FPGA_INVALID_PARAM);
}
/**
* @test main6
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if neither --freq-high (-H) nor --freq-low (-L) is given,<br>
* then the function prints an error<br>
* and returns FPGA_INVALID_PARAM.<br>
*/
TEST_P(userclk_c_hw_p, main6) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten };
EXPECT_EQ(userclk_main(11, argv), FPGA_INVALID_PARAM);
}
INSTANTIATE_TEST_CASE_P(userclk_c, userclk_c_hw_p,
::testing::ValuesIn(test_platform::hw_platforms({"skx-p","dcp-rc"})));
class userclk_c_mock_p : public userclk_c_p{
protected:
userclk_c_mock_p() {};
};
/**
* @test main3
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if --freq-low is not given,<br>
* then low is calculated from high,<br>
* and the fn returns zero.<br>
*/
TEST_P(userclk_c_mock_p, main3) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
strcpy(eleven, "-H");
strcpy(twelve, "400");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve };
/*
** FIXME: main should return zero in this case, but
** the user clocks API polls on a sysfs file with a
** timeout. Because the sysfs file never updates in
** a mock environment, the API will time out and return
** FPGA_NOT_SUPPORTED.
EXPECT_EQ(userclk_main(13, argv), 0);
*/
EXPECT_EQ(userclk_main(13, argv), FPGA_NOT_SUPPORTED);
}
/**
* @test main4
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if --freq-high is not given,<br>
* then high is calculated from low,<br>
* and the fn returns zero.<br>
*/
TEST_P(userclk_c_mock_p, main4) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
strcpy(eleven, "-L");
strcpy(twelve, "200");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve };
/*
** FIXME: main should return zero in this case, but
** the user clocks API polls on a sysfs file with a
** timeout. Because the sysfs file never updates in
** a mock environment, the API will time out and return
** FPGA_NOT_SUPPORTED.
EXPECT_EQ(userclk_main(13, argv), 0);
*/
EXPECT_EQ(userclk_main(13, argv), FPGA_NOT_SUPPORTED);
}
/**
* @test main5
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if both --freq-high (-H) and --freq-low (-L) are given,<br>
* then high must equal 2 * low,<br>
* or else the fn returns FPGA_INVALID_PARAM.<br>
*/
TEST_P(userclk_c_mock_p, main5) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
char eleven[20];
char twelve[20];
char thirteen[20];
char fourteen[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
strcpy(eleven, "-H");
strcpy(twelve, "300");
strcpy(thirteen, "-L");
strcpy(fourteen, "100");
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten, eleven, twelve, thirteen, fourteen };
EXPECT_EQ(userclk_main(15, argv), FPGA_INVALID_PARAM);
}
/**
* @test main6
* @brief Test: userclk_main
* @details When given valid command parameters that identify an accelerator,<br>
* if neither --freq-high (-H) nor --freq-low (-L) is given,<br>
* then the function prints an error<br>
* and returns FPGA_INVALID_PARAM.<br>
*/
TEST_P(userclk_c_mock_p, main6) {
char zero[20];
char one[20];
char two[20];
char three[20];
char four[20];
char five[20];
char six[20];
char seven[20];
char eight[20];
char nine[20];
char ten[20];
strcpy(zero, "userclk");
strcpy(one, "--segment");
sprintf(two, "%d", platform_.devices[0].segment);
strcpy(three, "-B");
sprintf(four, "%d", platform_.devices[0].bus);
strcpy(five, "-D");
sprintf(six, "%d", platform_.devices[0].device);
strcpy(seven, "-F");
sprintf(eight, "%d", platform_.devices[0].function);
strcpy(nine, "-S");
sprintf(ten, "%d", platform_.devices[0].socket_id);
char *argv[] = { zero, one, two, three, four,
five, six, seven, eight, nine,
ten };
EXPECT_EQ(userclk_main(11, argv), FPGA_INVALID_PARAM);
}
INSTANTIATE_TEST_CASE_P(userclk_c, userclk_c_mock_p,
::testing::ValuesIn(test_platform::mock_platforms({"skx-p", "dcp-rc"})));