Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Complete rcutils API coverage #272

Merged
merged 20 commits into from
Aug 7, 2020
Merged

Complete rcutils API coverage #272

merged 20 commits into from
Aug 7, 2020

Conversation

hidmic
Copy link
Contributor

@hidmic hidmic commented Jul 28, 2020

Precisely what the title says, filling the gaps with mocks. Depends on ros2/Mimick#7.

@hidmic
Copy link
Contributor Author

hidmic commented Jul 28, 2020

This isn't PR material just yet, but I wanted to open it early enough for folks to take a look at how tests are looking like, and, ideally, compare it side-by-side with @brawner's fault injection tooling. There are cases that definitely suit mocking conceptually (e.g. dealing with bad system clocks), others not so much (e.g. failing a finalization).

@hidmic hidmic force-pushed the hidmic/mock-system-calls branch 3 times, most recently from 4233dee to c9d722a Compare July 29, 2020 21:47
@hidmic
Copy link
Contributor Author

hidmic commented Jul 29, 2020

Total coverage is over 95%, but there're places where it is still below that mark. Those places were left out on purpose, and can be split into three (3) groups:

  • Those that can still be tested without mocking (e.g. using a bad allocator).
  • Those that I think are good candidates for fault injection (e.g. typical cascading errors during finalization).
  • Those that I think could use a revisit e.g. the use of an rcutils_string_map_t in logging.c to track logger severity levels adds failure points plus allocations/deallocation cycles on every log for no obvious reason.

@hidmic hidmic marked this pull request as ready for review July 29, 2020 22:46
@hidmic hidmic requested review from brawner and Blast545 July 29, 2020 22:46
src/char_array.c Outdated Show resolved Hide resolved
src/char_array.c Outdated Show resolved Hide resolved
test/mocking_utils.hpp Outdated Show resolved Hide resolved
#if !defined(_WIN32)
#if defined(__MACH__)

class fake_clock : unique_in_scope<fake_clock>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fake_* isn't a very helpful naming style for all these classes. What about rcutils_mock_* or something that helps people get where it's coming from and what its use is?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being an internal testing tool, I didn't see the need to standardize their names. But moving them out into rcpputils we have to.

test/mocking_utils.hpp Outdated Show resolved Hide resolved

#else // defined(__MACH__)

class fake_clock : unique_in_scope<fake_clock>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but the only difference between these same class definitions is that do_clock_get_time returns a kern_return_t vs an int? Can you consolidate these differencese to a much smaller #if defined block to reduce duplicated code? I think some of the other classes can be consolidated in a similar way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you consolidate these differences to a much smaller #if defined block to reduce duplicated code?

In this particular case, yes we can. A few using directives can go a long way here.

In general, all "equivalent" classes can be consolidated into one, but in some cases I think interleaving all platform-specific details works against readability and thus I tend to split.

test/mocking_utils.hpp Outdated Show resolved Hide resolved
test/test_char_array.cpp Outdated Show resolved Hide resolved
test/test_format_string.cpp Outdated Show resolved Hide resolved
CMakeLists.txt Show resolved Hide resolved
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
@hidmic hidmic requested a review from brawner August 4, 2020 23:10
@hidmic
Copy link
Contributor Author

hidmic commented Aug 4, 2020

@Blast545 @brawner PTAL at 9e004d7, as it completely revamps how mocks are made using generic C++ code.

Copy link
Contributor

@Blast545 Blast545 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work what you did here to improve Mimick's usage! Left a couple of minor comments to consider before merging

test/test_time.cpp Outdated Show resolved Hide resolved
test/test_time.cpp Show resolved Hide resolved
test/test_time.cpp Outdated Show resolved Hide resolved
test/test_filesystem.cpp Show resolved Hide resolved
fs.file_info(path).st_mode |= mocking_utils::filesystem::FileTypes::DIRECTORY;
fs.exhaust_file_descriptors();
size = rcutils_calculate_directory_size(path, g_allocator);
EXPECT_EQ(0u, size);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be checked here as well the output from the error or errno? saw the rcutils_calculate_directory_size code and it's printed with fprintf to stderr, should that be changed to rcutils_set_error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could, but I'd keep changes to rcutils implementation out of this PR. Same as before.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, I can help you opening an enhancement issue targeting that if you'd like.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
@hidmic
Copy link
Contributor Author

hidmic commented Aug 5, 2020

CI up to rcutils:

  • Linux Build Status
  • Linux-aarch64 Build Status
  • macOS Build Status
  • Windows Build Status

};

template<size_t N>
class FileSystem
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know it's a bit subjective and I suggested the opposite on a different file, but this class doesn't seem to reuse much code across #ifdef blocks. Since it's the filesystem and each OS handles it differently, I think this file makes sense define the full class in single ifdef blocks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See 83140ec.

mmk_mock_define(mock_type, ReturnType);
};

