Skip to content

Commit

Permalink
tests: add test for exit events
Browse files Browse the repository at this point in the history
Signed-off-by: Andrea Terzolo <[email protected]>
  • Loading branch information
Andreagit97 committed Dec 16, 2024
1 parent 2684d5c commit 68f6a46
Show file tree
Hide file tree
Showing 5 changed files with 382 additions and 2 deletions.
84 changes: 84 additions & 0 deletions userspace/libsinsp/test/parsers/parse_brk.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <sinsp_with_test_input.h>

TEST_F(sinsp_with_test_input, parse_brk_updated_prog_break) {
add_default_init_thread();
open_inspector();

// if the program break is updated the res should be equal to `addr`
uint64_t res = 83983092;
uint32_t vm_size = 294;
uint32_t vm_rss = 295;
uint32_t vm_swap = 296;

auto evt = add_event_advance_ts(increasing_ts(),
INIT_TID,
PPME_SYSCALL_BRK_4_X,
4,
res,
vm_size,
vm_rss,
vm_swap);

auto init_tinfo = m_inspector.get_thread_ref(INIT_TID, false, true).get();
ASSERT_TRUE(init_tinfo);
ASSERT_EQ(init_tinfo->m_vmsize_kb, vm_size);
ASSERT_EQ(init_tinfo->m_vmrss_kb, vm_rss);
ASSERT_EQ(init_tinfo->m_vmswap_kb, vm_swap);

assert_return_value(evt, res);

ASSERT_EQ(get_field_as_string(evt, "evt.arg[1]"), std::to_string(vm_size));
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.vm_size"), std::to_string(vm_size));

ASSERT_EQ(get_field_as_string(evt, "evt.arg[2]"), std::to_string(vm_rss));
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.vm_rss"), std::to_string(vm_rss));

ASSERT_EQ(get_field_as_string(evt, "evt.arg[3]"), std::to_string(vm_swap));
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.vm_swap"), std::to_string(vm_swap));
}

TEST_F(sinsp_with_test_input, parse_brk_no_update) {
add_default_init_thread();
open_inspector();

// if the program break is different from `addr`.
uint64_t res = 83983090;
uint32_t vm_size = 294;
uint32_t vm_rss = 295;
uint32_t vm_swap = 296;

auto evt = add_event_advance_ts(increasing_ts(),
INIT_TID,
PPME_SYSCALL_BRK_4_X,
4,
res,
vm_size,
vm_rss,
vm_swap);

auto init_tinfo = m_inspector.get_thread_ref(INIT_TID, false, true).get();
ASSERT_TRUE(init_tinfo);
// We should always update the info
ASSERT_EQ(init_tinfo->m_vmsize_kb, vm_size);
ASSERT_EQ(init_tinfo->m_vmrss_kb, vm_rss);
ASSERT_EQ(init_tinfo->m_vmswap_kb, vm_swap);

// BRK can update or not update the program break according to the value we provide. Today we
// don't consider a failure if the program break in not updated, we consider a failure only if
// the syscall sets an errno.
assert_return_value(evt, res);
}
88 changes: 88 additions & 0 deletions userspace/libsinsp/test/parsers/parse_pread.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@

// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <sinsp_with_test_input.h>

TEST_F(sinsp_with_test_input, parse_pread_success) {
add_default_init_thread();
open_inspector();

auto evt = generate_open_x_event();
ASSERT_TRUE(evt->get_fd_info());

std::string data = "hello";
uint32_t size = data.size();
uint64_t pos = 0;
evt = add_event_advance_ts(increasing_ts(),
INIT_TID,
PPME_SYSCALL_PREAD_X,
5,
(int64_t)size,
scap_const_sized_buffer{data.c_str(), size},
sinsp_test_input::open_params::default_fd,
size,
pos);

ASSERT_TRUE(evt->get_fd_info());
assert_fd_fields(evt,
sinsp_test_input::fd_info_fields{
.fd_num = sinsp_test_input::open_params::default_fd,
.fd_name = sinsp_test_input::open_params::default_path,
.fd_name_raw = sinsp_test_input::open_params::default_path,
.fd_directory = sinsp_test_input::open_params::default_directory,
.fd_filename = sinsp_test_input::open_params::default_filename});

assert_return_value(evt, size);

ASSERT_EQ(get_field_as_string(evt, "evt.arg[1]"), data);
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.data"), data);

ASSERT_EQ(get_field_as_string(evt, "evt.arg[2]"),
std::string("<f>") + sinsp_test_input::open_params::default_path);

Check warning on line 53 in userspace/libsinsp/test/parsers/parse_pread.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/test/parsers/parse_pread.cpp#L53

Added line #L53 was not covered by tests
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.fd"),
std::to_string(sinsp_test_input::open_params::default_fd));

