[libcamera-devel,17/18] test: object: Extend object test to verify parent-child relationships

Message ID 20190812124642.24287-18-laurent.pinchart@ideasonboard.com
State Superseded
Headers show
Series
  • Object & Thread enhancements
Related show

Commit Message

Laurent Pinchart Aug. 12, 2019, 12:46 p.m. UTC
The test verifies correct behaviour of parent-child relationships in
relation to thread affinity.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 test/object.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 76 insertions(+), 6 deletions(-)

Comments

Niklas Söderlund Aug. 17, 2019, 3:14 p.m. UTC | #1
Hi Laurent,

Thanks for your work.

On 2019-08-12 15:46:41 +0300, Laurent Pinchart wrote:
> The test verifies correct behaviour of parent-child relationships in
> relation to thread affinity.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

Reviewed-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>

> ---
>  test/object.cpp | 82 +++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 76 insertions(+), 6 deletions(-)
> 
> diff --git a/test/object.cpp b/test/object.cpp
> index 3f1f700d1b39..16118971c755 100644
> --- a/test/object.cpp
> +++ b/test/object.cpp
> @@ -25,8 +25,8 @@ public:
>  		MessageReceived,
>  	};
>  
> -	InstrumentedObject()
> -		: status_(NoMessage)
> +	InstrumentedObject(Object *parent = nullptr)
> +		: Object(parent), status_(NoMessage)
>  	{
>  	}
>  
> @@ -51,22 +51,82 @@ class ObjectTest : public Test
>  protected:
>  	int init()
>  	{
> +		/*
> +		 * Create a hierarchy of objects:
> +		 * A -> B -> C
> +		 *   \->D
> +		 * E
> +		 */
>  		a_ = new InstrumentedObject();
> +		b_ = new InstrumentedObject(a_);
> +		c_ = new InstrumentedObject(b_);
> +		d_ = new InstrumentedObject(a_);
> +		e_ = new InstrumentedObject();
> +		f_ = nullptr;
> +
>  		return TestPass;
>  	}
>  
>  	int run()
>  	{
> -		/* Verify that moving an object to a different thread succeeds. */
> -		a_->moveToThread(&thread_);
> +		/* Verify the parent-child relationships. */
> +		if (a_->parent() != nullptr || b_->parent() != a_ ||
> +		    c_->parent() != b_ || d_->parent() != a_ ||
> +		    e_->parent() != nullptr) {
> +			cout << "Incorrect parent-child relationships" << endl;
> +			return TestFail;
> +		}
>  
> -		if (a_->thread() != &thread_ || a_->thread() == Thread::current()) {
> +		/*
> +		 * Verify that moving an object with no parent to a different
> +		 * thread succeeds.
> +		 */
> +		e_->moveToThread(&thread_);
> +
> +		if (e_->thread() != &thread_ || e_->thread() == Thread::current()) {
>  			cout << "Failed to move object to thread" << endl;
>  			return TestFail;
>  		}
>  
> +		/*
> +		 * Verify that moving an object with a parent to a different
> +		 * thread fails. This results in an undefined behaviour, the
> +		 * test thus depends on the internal implementation returning
> +		 * without performing any change.
> +		 */
> +		b_->moveToThread(&thread_);
> +
> +		if (b_->thread() != Thread::current()) {
> +			cout << "Moving object with parent to thread shouldn't succeed" << endl;
> +			return TestFail;
> +		}
> +
> +		/*
> +		 * Verify that moving an object with children to a different
> +		 * thread moves all the children.
> +		 */
> +		a_->moveToThread(&thread_);
> +
> +		if (a_->thread() != &thread_ || b_->thread() != &thread_ ||
> +		    c_->thread() != &thread_ || d_->thread() != &thread_) {
> +			cout << "Failed to move children to thread" << endl;
> +			return TestFail;
> +		}
> +
> +		/* Verify that objects are bound to the thread of their parent. */
> +		f_ = new InstrumentedObject(d_);
> +
> +		if (f_->thread() != &thread_) {
> +			cout << "Failed to bind child to parent thread" << endl;
> +			return TestFail;
> +		}
> +
>  		/* Verify that objects receive a ThreadMoveMessage when moved. */
> -		if (a_->status() != InstrumentedObject::MessageReceived) {
> +		if (a_->status() != InstrumentedObject::MessageReceived ||
> +		    b_->status() != InstrumentedObject::MessageReceived ||
> +		    c_->status() != InstrumentedObject::MessageReceived ||
> +		    d_->status() != InstrumentedObject::MessageReceived ||
> +		    e_->status() != InstrumentedObject::MessageReceived) {
>  			cout << "Moving object didn't deliver ThreadMoveMessage" << endl;
>  			return TestFail;
>  		}
> @@ -77,10 +137,20 @@ protected:
>  	void cleanup()
>  	{
>  		delete a_;
> +		delete b_;
> +		delete c_;
> +		delete d_;
> +		delete e_;
> +		delete f_;
>  	}
>  
>  private:
>  	InstrumentedObject *a_;
> +	InstrumentedObject *b_;
> +	InstrumentedObject *c_;
> +	InstrumentedObject *d_;
> +	InstrumentedObject *e_;
> +	InstrumentedObject *f_;
>  
>  	Thread thread_;
>  };
> -- 
> Regards,
> 
> Laurent Pinchart
> 
> _______________________________________________
> libcamera-devel mailing list
> libcamera-devel@lists.libcamera.org
> https://lists.libcamera.org/listinfo/libcamera-devel

Patch

diff --git a/test/object.cpp b/test/object.cpp
index 3f1f700d1b39..16118971c755 100644
--- a/test/object.cpp
+++ b/test/object.cpp
@@ -25,8 +25,8 @@  public:
 		MessageReceived,
 	};
 
-	InstrumentedObject()
-		: status_(NoMessage)
+	InstrumentedObject(Object *parent = nullptr)
+		: Object(parent), status_(NoMessage)
 	{
 	}
 
@@ -51,22 +51,82 @@  class ObjectTest : public Test
 protected:
 	int init()
 	{
+		/*
+		 * Create a hierarchy of objects:
+		 * A -> B -> C
+		 *   \->D
+		 * E
+		 */
 		a_ = new InstrumentedObject();
+		b_ = new InstrumentedObject(a_);
+		c_ = new InstrumentedObject(b_);
+		d_ = new InstrumentedObject(a_);
+		e_ = new InstrumentedObject();
+		f_ = nullptr;
+
 		return TestPass;
 	}
 
 	int run()
 	{
-		/* Verify that moving an object to a different thread succeeds. */
-		a_->moveToThread(&thread_);
+		/* Verify the parent-child relationships. */
+		if (a_->parent() != nullptr || b_->parent() != a_ ||
+		    c_->parent() != b_ || d_->parent() != a_ ||
+		    e_->parent() != nullptr) {
+			cout << "Incorrect parent-child relationships" << endl;
+			return TestFail;
+		}
 
-		if (a_->thread() != &thread_ || a_->thread() == Thread::current()) {
+		/*
+		 * Verify that moving an object with no parent to a different
+		 * thread succeeds.
+		 */
+		e_->moveToThread(&thread_);
+
+		if (e_->thread() != &thread_ || e_->thread() == Thread::current()) {
 			cout << "Failed to move object to thread" << endl;
 			return TestFail;
 		}
 
+		/*
+		 * Verify that moving an object with a parent to a different
+		 * thread fails. This results in an undefined behaviour, the
+		 * test thus depends on the internal implementation returning
+		 * without performing any change.
+		 */
+		b_->moveToThread(&thread_);
+
+		if (b_->thread() != Thread::current()) {
+			cout << "Moving object with parent to thread shouldn't succeed" << endl;
+			return TestFail;
+		}
+
+		/*
+		 * Verify that moving an object with children to a different
+		 * thread moves all the children.
+		 */
+		a_->moveToThread(&thread_);
+
+		if (a_->thread() != &thread_ || b_->thread() != &thread_ ||
+		    c_->thread() != &thread_ || d_->thread() != &thread_) {
+			cout << "Failed to move children to thread" << endl;
+			return TestFail;
+		}
+
+		/* Verify that objects are bound to the thread of their parent. */
+		f_ = new InstrumentedObject(d_);
+
+		if (f_->thread() != &thread_) {
+			cout << "Failed to bind child to parent thread" << endl;
+			return TestFail;
+		}
+
 		/* Verify that objects receive a ThreadMoveMessage when moved. */
-		if (a_->status() != InstrumentedObject::MessageReceived) {
+		if (a_->status() != InstrumentedObject::MessageReceived ||
+		    b_->status() != InstrumentedObject::MessageReceived ||
+		    c_->status() != InstrumentedObject::MessageReceived ||
+		    d_->status() != InstrumentedObject::MessageReceived ||
+		    e_->status() != InstrumentedObject::MessageReceived) {
 			cout << "Moving object didn't deliver ThreadMoveMessage" << endl;
 			return TestFail;
 		}
@@ -77,10 +137,20 @@  protected:
 	void cleanup()
 	{
 		delete a_;
+		delete b_;
+		delete c_;
+		delete d_;
+		delete e_;
+		delete f_;
 	}
 
 private:
 	InstrumentedObject *a_;
+	InstrumentedObject *b_;
+	InstrumentedObject *c_;
+	InstrumentedObject *d_;
+	InstrumentedObject *e_;
+	InstrumentedObject *f_;
 
 	Thread thread_;
 };