diff --git a/userspace/libsinsp/test/filter_transformer.ut.cpp b/userspace/libsinsp/test/filter_transformer.ut.cpp index d66647d427..d40ce639c9 100644 --- a/userspace/libsinsp/test/filter_transformer.ut.cpp +++ b/userspace/libsinsp/test/filter_transformer.ut.cpp @@ -31,51 +31,80 @@ static std::set all_param_types() { return ret; } +template +static T extract_value_to_scalar(const extract_value_t& val) { + T ret; + EXPECT_EQ(val.len, sizeof(T)); + memcpy(&ret, val.ptr, val.len); + return ret; +} + static std::string supported_type_msg(ppm_param_type t, bool flags, bool support_expected) { return std::string("expected ") + (flags ? "list " : "") + "param type to" + std::string((support_expected ? " " : " not ")) + "be supported: " + std::string(param_type_to_string(t)); } -static std::string eq_test_msg(const std::pair &tc) { - return "expected '" + tc.first + "' (length: " + std::to_string(tc.first.length()) + ")" + - " to be equal to '" + tc.second + "' (length: " + std::to_string(tc.second.length()) + - ")"; +static std::string eq_test_msg(extract_value_t actual, extract_value_t expected) { + return "expected '" + std::string(reinterpret_cast(actual.ptr)) + + "' (length: " + std::to_string(actual.len) + ")" + " to be equal to '" + + std::string(reinterpret_cast(expected.ptr)) + + "' (length: " + std::to_string(expected.len) + ")"; } -static extract_value_t const_str_to_extract_value(const char *v) { - extract_value_t ret; - ret.ptr = (uint8_t *)v; - ret.len = strlen(v) + 1; - return ret; -} +struct ex_value : public extract_value_t { + ex_value(const ex_value& val) { + m_storage = val.m_storage; + len = val.len; -template -static T extract_value_to_scalar(const extract_value_t &val) { - T ret; - EXPECT_EQ(val.len, sizeof(T)); - memcpy(&ret, val.ptr, val.len); - return ret; -} + ptr = (uint8_t*)m_storage.data(); + } + + ex_value(std::string val) { + m_storage = std::vector(val.c_str(), val.c_str() + val.size() + 1); + + len = m_storage.size(); + ptr = (uint8_t*)m_storage.data(); + } -static void check_unsupported_types(sinsp_filter_transformer &tr, - std::set> &supported_types, - std::vector sample_vals) { + ex_value(uint64_t val) { + uint8_t* bytes = reinterpret_cast(&val); + m_storage = std::vector(bytes, bytes + sizeof(uint64_t)); + + len = sizeof(val); + ptr = (uint8_t*)m_storage.data(); + } + + std::vector m_storage; +}; + +struct test_case_entry { + uint32_t flags; + ppm_param_type input_type; + std::vector input; + ppm_param_type expected_type; + std::vector expected; +}; + +static void check_unsupported_types(sinsp_filter_transformer& tr, + std::set& supported_types, + std::set& supported_list_types) { auto all_types = all_param_types(); for(auto t : all_types) { uint32_t flags = EPF_IS_LIST; - if(supported_types.find({t, flags}) == supported_types.end()) { - auto vals = sample_vals; + if(supported_list_types.find(t) == supported_list_types.end()) { EXPECT_FALSE(tr.transform_type(t, flags)) << supported_type_msg(t, flags, false); + // vals is empty for simplicity, should not affect the test + std::vector vals{}; EXPECT_ANY_THROW(tr.transform_values(vals, t, flags)) << supported_type_msg(t, flags, false); } flags = 0; - if(supported_types.find({t, flags}) == supported_types.end()) { - auto vals = sample_vals; + if(supported_types.find(t) == supported_types.end()) { EXPECT_FALSE(tr.transform_type(t, flags)) << supported_type_msg(t, flags, false); + std::vector vals{}; EXPECT_ANY_THROW(tr.transform_values(vals, t, flags)) << supported_type_msg(t, flags, false); } @@ -85,46 +114,46 @@ static void check_unsupported_types(sinsp_filter_transformer &tr, TEST(sinsp_filter_transformer, toupper) { sinsp_filter_transformer tr(filter_transformer_type::FTR_TOUPPER); - auto all_types = all_param_types(); - - auto supported_types = std::set>( - {{PT_CHARBUF, false}, {PT_FSPATH, false}, {PT_FSRELPATH, false}}); - - auto test_cases = std::vector>{ - {"hello", "HELLO"}, - {"world", "WORLD"}, - {"eXcItED", "EXCITED"}, - {"", ""}, + std::set supported_types{PT_CHARBUF, PT_FSPATH, PT_FSRELPATH}; + std::set supported_list_types = supported_types; + + check_unsupported_types(tr, supported_types, supported_list_types); + + std::vector test_cases{ + {0, PT_CHARBUF, {{"hello"}}, PT_CHARBUF, {{"HELLO"}}}, + {0, PT_CHARBUF, {{"WORLD"}}, PT_CHARBUF, {{"WORLD"}}}, + {0, PT_CHARBUF, {{"eXcItED"}}, PT_CHARBUF, {{"EXCITED"}}}, + {0, PT_CHARBUF, {{""}}, PT_CHARBUF, {{""}}}, + {0, + PT_CHARBUF, + {{"hello"}, {"wOrLd"}, {"ONE_1234"}}, + PT_CHARBUF, + {{"HELLO"}, {"WORLD"}, {"ONE_1234"}}}, }; - std::vector sample_vals; - - for(auto &tc : test_cases) { - sample_vals.push_back(const_str_to_extract_value(tc.first.c_str())); - } - - check_unsupported_types(tr, supported_types, sample_vals); - - // check for supported types - for(auto t : supported_types) { - auto original_type = t.first; - uint32_t flags = t.second ? EPF_IS_LIST : 0; - auto transformed_type = original_type; + for(auto const& tc : test_cases) { + auto transformed_type = tc.input_type; + uint32_t flags = tc.flags; + bool is_list = flags & EPF_IS_LIST; EXPECT_TRUE(tr.transform_type(transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, - transformed_type); // note: toupper is expected not to alter the type + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(transformed_type, tc.expected_type); + + std::vector vals{}; + for(auto const& val : tc.input) { + vals.push_back(val); + } - auto vals = sample_vals; + transformed_type = tc.input_type; EXPECT_TRUE(tr.transform_values(vals, transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, transformed_type); - EXPECT_EQ(vals.size(), test_cases.size()); - - for(uint32_t i = 0; i < test_cases.size(); i++) { - EXPECT_EQ(std::string((const char *)vals[i].ptr), test_cases[i].second) - << eq_test_msg(test_cases[i]); - EXPECT_EQ(vals[i].len, test_cases[i].second.length() + 1) << eq_test_msg(test_cases[i]); + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(vals.size(), tc.expected.size()); + + for(std::vector::size_type i = 0; i < vals.size(); i++) { + std::string actual = (const char*)vals[i].ptr; + std::string expected = (const char*)tc.expected[i].ptr; + EXPECT_EQ(actual, expected) << eq_test_msg(vals[i], tc.expected[i]); + EXPECT_EQ(vals[i].len, tc.expected[i].len) << eq_test_msg(vals[i], tc.expected[i]); } } } @@ -132,46 +161,47 @@ TEST(sinsp_filter_transformer, toupper) { TEST(sinsp_filter_transformer, tolower) { sinsp_filter_transformer tr(filter_transformer_type::FTR_TOLOWER); - auto all_types = all_param_types(); - - auto supported_types = std::set>( - {{PT_CHARBUF, false}, {PT_FSPATH, false}, {PT_FSRELPATH, false}}); - - auto test_cases = std::vector>{ - {"HELLO", "hello"}, - {"world", "world"}, - {"NoT_eXcItED", "not_excited"}, - {"", ""}, + std::set supported_types{PT_CHARBUF, PT_FSPATH, PT_FSRELPATH}; + std::set supported_list_types = supported_types; + + check_unsupported_types(tr, supported_types, supported_list_types); + + std::vector test_cases{ + {0, PT_CHARBUF, {{"HELLO"}}, PT_CHARBUF, {{"hello"}}}, + {0, PT_CHARBUF, {{"world"}}, PT_CHARBUF, {{"world"}}}, + {0, PT_CHARBUF, {{"NoT eXcItED"}}, PT_CHARBUF, {{"not excited"}}}, + {0, PT_CHARBUF, {{""}}, PT_CHARBUF, {{""}}}, + {EPF_IS_LIST, + PT_CHARBUF, + {{"HELLO"}, {"wOrLd"}, {"one_1234"}}, + PT_CHARBUF, + {{"hello"}, {"world"}, {"one_1234"}}}, }; - std::vector sample_vals; + for(auto const& tc : test_cases) { + bool is_list = tc.flags & EPF_IS_LIST; + uint32_t flags = tc.flags; + auto transformed_type = tc.input_type; - for(auto &tc : test_cases) { - sample_vals.push_back(const_str_to_extract_value(tc.first.c_str())); - } - - check_unsupported_types(tr, supported_types, sample_vals); - - // check for supported types - for(auto t : supported_types) { - auto original_type = t.first; - uint32_t flags = t.second ? EPF_IS_LIST : 0; - auto transformed_type = original_type; EXPECT_TRUE(tr.transform_type(transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, - transformed_type); // note: tolower is expected not to alter the type + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(transformed_type, tc.expected_type); - auto vals = sample_vals; + std::vector vals{}; + for(auto const& val : tc.input) { + vals.push_back(val); + } + + transformed_type = tc.input_type; EXPECT_TRUE(tr.transform_values(vals, transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, transformed_type); - EXPECT_EQ(vals.size(), test_cases.size()); - - for(uint32_t i = 0; i < test_cases.size(); i++) { - EXPECT_EQ(std::string((const char *)vals[i].ptr), test_cases[i].second) - << eq_test_msg(test_cases[i]); - EXPECT_EQ(vals[i].len, test_cases[i].second.length() + 1) << eq_test_msg(test_cases[i]); + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(vals.size(), tc.expected.size()); + + for(std::vector::size_type i = 0; i < vals.size(); i++) { + std::string actual = (const char*)vals[i].ptr; + std::string expected = (const char*)tc.expected[i].ptr; + EXPECT_EQ(actual, expected) << eq_test_msg(vals[i], tc.expected[i]); + EXPECT_EQ(vals[i].len, tc.expected[i].len) << eq_test_msg(vals[i], tc.expected[i]); } } } @@ -179,163 +209,142 @@ TEST(sinsp_filter_transformer, tolower) { TEST(sinsp_filter_transformer, b64) { sinsp_filter_transformer tr(filter_transformer_type::FTR_BASE64); - auto all_types = all_param_types(); + std::set supported_types{PT_CHARBUF, PT_FSPATH, PT_FSRELPATH, PT_BYTEBUF}; + std::set supported_list_types = supported_types; - auto supported_types = - std::set>({{PT_CHARBUF, false}, {PT_BYTEBUF, false}}); + check_unsupported_types(tr, supported_types, supported_list_types); - auto test_cases = std::vector>{ - {"aGVsbG8=", "hello"}, - {"d29ybGQgIQ==", "world !"}, - {"", ""}, + std::vector test_cases{ + {0, PT_CHARBUF, {{"aGVsbG8="}}, PT_CHARBUF, {{"hello"}}}, + {0, PT_CHARBUF, {{"d29ybGQgIQ=="}}, PT_CHARBUF, {{"world !"}}}, + {0, PT_CHARBUF, {{""}}, PT_CHARBUF, {{""}}}, }; - std::vector invalid_test_cases{"!!!"}; + for(auto const& tc : test_cases) { + bool is_list = tc.flags & EPF_IS_LIST; + uint32_t flags = tc.flags; + auto transformed_type = tc.input_type; - std::vector sample_vals; - for(auto &tc : test_cases) { - sample_vals.push_back(const_str_to_extract_value(tc.first.c_str())); - } - - check_unsupported_types(tr, supported_types, sample_vals); - - // check for supported types - for(auto t : supported_types) { - auto original_type = t.first; - uint32_t flags = t.second ? EPF_IS_LIST : 0; - auto transformed_type = original_type; EXPECT_TRUE(tr.transform_type(transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, transformed_type); // note: b64 is expected not to alter the type + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(transformed_type, tc.expected_type); - auto vals = sample_vals; - EXPECT_TRUE(tr.transform_values(vals, transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, transformed_type); - EXPECT_EQ(vals.size(), test_cases.size()); - - for(uint32_t i = 0; i < test_cases.size(); i++) { - EXPECT_EQ(std::string((const char *)vals[i].ptr), test_cases[i].second) - << eq_test_msg(test_cases[i]); - EXPECT_EQ(vals[i].len, test_cases[i].second.length() + 1) << eq_test_msg(test_cases[i]); + std::vector vals{}; + for(auto const& val : tc.input) { + vals.push_back(val); } - } - - std::vector invalid_vals; - for(auto &tc : invalid_test_cases) { - invalid_vals.push_back(const_str_to_extract_value(tc.c_str())); - } - // check invalid input being rejected - { - auto t = PT_CHARBUF; - uint32_t flags = 0; - EXPECT_FALSE(tr.transform_values(invalid_vals, t, flags)); - EXPECT_EQ(t, PT_CHARBUF); + transformed_type = tc.input_type; + EXPECT_TRUE(tr.transform_values(vals, transformed_type, flags)) + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(vals.size(), tc.expected.size()); + + for(std::vector::size_type i = 0; i < vals.size(); i++) { + std::string actual = (const char*)vals[i].ptr; + std::string expected = (const char*)tc.expected[i].ptr; + EXPECT_EQ(actual, expected) << eq_test_msg(vals[i], tc.expected[i]); + EXPECT_EQ(vals[i].len, tc.expected[i].len) << eq_test_msg(vals[i], tc.expected[i]); + } } } TEST(sinsp_filter_transformer, basename) { sinsp_filter_transformer tr(filter_transformer_type::FTR_BASENAME); - auto all_types = all_param_types(); + std::set supported_types{PT_CHARBUF, PT_FSPATH, PT_FSRELPATH}; + std::set supported_list_types = supported_types; - auto supported_types = std::set>( - {{PT_CHARBUF, false}, {PT_FSPATH, false}, {PT_FSRELPATH, false}}); + check_unsupported_types(tr, supported_types, supported_list_types); - auto test_cases = std::vector>{ - {"/home/ubuntu/hello.txt", "hello.txt"}, - {"/usr/local/bin/cat", "cat"}, - {"/", ""}, - {"", ""}, - {"/hello/", ""}, - {"hello", "hello"}, + std::vector test_cases{ + {0, PT_CHARBUF, {{"/home/ubuntu/hello.txt"}}, PT_CHARBUF, {{"hello.txt"}}}, + {0, PT_FSPATH, {{"/usr/local/bin/cat"}}, PT_FSPATH, {{"cat"}}}, + {0, PT_FSPATH, {{"/"}}, PT_FSPATH, {{""}}}, + {0, PT_CHARBUF, {{"/hello/"}}, PT_CHARBUF, {{""}}}, + {0, PT_CHARBUF, {{"hello"}}, PT_CHARBUF, {{"hello"}}}, + {0, PT_CHARBUF, {{""}}, PT_CHARBUF, {{""}}}, }; - std::vector sample_vals; - - for(auto &tc : test_cases) { - sample_vals.push_back(const_str_to_extract_value(tc.first.c_str())); - } - - check_unsupported_types(tr, supported_types, sample_vals); + for(auto const& tc : test_cases) { + bool is_list = tc.flags & EPF_IS_LIST; + uint32_t flags = tc.flags; + auto transformed_type = tc.input_type; - // check for supported types - for(auto t : supported_types) { - auto original_type = t.first; - uint32_t flags = t.second ? EPF_IS_LIST : 0; - auto transformed_type = original_type; EXPECT_TRUE(tr.transform_type(transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, - transformed_type); // note: basename is expected not to alter the type + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(transformed_type, tc.expected_type); - auto vals = sample_vals; + std::vector vals{}; + for(auto const& val : tc.input) { + vals.push_back(val); + } + + transformed_type = tc.input_type; EXPECT_TRUE(tr.transform_values(vals, transformed_type, flags)) - << supported_type_msg(original_type, t.second, true); - EXPECT_EQ(original_type, transformed_type); - EXPECT_EQ(vals.size(), test_cases.size()); - - for(uint32_t i = 0; i < test_cases.size(); i++) { - EXPECT_EQ(std::string((const char *)vals[i].ptr), test_cases[i].second) - << eq_test_msg(test_cases[i]); - EXPECT_EQ(vals[i].len, test_cases[i].second.length() + 1) << eq_test_msg(test_cases[i]); + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(vals.size(), tc.expected.size()); + + for(std::vector::size_type i = 0; i < vals.size(); i++) { + std::string actual = (const char*)vals[i].ptr; + std::string expected = (const char*)tc.expected[i].ptr; + EXPECT_EQ(actual, expected) << eq_test_msg(vals[i], tc.expected[i]); + EXPECT_EQ(vals[i].len, tc.expected[i].len) << eq_test_msg(vals[i], tc.expected[i]); } } } -TEST(sinsp_filter_transformer, len_list) { +TEST(sinsp_filter_transformer, len) { sinsp_filter_transformer tr(filter_transformer_type::FTR_LEN); - auto all_types = all_param_types(); + std::set supported_types{PT_CHARBUF, PT_FSPATH, PT_FSRELPATH, PT_BYTEBUF}; + std::set supported_list_types = all_param_types(); - std::vector list_values = {"value 1", "value 2", "value 3", "value 4"}; - std::vector list; + check_unsupported_types(tr, supported_types, supported_list_types); - for(auto &tc : list_values) { - list.push_back(const_str_to_extract_value(tc.c_str())); - } + std::vector test_cases{ + {0, PT_CHARBUF, {{"/home/ubuntu/hello.txt"}}, PT_UINT64, {{22}}}, + {0, PT_FSPATH, {{"/"}}, PT_UINT64, {{1}}}, + {EPF_IS_LIST, PT_FSPATH, {{"/hello"}}, PT_UINT64, {{1}}}, + {EPF_IS_LIST, PT_CHARBUF, {}, PT_UINT64, {{0}}}, + {EPF_IS_LIST, PT_UINT64, {{1}, {2}, {3}, {4}, {5}}, PT_UINT64, {{5}}}, + }; + + for(auto const& tc : test_cases) { + bool is_list = tc.flags & EPF_IS_LIST; + uint32_t flags = tc.flags; + auto transformed_type = tc.input_type; + + EXPECT_TRUE(tr.transform_type(transformed_type, flags)) + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(transformed_type, tc.expected_type); + + std::vector vals{}; + for(auto const& val : tc.input) { + vals.push_back(val); + } + + transformed_type = tc.input_type; + flags = tc.flags; + EXPECT_TRUE(tr.transform_values(vals, transformed_type, flags)) + << supported_type_msg(tc.input_type, is_list, true); + EXPECT_EQ(vals.size(), tc.expected.size()); - auto original_type = PT_CHARBUF; - uint32_t original_flags = EPF_IS_LIST; - auto type = original_type; - auto flags = original_flags; - EXPECT_TRUE(tr.transform_type(type, flags)) << supported_type_msg(original_type, true, true); - EXPECT_EQ(type, PT_UINT64); - EXPECT_EQ(flags & EPF_IS_LIST, 0); - - type = original_type; - flags = original_flags; - auto vals = list; - EXPECT_TRUE(tr.transform_values(vals, type, flags)) - << supported_type_msg(original_type, true, true); - EXPECT_EQ(type, PT_UINT64); - EXPECT_EQ(flags & EPF_IS_LIST, 0); - ASSERT_EQ(vals.size(), 1); - - EXPECT_EQ(extract_value_to_scalar(vals[0]), list_values.size()); - - std::vector empty_list; - type = original_type; - flags = original_flags; - vals = empty_list; - EXPECT_TRUE(tr.transform_values(vals, type, flags)) - << supported_type_msg(original_type, true, true); - EXPECT_EQ(type, PT_UINT64); - EXPECT_EQ(flags & EPF_IS_LIST, 0); - ASSERT_EQ(vals.size(), 1); - - EXPECT_EQ(extract_value_to_scalar(vals[0]), 0); + for(std::vector::size_type i = 0; i < vals.size(); i++) { + uint64_t actual = extract_value_to_scalar(vals[i]); + uint64_t expected = extract_value_to_scalar(tc.expected[i]); + EXPECT_EQ(actual, expected); + } + } } TEST_F(sinsp_with_test_input, basename_transformer) { add_default_init_thread(); open_inspector(); - sinsp_evt *evt; + sinsp_evt* evt; int64_t dirfd = 3; - const char *file_to_run = "/tmp/file_to_run"; + const char* file_to_run = "/tmp/file_to_run"; add_event_advance_ts(increasing_ts(), 1, PPME_SYSCALL_OPEN_E, 3, file_to_run, 0, 0); evt = add_event_advance_ts(increasing_ts(), 1, @@ -356,10 +365,10 @@ TEST_F(sinsp_with_test_input, len_transformer) { add_default_init_thread(); open_inspector(); - sinsp_evt *evt; + sinsp_evt* evt; int64_t dirfd = 3; - const char *file_to_run = "/tmp/file_to_run"; + const char* file_to_run = "/tmp/file_to_run"; evt = add_event_advance_ts(increasing_ts(), 1, @@ -391,4 +400,14 @@ TEST_F(sinsp_with_test_input, len_transformer) { // fd.types = (ipv4,file) EXPECT_TRUE(eval_filter(evt, "len(fd.types) = 2")); + + uint8_t read_buf[] = {'\x01', '\x02', '\x03', '\x04', '\x05', '\x06'}; + evt = add_event_advance_ts(increasing_ts(), + 1, + PPME_SYSCALL_READ_X, + 2, + (int64_t)0, + scap_const_sized_buffer{read_buf, sizeof(read_buf)}); + + EXPECT_TRUE(eval_filter(evt, "len(evt.arg.data) == 6")); }