Check warning on line 55 in userspace/libsinsp/test/parsers/parse_pread.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/test/parsers/parse_pread.cpp#L55

Added line #L55 was not covered by tests

ASSERT_EQ(get_field_as_string(evt, "evt.arg[3]"), std::to_string(size));
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.size"), std::to_string(size));
}

TEST_F(sinsp_with_test_input, parse_pread_failure) {
add_default_init_thread();
open_inspector();

auto evt = generate_open_x_event();

std::string data = "hello";
uint32_t size = data.size();
int64_t errno_code = -3;
uint64_t pos = 0;
evt = add_event_advance_ts(increasing_ts(),
INIT_TID,
PPME_SYSCALL_PREAD_X,
5,
errno_code,
scap_const_sized_buffer{data.c_str(), size},
sinsp_test_input::open_params::default_fd,
size,
pos);

// Check we have the correct fd info associated with the event
auto fdinfo = evt->get_fd_info();
ASSERT_TRUE(fdinfo);
ASSERT_EQ(fdinfo->m_fd, sinsp_test_input::open_params::default_fd);

// Assert return value filterchecks
assert_return_value(evt, errno_code);
}
84 changes: 84 additions & 0 deletions userspace/libsinsp/test/parsers/parse_read.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@

// SPDX-License-Identifier: Apache-2.0
/*
Copyright (C) 2024 The Falco Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include <sinsp_with_test_input.h>

TEST_F(sinsp_with_test_input, parse_read_success) {
add_default_init_thread();
open_inspector();

auto evt = generate_open_x_event();
ASSERT_TRUE(evt->get_fd_info());

std::string data = "hello";
uint32_t size = data.size();
evt = add_event_advance_ts(increasing_ts(),
INIT_TID,
PPME_SYSCALL_READ_X,
4,
(int64_t)size,
scap_const_sized_buffer{data.c_str(), size},
sinsp_test_input::open_params::default_fd,
size);

ASSERT_TRUE(evt->get_fd_info());
assert_fd_fields(evt,
sinsp_test_input::fd_info_fields{
.fd_num = sinsp_test_input::open_params::default_fd,
.fd_name = sinsp_test_input::open_params::default_path,
.fd_name_raw = sinsp_test_input::open_params::default_path,
.fd_directory = sinsp_test_input::open_params::default_directory,
.fd_filename = sinsp_test_input::open_params::default_filename});

assert_return_value(evt, size);

ASSERT_EQ(get_field_as_string(evt, "evt.arg[1]"), data);
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.data"), data);

ASSERT_EQ(get_field_as_string(evt, "evt.arg[2]"),
std::string("<f>") + sinsp_test_input::open_params::default_path);

Check warning on line 51 in userspace/libsinsp/test/parsers/parse_read.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/test/parsers/parse_read.cpp#L51

Added line #L51 was not covered by tests
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.fd"),
std::to_string(sinsp_test_input::open_params::default_fd));

Check warning on line 53 in userspace/libsinsp/test/parsers/parse_read.cpp

View check run for this annotation

Codecov / codecov/patch

userspace/libsinsp/test/parsers/parse_read.cpp#L53

Added line #L53 was not covered by tests

ASSERT_EQ(get_field_as_string(evt, "evt.arg[3]"), std::to_string(size));
ASSERT_EQ(get_field_as_string(evt, "evt.rawarg.size"), std::to_string(size));
}

TEST_F(sinsp_with_test_input, parse_read_failure) {
add_default_init_thread();
open_inspector();

auto evt = generate_open_x_event();

std::string data = "hello";
uint32_t size = data.size();
int64_t errno_code = -3;
evt = add_event_advance_ts(increasing_ts(),
INIT_TID,
PPME_SYSCALL_READ_X,
4,
errno_code,
scap_const_sized_buffer{data.c_str(), size},
sinsp_test_input::open_params::default_fd,
size);

// Check we have the correct fd info associated with the event
auto fdinfo = evt->get_fd_info();
ASSERT_TRUE(fdinfo);
ASSERT_EQ(fdinfo->m_fd, sinsp_test_input::open_params::default_fd);

// Assert return value filterchecks
assert_return_value(evt, errno_code);
}
112 changes: 112 additions & 0 deletions userspace/libsinsp/test/sinsp_with_test_input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -693,3 +693,115 @@ sinsp_evt* sinsp_with_test_input::next_event() {
auto result = m_inspector.next(&evt);
return result == SCAP_SUCCESS ? evt : nullptr;
}

void sinsp_with_test_input::assert_return_value(sinsp_evt* evt, int64_t expected_retval) {
// First the event we provide should have the return value
ASSERT_TRUE(evt->has_return_value());

// The raw value should be equal to what we expect
ASSERT_EQ(evt->get_syscall_return_value(), expected_retval);

// We need to create the filtercheck name for the first parameter, usually `res`/`fd` but not
// always, could be also `addr` for example...
std::string evt_rawarg_name = std::string("evt.rawarg.") + std::string(evt->get_param_name(0));

// SUCCESS CASE: we consider success when retval >= 0 (so != errno)
if(expected_retval >= 0) {
/////////////
// Res
/////////////
ASSERT_EQ(get_field_as_string(evt, "evt.res"), "SUCCESS");
ASSERT_EQ(get_field_as_string(evt, "evt.rawres"), std::to_string(expected_retval));
ASSERT_EQ(get_field_as_string(evt, "evt.failed"), "false");

/////////////
// First parameter (arg0)
/////////////
auto arg0_info = evt->get_param_info(0);
ASSERT_TRUE(arg0_info);
// Default values
std::string arg0 = std::to_string(expected_retval);
std::string raw_arg0 = std::to_string(expected_retval);

// Some cases in which we need to modify `arg0` or `raw_arg0`
if(arg0_info->type == PT_FD) {
// If the return value is a file descriptor the value of `evt.arg[0]` is the path
// prefixed by `<f>`
auto fdinfo = evt->get_fd_info();
ASSERT_TRUE(fdinfo);
arg0 = std::string("<f>") + fdinfo->m_name;

// raw_arg0 is ok!
}

if(arg0_info->fmt == PF_HEX && arg0_info->type == PT_UINT64) {
// both `evt.arg[0]` and `evt.rawarg` become hexadecimal
char buffer[100];
std::snprintf(buffer, sizeof(buffer), "%" PRIX64, expected_retval);
arg0 = buffer;
raw_arg0 = buffer;
}

ASSERT_EQ(get_field_as_string(evt, "evt.arg[0]"), arg0);
ASSERT_EQ(get_field_as_string(evt, evt_rawarg_name), raw_arg0);
} else {
/////////////
// Res
/////////////
ASSERT_EQ(get_field_as_string(evt, "evt.res"), sinsp_utils::errno_to_str(expected_retval));
ASSERT_EQ(get_field_as_string(evt, "evt.rawres"), std::to_string(expected_retval));
ASSERT_EQ(get_field_as_string(evt, "evt.failed"), "true");

/////////////
// First parameter (arg0)
/////////////
ASSERT_EQ(get_field_as_string(evt, "evt.arg[0]"), get_field_as_string(evt, "evt.res"));
ASSERT_EQ(get_field_as_string(evt, evt_rawarg_name),
get_field_as_string(evt, "evt.rawres"));
}
}

void sinsp_with_test_input::assert_fd_fields(sinsp_evt* evt,
sinsp_test_input::fd_info_fields fields) {
auto fdinfo = evt->get_fd_info();

// Right now we only assert if the fdinfo is present, but we want to be sure that for some
// events the fdinfo should be here
if((evt->creates_fd() || evt->uses_fd()) && evt->get_syscall_return_value() >= 0) {
ASSERT_TRUE(fdinfo);
}

if(fdinfo) {
if(fields.fd_num.has_value()) {
ASSERT_EQ(fdinfo->m_fd, fields.fd_num.value());
}

if(fields.fd_name.has_value()) {
ASSERT_EQ(fdinfo->m_name, fields.fd_name.value());
}

if(fields.fd_name_raw.has_value()) {
ASSERT_EQ(fdinfo->m_name_raw, fields.fd_name_raw.value());
}
}

if(fields.fd_num.has_value()) {
ASSERT_EQ(get_field_as_string(evt, "fd.num"), std::to_string(fields.fd_num.value()));
}

if(fields.fd_name.has_value()) {
ASSERT_EQ(get_field_as_string(evt, "fd.name"), fields.fd_name.value());
}

if(fields.fd_name_raw.has_value()) {
ASSERT_EQ(get_field_as_string(evt, "fd.nameraw"), fields.fd_name_raw.value());
}

if(fields.fd_directory.has_value()) {
ASSERT_EQ(get_field_as_string(evt, "fd.directory"), fields.fd_directory.value());
}

if(fields.fd_filename.has_value()) {
ASSERT_EQ(get_field_as_string(evt, "fd.filename"), fields.fd_filename.value());
}
}
Loading

0 comments on commit 68f6a46

Please sign in to comment.