template<size_t N, typename ReturnType, typename ArgType0>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it not possible to use a parameter pack like you do the trampoline struct for the mmk_mock_define calls? I'm not familiar with parameter packs, but I'm guessing you would have used them if it were actually possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not because mmk_mock_define is a macro that needs all the parameter types given as separate arguments at the preprocessing stage -- it won't play along with parameter packs.

///
/// Useful to enable patching functions that take arguments whose types
/// do not define basic comparison operators required by Mimick.
#define MOCKING_UTILS_DEFINE_DUMMY_OPERATOR(type, op) \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest: MOCKING_UTILS_BOOL_OPERATOR_RETURNS_FALSE

Just so when people see it in code, it's a bit clearer what this macro is doing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See 83140ec.

@@ -19,6 +19,7 @@
#include "rcutils/error_handling.h"
#include "rcutils/split.h"
#include "rcutils/types/string_array.h"
#include "rcutils/types/char_array.h"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix ordering

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That include actually shouldn't be there! It's a leftover, removed in 46a4c15.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Copy link
Contributor

@brawner brawner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Just a few minor comments.

explicit FileSystem(const std::string & scope)
: opendir_mock_(MOCKING_UTILS_PATCH_TARGET(scope, opendir),
MOCKING_UTILS_PATCH_PROXY(opendir)),
#ifndef _GNU_SOURCE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also seems like a good candidate for combining with the ifndef block at line 88 below. Line 87 is the only line shared between the two cases.

@@ -201,6 +203,21 @@ TEST_F(TestFilesystemFixture, is_readable) {
ASSERT_FALSE(nullptr == path);
EXPECT_FALSE(rcutils_is_readable(path));
}
{
char * path = rcutils_join_path(this->test_path, "dummy_nonexisting_file.txt", g_allocator);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
char * path = rcutils_join_path(this->test_path, "dummy_nonexisting_file.txt", g_allocator);
char * path = rcutils_join_path(this->test_path, "dummy_nonexistent_file.txt", g_allocator);

}
{
auto fs = mocking_utils::patch_filesystem("lib:rcutils");
const char * path = "dummy_non_readable_file.txt";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const char * path = "dummy_non_readable_file.txt";
const char * path = "dummy_unreadable_file.txt";

@@ -232,6 +249,12 @@ TEST_F(TestFilesystemFixture, is_writable) {
ASSERT_FALSE(nullptr == path);
EXPECT_FALSE(rcutils_is_writable(path));
}
{
auto fs = mocking_utils::patch_filesystem("lib:rcutils");
const char * path = "dummy_non_writable_file.txt";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const char * path = "dummy_non_writable_file.txt";
const char * path = "dummy_unwritable_file.txt";

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
@hidmic
Copy link
Contributor Author

hidmic commented Aug 5, 2020

Well, it appears that there's something very peculiar about how va_list is implemented in aarch64. I don't know what the compiler is doing behind the hood, but the type does not define comparison operators nor it allows overloading such operators. As a result, functions taking va_list arguments are off the table in this platform 🙁

I'll exclude the tests that mock vsnprintf in this platform.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
@hidmic
Copy link
Contributor Author

hidmic commented Aug 6, 2020

Oh well, vsnprintf mocking only works on Linux x86-64: binary APIs on MacOS and Windows are inaccessible and undocumented respectively, and the va_list type on Linux aarch64 won't play along with Mimick.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
@hidmic
Copy link
Contributor Author

hidmic commented Aug 7, 2020

Alright, finally all green. @brawner @Blast545 PTAL!

@hidmic hidmic requested review from Blast545 and brawner August 7, 2020 18:43
@hidmic
Copy link
Contributor Author

hidmic commented Aug 7, 2020

Alright, thanks for the reviews guys!

@hidmic hidmic merged commit ee883ab into master Aug 7, 2020
@hidmic hidmic deleted the hidmic/mock-system-calls branch August 7, 2020 19:42
@ivanpauno
Copy link
Member

ivanpauno commented Aug 10, 2020

I'm not completely sure if this PR is the root cause, but there are a bunch of new test failures on the nightlies https://ci.ros2.org/view/nightly/job/nightly_linux_release/1633/ (all related to rcutils tests).

@hidmic
Copy link
Contributor Author

hidmic commented Aug 10, 2020

Indeed. Looks like another corner case when mocking vsnprintf... Looking.

@dirk-thomas
Copy link
Member

dirk-thomas commented Aug 10, 2020

I'm not completely sure if this PR is the root cause, but there are a bunch of new test failures on the nightlies

Since most of them started 3 days ago (see https://ci.ros2.org/view/nightly/job/nightly_linux_extra_rmw_release/797/testReport/ and https://ci.ros2.org/view/nightly/job/nightly_linux_thread_sanitizer/504/testReport/) I would think so.

@hidmic
Copy link
Contributor Author

hidmic commented Aug 10, 2020

Fix PR'd in #274.

ahcorde pushed a commit that referenced this pull request Oct 2, 2020
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
ahcorde pushed a commit that referenced this pull request Oct 6, 2020
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants