Skip to content

Commit

Permalink
test(libebpfdiscoveryskel): Implement unit tests for eBPF data utilit…
Browse files Browse the repository at this point in the history
…y functions (#11)
  • Loading branch information
hparzych authored Sep 27, 2023
1 parent b9b635e commit 4d9c29f
Show file tree
Hide file tree
Showing 10 changed files with 194 additions and 9 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ endif(NOT TARGET fmt)
find_package(Protobuf REQUIRED)

set(INSTALL_GTEST OFF CACHE BOOL "Disable installation of googletest" FORCE)
if(BUILD_TESTS)
if(BUILD_TESTS OR BUILD_BPF_TESTS)
include(FetchContent)
FetchContent_Declare(googletest URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip)
FetchContent_MakeAvailable(googletest)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Build debug:

```
conan install . --build=missing -s build_type=Debug
cmake --preset conan-debug -DTHIRDPARTY_MAKE_JOBS_COUNT=$((`nproc` / 2))
cmake --preset conan-debug -DTHIRDPARTY_MAKE_JOBS_COUNT=$((`nproc` / 2)) -DBUILD_BPF_TESTS=On
cmake --build --preset conan-debug
```

Expand Down
19 changes: 17 additions & 2 deletions libebpfdiscoveryskel/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
set(BPF_C_FLAGS ${BPF_C_FLAGS} -I${PROJECT_SOURCE_DIR}/libebpfdiscoveryshared/headers)
set(TARGET ebpfdiscoveryskel)

set(BPF_C_FLAGS ${BPF_C_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/src -I${PROJECT_SOURCE_DIR}/libebpfdiscoveryshared/headers)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(BpfObject REQUIRED)
bpf_object(ebpfdiscoveryskel src/discovery.bpf.c)
bpf_object(${TARGET} src/discovery.bpf.c)

if(BUILD_BPF_TESTS)
set(TEST_SKEL_TARGET ebpfdiscoverytestskel)
set(BPF_C_FLAGS ${BPF_C_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/test)
bpf_object(${TEST_SKEL_TARGET} testbpf/discoveryTest.bpf.c)

list(APPEND TEST_SOURCES test/DataFunctionsTest.cpp)
set(TEST_TARGET test${TARGET})

add_executable(${TEST_TARGET} ${TEST_SOURCES})
target_link_libraries(${TEST_TARGET} GTest::gtest_main ${TEST_SKEL_TARGET})
gtest_discover_tests(${TEST_TARGET})
endif()
10 changes: 5 additions & 5 deletions libebpfdiscoveryskel/src/DataFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

#include <bpf/bpf_helpers.h>

__attribute__((always_inline)) inline static int dataProbeIsEqualToString(const char* src, const char* str, size_t len) {
__attribute__((always_inline)) inline static int dataProbeEqualToString(const char* src, const char* str, size_t len) {
char ch;
for (size_t i = 0; i < len; ++i) {
int result = bpf_probe_read(&ch, sizeof(char), (char*)src + i);
if (result < 0) {
return result;
int res = bpf_probe_read(&ch, sizeof(char), (char*)src + i);
if (res < 0) {
return res;
}

if (ch != str[i] || ch == '\0') {
Expand All @@ -26,5 +26,5 @@ __attribute__((always_inline)) inline static bool dataProbeIsBeginningOfHttpRequ
// We expect only GET and POST requests. We expect request URI's to start with a slash as absolute urls are mainly used in
// requests to proxy servers.
return len >= DISCOVERY_MIN_HTTP_REQUEST_LENGTH &&
(dataProbeIsEqualToString(ptr, "GET /", 5) || dataProbeIsEqualToString(ptr, "POST /", 6));
(dataProbeEqualToString(ptr, "GET /", 5) == 5 || dataProbeEqualToString(ptr, "POST /", 6) == 6);
}
40 changes: 40 additions & 0 deletions libebpfdiscoveryskel/test/DataFunctionsTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-2.0
#include "DiscoveryTest.h"

#include "discoveryTest.skel.h"

#include <gtest/gtest.h>

#include <optional>
#include <tuple>
#include <variant>

using ebpfdiscovery::bpftest::attachBpfProgram;
using ebpfdiscovery::bpftest::DiscoveryTest;
using ebpfdiscovery::bpftest::triggerTracepoint;

struct DiscoveryDataFunctionsTestParams {
std::string inputPtrData;
size_t inputLen;
int expectedRet;
};

class DiscoveryDataFunctionsTest : public DiscoveryTest, public ::testing::WithParamInterface<DiscoveryDataFunctionsTestParams> {};
class DataProbeIsBeginningOfHttpRequestTest : public DiscoveryDataFunctionsTest {};

TEST_P(DataProbeIsBeginningOfHttpRequestTest, Default) {
const auto& data{GetParam()};
setInPtr(data.inputPtrData);
setInLen(data.inputLen);

attachBpfProgram(testSkel->progs.testDataProbeIsBeginningOfHttpRequest);
triggerTracepoint();

EXPECT_EQ(getOutRet(), data.expectedRet);
}

INSTANTIATE_TEST_SUITE_P(
Default,
DataProbeIsBeginningOfHttpRequestTest,
::testing::Values(DiscoveryDataFunctionsTestParams{
.inputPtrData = std::string("GET / HTTP/1.1\r\n"), .inputLen = 16, .expectedRet = (int)true}));
81 changes: 81 additions & 0 deletions libebpfdiscoveryskel/test/DiscoveryTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// SPDX-License-Identifier: GPL-2.0
#pragma once

#include "DiscoveryTestConstants.h"

#include "discoveryTest.skel.h"

#include <bpf/bpf.h>
#include <bpf/libbpf.h>

#include <gtest/gtest.h>

namespace ebpfdiscovery::bpftest {

class DiscoveryTest : public ::testing::Test {
public:
DiscoveryTest() : testSkel{nullptr}, testBss{nullptr} {
}

bool isLoaded() {
return testSkel != nullptr && testBss != nullptr;
}

void setInPtr(const std::string& str) {
checkLoaded();
inPtrSrc.clear();
std::copy(str.begin(), str.end(), std::back_inserter(inPtrSrc));
testBss->inPtr = inPtrSrc.data();
}

void setInLen(size_t len) {
checkLoaded();
testBss->inLen = len;
}

int getOutRet() {
checkLoaded();
return testBss->outRet;
}

protected:
void SetUp() override {
testSkel = discoveryTest_bpf__open_and_load();
if (testSkel == nullptr) {
GTEST_SKIP() << "Couldn't open and load BPF object for test execution.";
}

testBss = testSkel->bss;
testBss->runnerPid = getpid();
}

void TearDown() override {
if (testSkel != nullptr) {
discoveryTest_bpf__destroy(testSkel);
}
}

discoveryTest_bpf* testSkel;
discoveryTest_bpf::discoveryTest_bpf__bss* testBss;

std::vector<char> inPtrData;

void checkLoaded() {
if (!isLoaded()) {
throw std::runtime_error("DiscoveryTest is uninitialized");
}
}
};

void attachBpfProgram(bpf_program* prog) {
auto link = bpf_program__attach(prog);
if (link == nullptr) {
throw std::runtime_error("couldn't attach bpf program");
}
}

void triggerTracepoint() {
usleep(1);
}

} // namespace ebpfdiscovery::bpftest
4 changes: 4 additions & 0 deletions libebpfdiscoveryskel/test/DiscoveryTestConstants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
#pragma once

#define DISCOVERY_TEST_MAX_INPUT_LEN 1024
16 changes: 16 additions & 0 deletions libebpfdiscoveryskel/testbpf/DataFunctionsTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: GPL-2.0
#pragma once

#include "DataFunctions.h"

#include "TestDefine.h"

TEST_ENTRY int BPF_PROG(testDataProbeIsBeginningOfHttpRequest) {
CHECK_TEST_RUNNER(runnerPid);

if (inPtr != NULL && inLen < DISCOVERY_TEST_MAX_INPUT_LEN) {
outRet = dataProbeIsBeginningOfHttpRequest(inPtr, inLen);
}

return 0;
}
21 changes: 21 additions & 0 deletions libebpfdiscoveryskel/testbpf/TestDefine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0
#pragma once

#include "DiscoveryTestConstants.h"

#include "vmlinux.h"

#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

__u32 runnerPid = 0;

char* inPtr = NULL;
size_t inLen = 0;
int outRet = 0;

#define TEST_ENTRY SEC("fentry/do_nanosleep")
#define CHECK_TEST_RUNNER(runnerPid) \
if ((bpf_get_current_pid_tgid() >> 32) != runnerPid) { \
return 0; \
}
8 changes: 8 additions & 0 deletions libebpfdiscoveryskel/testbpf/discoveryTest.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
#include "DataFunctionsTest.h"

#include "vmlinux.h"

#include <bpf/bpf_helpers.h>

char _license[] SEC("license") = "GPL";

0 comments on commit 4d9c29f

Please sign in to comment.