[PATCH 09/12] test: timer-thread: Move timer start from wrong thread to separate test

Milan Zamazal mzamazal at redhat.com
Mon Jan 22 21:17:56 CET 2024


Laurent Pinchart <laurent.pinchart at ideasonboard.com> writes:

> Starting a timer from the wrong thread is expected to fail, and we test
> this in the timer-thread unit test. This is however not something that a
> caller is allowed to do, and libcamera will get assertion failures to
> catch this invalid usage. The unit test will then fail.
>
> To prepare for this, split the unit test in two, with a test that is
> expected by meson to succeed, and one that is expected to fail. The
> assertion will then cause an expected failure, making the test suite
> succeed.

What if the tests crashes for an unrelated reason?  Is it possible to
distinguish between the "right" error and an unexpected error?

> Signed-off-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> ---
>  test/meson.build      |   9 ++--
>  test/timer-fail.cpp   | 101 ++++++++++++++++++++++++++++++++++++++++++
>  test/timer-thread.cpp |  22 ---------
>  3 files changed, 107 insertions(+), 25 deletions(-)
>  create mode 100644 test/timer-fail.cpp
>
> diff --git a/test/meson.build b/test/meson.build
> index 189e1428485a..8b6057d4e800 100644
> --- a/test/meson.build
> +++ b/test/meson.build
> @@ -69,6 +69,7 @@ internal_tests = [
>      {'name': 'signal-threads', 'sources': ['signal-threads.cpp']},
>      {'name': 'threads', 'sources': 'threads.cpp', 'dependencies': [libthreads]},
>      {'name': 'timer', 'sources': ['timer.cpp']},
> +    {'name': 'timer-fail', 'sources': ['timer-fail.cpp'], 'should_fail': true},
>      {'name': 'timer-thread', 'sources': ['timer-thread.cpp']},
>      {'name': 'unique-fd', 'sources': ['unique-fd.cpp']},
>      {'name': 'utils', 'sources': ['utils.cpp']},
> @@ -91,7 +92,7 @@ foreach test : public_tests
>                       link_with : test_libraries,
>                       include_directories : test_includes_public)
>  
> -    test(test['name'], exe)
> +    test(test['name'], exe, should_fail : test.get('should_fail', false))
>  endforeach
>  
>  foreach test : internal_tests
> @@ -105,7 +106,7 @@ foreach test : internal_tests
>                       link_with : test_libraries,
>                       include_directories : test_includes_internal)
>  
> -    test(test['name'], exe)
> +    test(test['name'], exe, should_fail : test.get('should_fail', false))
>  endforeach
>  
>  foreach test : internal_non_parallel_tests
> @@ -119,5 +120,7 @@ foreach test : internal_non_parallel_tests
>                       link_with : test_libraries,
>                       include_directories : test_includes_internal)
>  
> -    test(test['name'], exe, is_parallel : false)
> +    test(test['name'], exe,
> +         is_parallel : false,
> +         should_fail : test.get('should_fail', false))
>  endforeach
> diff --git a/test/timer-fail.cpp b/test/timer-fail.cpp
> new file mode 100644
> index 000000000000..e9a3b1b61bcb
> --- /dev/null
> +++ b/test/timer-fail.cpp
> @@ -0,0 +1,101 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2024, Ideas on Board Oy
> + *
> + * timer-fail.cpp - Threaded timer failure test
> + */
> +
> +#include <chrono>
> +#include <iostream>
> +
> +#include <libcamera/base/event_dispatcher.h>
> +#include <libcamera/base/object.h>
> +#include <libcamera/base/thread.h>
> +#include <libcamera/base/timer.h>
> +
> +#include "test.h"
> +
> +using namespace libcamera;
> +using namespace std;
> +using namespace std::chrono_literals;
> +
> +class TimeoutHandler : public Object
> +{
> +public:
> +	TimeoutHandler()
> +		: timer_(this), timeout_(false)
> +	{
> +		timer_.timeout.connect(this, &TimeoutHandler::timeoutHandler);
> +	}
> +
> +	void start()
> +	{
> +		timer_.start(100ms);
> +	}
> +
> +	bool timeout() const
> +	{
> +		return timeout_;
> +	}
> +
> +private:
> +	void timeoutHandler()
> +	{
> +		timeout_ = true;
> +	}
> +
> +	Timer timer_;
> +	bool timeout_;
> +};
> +
> +class TimerFailTest : public Test
> +{
> +protected:
> +	int init()
> +	{
> +		thread_.start();
> +		timeout_.moveToThread(&thread_);
> +
> +		return TestPass;
> +	}
> +
> +	int run()
> +	{
> +		/*
> +		 * Test that the forbidden operation of starting the timer from
> +		 * another thread results in a failure. We need to interrupt the
> +		 * event dispatcher to make sure we don't succeed simply because
> +		 * the event dispatcher hasn't noticed the timer restart.
> +		 */
> +		timeout_.start();
> +		thread_.eventDispatcher()->interrupt();
> +
> +		this_thread::sleep_for(chrono::milliseconds(200));
> +
> +		/*
> +		 * Meson expects this test to fail, so we need to return

It'd be good to mention here that it's expected to fail on an assertion.

> +		 * TestPass in the unexpected (usually known as "fail"), case,
> +		 * and TestFail otherwise.
> +		 */
> +		if (timeout_.timeout()) {
> +			cout << "Timer start from wrong thread succeeded unexpectedly"
> +			     << endl;
> +			return TestPass;
> +		}
> +
> +		return TestFail;
> +	}
> +
> +	void cleanup()
> +	{
> +		/* Must stop thread before destroying timeout. */
> +		thread_.exit(0);
> +		thread_.wait();
> +	}
> +
> +private:
> +	TimeoutHandler timeout_;
> +	Thread thread_;
> +};
> +
> +TEST_REGISTER(TimerFailTest)
> diff --git a/test/timer-thread.cpp b/test/timer-thread.cpp
> index 0bcd0d8ce194..4caf4e33b2ba 100644
> --- a/test/timer-thread.cpp
> +++ b/test/timer-thread.cpp
> @@ -29,12 +29,6 @@ public:
>  		timer_.start(100ms);
>  	}
>  
> -	void restart()
> -	{
> -		timeout_ = false;
> -		timer_.start(100ms);
> -	}
> -
>  	bool timeout() const
>  	{
>  		return timeout_;
> @@ -74,22 +68,6 @@ protected:
>  			return TestFail;
>  		}
>  
> -		/*
> -		 * Test that starting the timer from another thread fails. We
> -		 * need to interrupt the event dispatcher to make sure we don't
> -		 * succeed simply because the event dispatcher hasn't noticed
> -		 * the timer restart.
> -		 */
> -		timeout_.restart();
> -		thread_.eventDispatcher()->interrupt();
> -
> -		this_thread::sleep_for(chrono::milliseconds(200));
> -
> -		if (timeout_.timeout()) {
> -			cout << "Timer restart test failed" << endl;
> -			return TestFail;
> -		}
> -
>  		return TestPass;
>  	}



More information about the libcamera-devel mailing list