-
Notifications
You must be signed in to change notification settings - Fork 403
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
iox-#1099 Separate test part from ErrorHandler
and call errorHandler()
in iceoryx_hoofs
only once
#1100
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1100 +/- ##
==========================================
+ Coverage 78.93% 78.95% +0.01%
==========================================
Files 370 371 +1
Lines 14705 14683 -22
Branches 2059 2051 -8
==========================================
- Hits 11608 11593 -15
+ Misses 2417 2415 -2
+ Partials 680 675 -5
Flags with carried forward coverage won't be shown. Click here to find out more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please squash or reorder and squash some commits and revert some changes by dropping some commits like:
- Update copyright header, this really clutters our git history.
- The last two one liner commits.
Please create one commit here instead of 4 and add the copyright year findings to it.
I suggest to squash and drop the commits as a first step. After you done this we can go to the next review stage where you try to avoid rebasing/push force so that all the reviewers see only the changes. But lets start with a more or less clean git history and when it clutters up in the later review process then just let it clutter up.
CONTRIBUTING.md
Outdated
@@ -110,8 +110,8 @@ codebase follows these rules, things are work in progress. | |||
our code may contain additions which are not compatible with the STL (e.g. `iox::cxx::vector::emplace_back()` | |||
does return a bool) | |||
7) **Always use `iox::log::Logger`**, instead of `printf()` | |||
8) **Always use `iox::ErrorHandler()`**, when an error occurs that cannot or shall not be propagated via an | |||
`iox::cxx::expected`, the `iox::ErrorHandler()` shall be used; exceptions are not allowed | |||
8) **Always use `iox::ErrorHandler()` or `cxx::Expects`/`cxx::Ensures`**, when an error occurs that cannot or shall not be propagated via an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion this will be very soon outdated when the low level error handler becomes also available for iceoryx hoofs. Then it would make sense to never use cxx::Expects
/ cxx::Ensures
(even when they use the error handler behind the scenes).
I would state here right from the beginning: always use the iox::ErrorHandler
since we can emit an error code here which can be important for later bug reports or debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think having indivual error codes in iceoryx hoofs (e.g. when a vector capacity is exceeded) is a good idea. In my opinion this does not belong into a generic library. We should use a generic hoofs error category (or categories, exception like).
Regardless, this is for another time and we should state how the handling is currently intended, even if it will change in the (near) future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it makes sense to use errorHandler()
in iceoryx_hoofs
building blocks. IMHO it's more idiomatic and closer to a library philosophy to use Expects
/ Ensures
and allow the users to call the errorHandler()
inside Expects
/ Ensures
(or throw
or std::terminate
).
However, we should not discuss this here, that's something for #1032
The goal for v2.0
is to decouple iceoryx_posh
and iceoryx_binding_c
from iceoryx_hoofs
as an intermediate step. Hence, the description above is still valid.
@@ -17,6 +17,8 @@ | |||
#ifndef IOX_DDS_GATEWAY_TEST_TEST_HPP | |||
#define IOX_DDS_GATEWAY_TEST_TEST_HPP | |||
|
|||
#include "iceoryx_hoofs/testing/mocks/error_handler_mock.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we actually require an error handler mock? We can always set a temporary error handler and check if it was called with the correct arguments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I had the same observation in the previous PR. I do not think we require a mock or it is actually a mock, we just want to change to a different ErrorHandler for the tests (which is one reason to have a configurable ErrorHandler) . It somehow looks like a design flaw or I do not understand it correctly.
Should at least be considered in another refactoring pass.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ErrorHandlerMock
contains call code which is only needed in test code. Now, ErrorHandler
on the other hand, contains the code needed during runtime of an iceoryx system and is not cluttered with test-only code anymore. The templatization of setTemporaryErrorHandler
is necessary to provide a user friendly way to use a different error enums for each module (posh, C binding).
iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp
Outdated
Show resolved
Hide resolved
std::cerr << "\033[5;31m" | ||
<< "Could not open file '" << m_file << "'. Exiting!" | ||
<< "\033[0m" << std::endl; | ||
cxx::Ensures(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we will most likely use the error handler in the complete code base, why not use it here with a newly created enum to spare us some future work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would not do this in the scope of this PR since the concept is still not fully clear. Just cause no regression compared to previous code.
Reason: Global error handling cannot be applied if the user is supposed to somehow configure the error handling of FileReader
individually (i.e. decoupled from the global error handling). And if it is just the terminate case Ensures
is sufficient for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I disagree with using the errorHandler()
directly in iceoryx_hoofs
. See this comment for the background. That's something to be discussed in #1032. For v2.0
I would like to implement our current error handling strategy as described in doc/design/error-handling.md
to have a consistent code base.
errorHandler(Error::kPOSIX_TIMER__INCONSISTENT_STATE); | ||
return; | ||
} | ||
cxx::Expects((handle.m_timer != nullptr) && "Timer in inconsistent state"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the error handler here and in all remaining files where you added an cxx::Expects
/ cxx::Ensures
or where you removed the errorHandler
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disagree. The entire point AFAIK is not to use the error handler in hoofs directly (and I agree with this). Expects
may call or may not call it, this is implementation specific.
On another note Expects
is just a runtime assert in its most basic form and I do not really see a reason to not name it Assert
as we cannot use it as a true precondition check (enforced as a contract!) as the standard says https://doc.bccnsoft.com/docs/cppreference2018/en/cpp/language/attributes/contract.html (same with Ensures
). To do so we need compiler support which we do not have (i.e. we cannot implement this in with C++17 alone).
Whenever something like this is checked in the function body it is an assert (as per the standard) and I would not deviate from this (as it has no point and just causes confusion).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rejected, quote from doc/design/error-handling.md
:
The error handler cannot be used in hoofs.
See this comment for the background an my opinion. For v2.0
I would like to implement our current error handling strategy.
I'm happy to discuss changes to the error handling strategy in #1032 for v3.0
.
std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT.toMilliseconds() * 10)); | ||
TIMING_TEST_EXPECT_FALSE(hasTerminated); | ||
// EXPECT_NO_DEATH | ||
EXPECT_TRUE(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert the changes (in whole file). cxx::Expects
/ cxx::Ensures
are calling the error handler and terminate the program. When this test fails the whole test is terminated and the user is wondering what happened.
If possible, a unit test should never die! We always want a list of all the failing unit tests with the condition/code line which failed - this test setup makes this impossible since we do not know if the test failed or some segfault occurred.
Please do this by dropping the commit otherwise we clutter or history with changes which actually never happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be able to exchange the error handling to some specific test handling where we do not terminate but indicate that an error occurred instead ... If this is not possible right now (why not?) it needs to be possible in the future at least (and a todo added).
Furthermore if the test success is determined at some point we should use SUCCEED()
.
But I thought we will get rid of the POSIX timer which would make all this a non-issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, DEATH_TESTS
should be avoided. However, this is an intermediate step as the posix::Timer
and its tests will be removed before v2.0
e.g. by finishing off #754 or re-implementing it from scratch.
@@ -0,0 +1,81 @@ | |||
// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need it and cannot use the setTemporaryErrorHandler
?
Please drop this change from the history as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, the ErrorHandler
is free from any test code, see more in my previous comment.
@mossmaurice can't promise to look at this anytime soon since I'm quite busy with the request-response feature |
068001c
to
258bbcd
Compare
258bbcd
to
907ad93
Compare
bc69ced
to
0f40aea
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good in general. I'm just not sure about the new death tests, since the make problems on macOS
class ErrorHandlerMock : protected ErrorHandler | ||
{ | ||
public: | ||
template <typename Error> | ||
static cxx::GenericRAII setTemporaryErrorHandler(const TypedHandlerFunction<Error>& newHandler) noexcept; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of having to call a function, why not make this the ctor?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be possible. However, using setTemporaryErrorHandler()
in tests is more meaningful for me. I use a mock and call a method to set a certain behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me it is the oposite. It's like with the std::lock
. One creates the object and let it's dtor do everything.
iceoryx_hoofs/include/iceoryx_hoofs/error_handling/error_handling.hpp
Outdated
Show resolved
Hide resolved
1ae5fd0
to
386f5c0
Compare
Let's delete the |
d0d769e
to
c7a6cb4
Compare
…ler() calls from hoofs Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
…le 'handler' Signed-off-by: Simon Hoinkis <[email protected]>
…with errorHandler() Signed-off-by: Simon Hoinkis <[email protected]>
…void problems in tests Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
…osh_testing Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
… unexpected error enum type in error handler Signed-off-by: Simon Hoinkis <[email protected]>
… todo Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
… in .inl Signed-off-by: Simon Hoinkis <[email protected]>
… includes Signed-off-by: Simon Hoinkis <[email protected]>
c7a6cb4
to
6f8560e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok in general for the purpose of separating the error handling but we need to rethink some of the error handling in another issue. I also think ErrorHandlerMock is the wrong name, it is the TestErrorHandler
or something like this.
What happened to typed_unique_id.hpp
?
CONTRIBUTING.md
Outdated
@@ -110,8 +110,8 @@ codebase follows these rules, things are work in progress. | |||
our code may contain additions which are not compatible with the STL (e.g. `iox::cxx::vector::emplace_back()` | |||
does return a bool) | |||
7) **Always use `iox::log::Logger`**, instead of `printf()` | |||
8) **Always use `iox::ErrorHandler()`**, when an error occurs that cannot or shall not be propagated via an | |||
`iox::cxx::expected`, the `iox::ErrorHandler()` shall be used; exceptions are not allowed | |||
8) **Always use `iox::ErrorHandler()` or `cxx::Expects`/`cxx::Ensures`**, when an error occurs that cannot or shall not be propagated via an |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think having indivual error codes in iceoryx hoofs (e.g. when a vector capacity is exceeded) is a good idea. In my opinion this does not belong into a generic library. We should use a generic hoofs error category (or categories, exception like).
Regardless, this is for another time and we should state how the handling is currently intended, even if it will change in the (near) future.
@@ -17,6 +17,8 @@ | |||
#ifndef IOX_DDS_GATEWAY_TEST_TEST_HPP | |||
#define IOX_DDS_GATEWAY_TEST_TEST_HPP | |||
|
|||
#include "iceoryx_hoofs/testing/mocks/error_handler_mock.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I had the same observation in the previous PR. I do not think we require a mock or it is actually a mock, we just want to change to a different ErrorHandler for the tests (which is one reason to have a configurable ErrorHandler) . It somehow looks like a design flaw or I do not understand it correctly.
Should at least be considered in another refactoring pass.
// We undo the type erasure | ||
auto typedError = static_cast<ErrorEnumType>(error); | ||
typedHandler<iox::Error>.and_then( | ||
[&](TypedHandlerFunction<Error> storedHandler) { storedHandler(typedError, level); }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it a storedHandler
though? At this point it is merely a passed argument, nor will it be stored (so maybe only handler
). Furthermore we pass by value here, is this a good idea/necessary since we call the function right away and are done. Could we encounter a dangling reference? If so, is it due to bad design or unavoidable or a misuse?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the handler is stored inside typedHandler
. If the cxx::optional
contains a value, this handler is invoked. It is not possible to encounter a dangling reference, as the resetting is done via a cxx::GenericRAII
. Misuse is therefore very low. Semantically there is no change to before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, but I mean in the context of the lambda it is meaningless whether it is/was stored or not so I would have dropped this from the name (it does not help clarity, it just adds confusion IMO).
But it is a small scope so I do not care too much.
iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp
Outdated
Show resolved
Hide resolved
|
||
namespace iox | ||
{ | ||
std::mutex ErrorHandlerMock::handler_mutex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this snake case break with our (local) conventions or is there more of a purpose?
I prefer snake case for certain library abstractions but not variables like this one, unless all variables in the module follow this convention.
But more importantly, it is a global variable in the iox namespace but is actually something specific to error handling. We should try to avoid polluting the iox namespace with this. If we cannot avoid the global mutex (can we confine it to some class as a static?) maybe it should live in something like iox::error_handling::detail
.
The convention being that the any detail
namespace is certainly not to be accessed by the user (even if it can be accessed to write a global variable like this one).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed the snake case naming. We can think about wrapping parts of the error_handling
in objects in an extra namespace. For me this not an important topic, as the class is already separate in a testing package. Hence, not a big deal for me.
Agree, that will happen as part of #1032.
|
Signed-off-by: Simon Hoinkis <[email protected]>
Signed-off-by: Simon Hoinkis <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please remove the empty typed_unique_id.hpp
class ErrorHandlerMock : protected ErrorHandler | ||
{ | ||
public: | ||
template <typename Error> | ||
static cxx::GenericRAII setTemporaryErrorHandler(const TypedHandlerFunction<Error>& newHandler) noexcept; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me it is the oposite. It's like with the std::lock
. One creates the object and let it's dtor do everything.
inline void errorHandlerForTest(const uint32_t error, const char* errorName, const ErrorLevel level) noexcept | ||
{ | ||
uint32_t errorEnumType = error >> 16; | ||
uint32_t expectedErrorEnumType = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this just be 0
with a comment why it currently 0 and what will change?
iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp
Show resolved
Hide resolved
iceoryx_hoofs/testing/include/iceoryx_hoofs/testing/mocks/error_handler_mock.hpp
Show resolved
Hide resolved
@elBoberido It's already removed, maybe just harder to catch in GitHub web GUI due to being empty. |
Pre-Review Checklist for the PR Author
iox-#123-this-is-a-branch
)iox-#123 commit text
)git commit -s
)task-list-completed
)Notes for Reviewer
ErrorHandler
and templatizesetTemporaryErrorHandler(..)
errorHandler(..)
only once iniceoryx_hoofs
inExpects
/Ensures
Checklist for the PR Reviewer
Post-review Checklist for the PR Author
References
iceoryx_hoofs
#1099 (partly)