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

Feature/async #20

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Feature/async #20

wants to merge 4 commits into from

Conversation

teajay-fr
Copy link

This branch adds support for asynchronous expectations.

I think the code is ok now, and ready for comments. If you are interested in this extension let me know I will also extend the documentation.

@mat007
Copy link
Owner

mat007 commented Jan 16, 2016

Hi Thomas and thanks for the PR !

What is the motivation for those changes exactly ?
What would a user test look like e.g. in test_integration.cpp ?
Also how does it fundamentally differ from http://turtle.sourceforge.net/turtle/patterns.html#turtle.patterns.waiting_for_an_asynchronous_call (which I agree could be factorized and packaged a bit better into the library) ?

@teajay-fr
Copy link
Author

The main motivation is to make formulating and checking of asynchronous calls easier. I started out using the construct proposed in the documentation, but it has the drawback that it's a lot more typing than doing something like this:

MOCK_EXPECT(m1).async(milliseconds(100)).once().in(s).with(10).returns(false);

The interesting part is also that you can easily specify timeout values for the calls. In my case I'm testing communication protocols and the timeout handling is a core part of the testing.
You can have a look at the intended use in the test_async.cpp file.

As you can see I'm still fighting a bit to get the modifications I made based on the c++11 standard work on the older standards, but I'll get there soon.

If your interested in the code, I'm willing to take time to adapt anything that doesn't fit !

{
if (timeout_)
{
while (!invocation_->verify())
Copy link
Owner

Choose a reason for hiding this comment

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

Is this blocking until all the expectations are fulfilled or time out ?
What happens for other objects expectations ? Won't they sometimes succeed when they should have timed out ?

Copy link
Author

Choose a reason for hiding this comment

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

Yes. This is the idea. This determine if the objects expectations are met before the time out occurs. If you write that a function is expected to be called twice, then the function would wait for the function to be called twice until the timeout occurs.

Copy link
Owner

Choose a reason for hiding this comment

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

So this can only be used with one expectation because it will block on that expectation ? What if test mock object has two methods with two expectations ?

Copy link
Author

Choose a reason for hiding this comment

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

It didn't have time to work on this earlier. But here is an answer: it also works. As proof you can look in the test_async.cpp file for a demonstration of this.

Every expectation can have a time out value associated with it. The delaying of the execution is done inside the expectation verification.

Copy link
Owner

Choose a reason for hiding this comment

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

What I meant is this will pass whereas it should have failed

BOOST_FIXTURE_TEST_CASE( mock_object_asynchonous_call_expectation_in_sequence, mock_error_fixture )
{
#if defined(MOCK_ASYNC)
    const mock_class m{};
    MOCK_EXPECT( m.my_tag ).async(MOCK_THREAD_NAMESPACE::chrono::milliseconds(50)).once().with( "some parameter" );
    MOCK_EXPECT( m.my_tag ).async(MOCK_THREAD_NAMESPACE::chrono::milliseconds(5)).once().with( "some parameter2" );
    MOCK_THREAD_NAMESPACE::thread context([&](){
        MOCK_THREAD_NAMESPACE::this_thread::sleep_for(MOCK_THREAD_NAMESPACE::chrono::milliseconds(10));
        m.my_method("some parameter");
        m.my_method("some parameter2");
    });
    mock::verify();
    CHECK_CALLS( 2 );
    context.join();
#endif
}

and this will fail whereas it should have succeeded

BOOST_FIXTURE_TEST_CASE( mock_object_asynchonous_call_expectation_in_sequence, mock_error_fixture )
{
#if defined(MOCK_ASYNC)
    const mock_class m{};
    MOCK_EXPECT( m.my_tag ).async(MOCK_THREAD_NAMESPACE::chrono::milliseconds(50)).once().with( "some parameter" );
    MOCK_EXPECT( m.my_tag ).async(MOCK_THREAD_NAMESPACE::chrono::milliseconds(20)).once().with( "some parameter2" );
    MOCK_THREAD_NAMESPACE::thread context([&](){
        MOCK_THREAD_NAMESPACE::this_thread::sleep_for(MOCK_THREAD_NAMESPACE::chrono::milliseconds(10));
        m.my_method("some parameter2");
        MOCK_THREAD_NAMESPACE::this_thread::sleep_for(MOCK_THREAD_NAMESPACE::chrono::milliseconds(20));
        m.my_method("some parameter");
    });
    mock::verify();
    CHECK_CALLS( 2 );
    context.join();
#endif
}

Copy link
Owner

Choose a reason for hiding this comment

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

Well sorry, actually the second one will pass with the current implementation, I was already thinking that first testing the timeout before the expectation completion would not work either.

Copy link
Author

Choose a reason for hiding this comment

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

Ok. I get your point. The difficulty is actually making clear which time reference point is taken for checking the async expectation. I'll try to come up with something.

@mat007
Copy link
Owner

mat007 commented Jan 17, 2016

I'm still struggling to see what a real world use case would look like, would it be something like

struct observer
{
    virtual void started( int status ) = 0; // must be called within 50 ms of starting the computation
    virtual void updated( int progress ) = 0; // must be called in ticks of no more than 10 ms
    virtual void finished( int result ) = 0; // must be called within 2s
};

struct system_under_test
{
    void compute( observer& o ); // returns immediately, performs the computation in a background thread
};

?

@teajay-fr
Copy link
Author

Yes you got the idea. For algorithmic computations, the usefulness of the async construct is not very obvious. It makes much more sense for me, when you want to test communication protocol implementations. For example, if you are writing a client protocol which uses a heartbeat frame to check the link to the server is good, you can test the heartbeat regularity very easily with the construct. This actually one of the case I'm using it for currently. Does this make more sense to you ?

@mat007 mat007 force-pushed the master branch 3 times, most recently from df62e44 to afffdb4 Compare May 30, 2017 14:15
@mat007 mat007 changed the base branch from master to main September 28, 2024 08:56
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.

2 participants