<commit_before>#include <gtest/gtest.h>
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <move_basic/queued_action_server.h>
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

class GoalQueueSuite : public ::testing::Test {
protected:
	virtual void SetUp() {
		resetFlags();
		ros::NodeHandle actionNh("");
		qserv.reset(new actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> (actionNh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)));
		cli.reset(new actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> ("queue_server", true)); // true -> don't need ros::spin()

		qserv->start();
	}

	virtual void TearDown() {
		// Kill the executeCallback if it is running
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); // Releases one waiting thread
		}
		qserv->shutdown();
	}

	void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg) {
		resetFlags();
		got_goal = true;
		received_goal = msg;
		while (true) {
			goal_preempted = qserv->isPreemptRequested() ? true : false;
			next_goal_available = qserv->isNewGoalAvailable() ? true : false;

			// Test fixture can continue
			execution = true;
			sleep_cv.notify_one();
			// Wait until signalled to end
			std::unique_lock<std::mutex> lk(execute_lock);
			execute_cv.wait(lk,
				//lambda function to wait on our bool variables
				[this](){return finish_executing || resume_executing;} // blocks only if lambda returns false
			);
			execution = false;
			// We were requested to stop, so we stop
			if (finish_executing) {
				break;
			}
		}

		// Signal that we are done here
		std::lock_guard<std::mutex> lk(execute_done_lock);
		execute_done = true;
		execute_done_cv.notify_all();
	}

	// Helper function to signal the executeCallback to end
	void finishExecuting() {
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); //unlocks lambda waiting function in ExecuteCallback
		}

		// Wait for execute callback to actually finish
		std::unique_lock<std::mutex> lk2(execute_done_lock);
		execute_done_cv.wait(lk2, [this]() {return execute_done;}); // at the end of ExecuteCallback
	}

	// Helper function to signal the executeCallback to resume
	// This is useful for seeing if the callback code sees a preempt
	void resumeExecuting() {
		std::lock_guard<std::mutex> lk(execute_lock);
		resume_executing = true;
		execute_cv.notify_one();
	}

	// Helper function to wait to for flags to update in ExecuteCallback
	void sleepExecuting() {
		std::unique_lock<std::mutex> slk(sleep_lock);
		sleep_cv.wait(slk,
				[this](){return execution;}
			);
	}

	void resetFlags() {
		got_goal = false;
		goal_preempted = false;
		next_goal_available = false;
		received_goal = nullptr;

		// Signal flags
		execution = false;
		finish_executing = false;
		resume_executing = false;
		execute_done = false;
	}

	// Flags for assertions
	bool got_goal;
	bool goal_preempted;
	bool next_goal_available;
	move_base_msgs::MoveBaseGoalConstPtr received_goal;

	// Signaling variables
	bool execution;
	bool finish_executing;
	bool resume_executing;
	bool execute_done;
	std::mutex sleep_lock;
	std::mutex execute_lock;
	std::mutex execute_done_lock;
	std::condition_variable sleep_cv;
	std::condition_variable execute_cv;
	std::condition_variable execute_done_cv;

	std::unique_ptr<actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction>> qserv;
	std::unique_ptr<actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>> cli;
};

TEST_F(GoalQueueSuite, establishDuplex) {
	move_base_msgs::MoveBaseGoal goal;

	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();

 	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_FALSE(goal_preempted);
	EXPECT_FALSE(next_goal_available);
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);
	finishExecuting();
	ros::Duration(0.5).sleep();
	EXPECT_FALSE(qserv->isActive());
}

TEST_F(GoalQueueSuite, addGoalWhileExecuting) {
	move_base_msgs::MoveBaseGoal goal;

	// First goal
	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_FALSE(goal_preempted);
	EXPECT_FALSE(next_goal_available);
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Second goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();

	resumeExecuting();
	ros::Duration(0.5).sleep();
	sleepExecuting();
 	EXPECT_TRUE(next_goal_available);

	// Cancel the last goal sent
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x); // Making sure we are in the first goal thread
 	finishExecuting(); // Finish 1st goal
	ros::Duration(0.5).sleep();
	EXPECT_TRUE(goal_preempted);
 	finishExecuting(); // Finish 2nd (canceled) goal
	ros::Duration(0.5).sleep();

	// New goal
	goal.target_pose.pose.position.x = 13.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_FALSE(goal_preempted);
	EXPECT_EQ(13.0, received_goal->target_pose.pose.position.x);
	finishExecuting(); // Finish new goal

// 	- if another goal is received add it to the queue (DONE)
// 	- if the queue full, set the next goal as preempted - explicitly called! - so cancelling the next goal and adding new to the queue
// 	- start executing the new goal in queue (after the current)
}

/*
TEST_F(GoalQueueSuite, goalPreempting) {
	move_base_msgs::MoveBaseGoal goal;

	// One goal -> Cancel request -> Stop
	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	cli->cancelGoal();
	ros::spinOnce();
	resumeExecuting();
	// ros::spinOnce();
	sleepExecuting();
	// ASSERT_TRUE(goal_preempted);
	finishExecuting(); // Finish the goal
	ros::spinOnce();
	sleepExecuting();
// 	ASSERT_FALSE(qserv->isActive());

	// Two goals -> Cancel current goal -> Start executing the second
	// First goal
	cli->sendGoal(goal);
	ros::spinOnce();

	sleepExecuting();
	// ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Cancelling the first goal - PITFALL
	cli->cancelGoal();
	ros::spinOnce();
	resumeExecuting();
	sleepExecuting();
	// ros::spinOnce();
	// ASSERT_TRUE(goal_preempted);
	// Finish the preempted goal
	finishExecuting(); // Finish 1st goal

	// "Second" goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();

	sleepExecuting();
	ASSERT_TRUE(got_goal);
	// ASSERT_EQ(7.0, received_goal->target_pose.pose.position.x); // call FINISH!
	finishExecuting(); // Finish 2nd goal

//	- if a cancel request is received for the current goal, set it as preempted (DONE)
//	- if there another goal, start executing it
//	- if no goal, stop (DONE)
}

*/
TEST_F(GoalQueueSuite, goalCancelling) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	// Two goals -> Cancel current goal -> Start executing the second
	cli->sendGoal(goal);
	ros::spinOnce();

	sleepExecuting();
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Second goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();

	resumeExecuting();
	ros::Duration(0.5).sleep(); // Needs to wait so the execution variable can update
	sleepExecuting();
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
	EXPECT_TRUE(next_goal_available);

	// Cancelling the second goal
	EXPECT_TRUE(qserv->isActive());
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
 	finishExecuting(); // finish 1st goal
 	ros::Duration(0.5).sleep(); // Needs to wait so the executeCallback can finish

	EXPECT_TRUE(goal_preempted); // Must be checked in the goal-thread that is cancelled
	finishExecuting(); // Finish the cancelled goal
	ros::Duration(0.5).sleep();
	ASSERT_FALSE(qserv->isActive());

// 	- if a cancel request on the "next_goal" received, remove it from the queue and set it as cancelled
}
// Two more TEST_F missing

int main(int argc, char **argv) {
    ros::init(argc, argv, "goal_queueing_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>goalPreempting works.<commit_after>#include <gtest/gtest.h>
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <move_basic/queued_action_server.h>
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

class GoalQueueSuite : public ::testing::Test {
protected:
	virtual void SetUp() {
		resetFlags();
		ros::NodeHandle actionNh("");
		qserv.reset(new actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> (actionNh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)));
		cli.reset(new actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> ("queue_server", true)); // true -> don't need ros::spin()

		qserv->start();
	}

	virtual void TearDown() {
		// Kill the executeCallback if it is running
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); // Releases one waiting thread
		}
		qserv->shutdown();
	}

	void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg) {
		resetFlags();
		got_goal = true;
		received_goal = msg;
		while (true) {
			goal_preempted = qserv->isPreemptRequested() ? true : false;
			next_goal_available = qserv->isNewGoalAvailable() ? true : false;

			// Test fixture can continue
			execution = true;
			sleep_cv.notify_one();
			// Wait until signalled to end
			std::unique_lock<std::mutex> lk(execute_lock);
			execute_cv.wait(lk,
				//lambda function to wait on our bool variables
				[this](){return finish_executing || resume_executing;} // blocks only if lambda returns false
			);
			execution = false;
			// We were requested to stop, so we stop
			if (finish_executing) {
				break;
			}
		}

		// Signal that we are done here
		std::lock_guard<std::mutex> lk(execute_done_lock);
		execute_done = true;
		execute_done_cv.notify_all();
	}

	// Helper function to signal the executeCallback to end
	void finishExecuting() {
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); //unlocks lambda waiting function in ExecuteCallback
		}

		// Wait for execute callback to actually finish
		std::unique_lock<std::mutex> lk2(execute_done_lock);
		execute_done_cv.wait(lk2, [this]() {return execute_done;}); // at the end of ExecuteCallback
	}

	// Helper function to signal the executeCallback to resume
	// This is useful for seeing if the callback code sees a preempt
	void resumeExecuting() {
		std::lock_guard<std::mutex> lk(execute_lock);
		resume_executing = true;
		execute_cv.notify_one();
	}

	// Helper function to wait to for flags to update in ExecuteCallback
	void sleepExecuting() {
		std::unique_lock<std::mutex> slk(sleep_lock);
		sleep_cv.wait(slk,
				[this](){return execution;}
			);
	}

	void resetFlags() {
		got_goal = false;
		goal_preempted = false;
		next_goal_available = false;
		received_goal = nullptr;

		// Signal flags
		execution = false;
		finish_executing = false;
		resume_executing = false;
		execute_done = false;
	}

	// Flags for assertions
	bool got_goal;
	bool goal_preempted;
	bool next_goal_available;
	move_base_msgs::MoveBaseGoalConstPtr received_goal;

	// Signaling variables
	bool execution;
	bool finish_executing;
	bool resume_executing;
	bool execute_done;
	std::mutex sleep_lock;
	std::mutex execute_lock;
	std::mutex execute_done_lock;
	std::condition_variable sleep_cv;
	std::condition_variable execute_cv;
	std::condition_variable execute_done_cv;

	std::unique_ptr<actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction>> qserv;
	std::unique_ptr<actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>> cli;
};

TEST_F(GoalQueueSuite, establishDuplex) {
	move_base_msgs::MoveBaseGoal goal;

	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();

 	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_FALSE(goal_preempted);
	EXPECT_FALSE(next_goal_available);
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);
	finishExecuting();
	ros::Duration(0.5).sleep();
	EXPECT_FALSE(qserv->isActive());
}

TEST_F(GoalQueueSuite, addGoalWhileExecuting) {
	move_base_msgs::MoveBaseGoal goal;

	// First goal
	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_FALSE(goal_preempted);
	EXPECT_FALSE(next_goal_available);
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Second goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();

	resumeExecuting();
	ros::Duration(0.5).sleep();
	sleepExecuting();
 	EXPECT_TRUE(next_goal_available);

	// Cancel the last goal sent
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x); // Making sure we are in the first goal thread
 	finishExecuting(); // Finish 1st goal
	ros::Duration(0.5).sleep();
	EXPECT_TRUE(goal_preempted);
 	finishExecuting(); // Finish 2nd (canceled) goal
	ros::Duration(0.5).sleep();

	// New goal
	goal.target_pose.pose.position.x = 13.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_FALSE(goal_preempted);
	EXPECT_EQ(13.0, received_goal->target_pose.pose.position.x);
	finishExecuting(); // Finish new goal

// 	- if another goal is received add it to the queue (DONE)
// 	- if the queue full, set the next goal as preempted - explicitly called! - so cancelling the next goal and adding new to the queue
// 	- start executing the new goal in queue (after the current)
}

TEST_F(GoalQueueSuite, goalPreempting) {
	move_base_msgs::MoveBaseGoal goal;

	// One goal -> Cancel request -> Stop
	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);

	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
	resumeExecuting();
	ros::Duration(0.5).sleep();

	EXPECT_TRUE(goal_preempted);
	finishExecuting(); // Finish the goal
	ros::Duration(0.5).sleep();
 	EXPECT_FALSE(qserv->isActive());

	// Two goals -> Cancel current goal -> Start executing the second
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	EXPECT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Cancelling the first goal - PITFALL
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
	resumeExecuting();
	ros::Duration(0.5).sleep();
	sleepExecuting();
	ASSERT_TRUE(goal_preempted);
	finishExecuting(); // Finish the preempted goal

	// "Second" goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	sleepExecuting();
	EXPECT_TRUE(got_goal);
	ASSERT_EQ(7.0, received_goal->target_pose.pose.position.x);
	finishExecuting(); // Finish 2nd goal

//	- if a cancel request is received for the current goal, set it as preempted (DONE)
//	- if there another goal, start executing it
//	- if no goal, stop (DONE)
}

TEST_F(GoalQueueSuite, goalCancelling) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	// Two goals -> Cancel current goal -> Start executing the second
	cli->sendGoal(goal);
	ros::spinOnce();

	sleepExecuting();
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Second goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();

	resumeExecuting();
	ros::Duration(0.5).sleep(); // Needs to wait so the execution variable can update
	sleepExecuting();
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
	EXPECT_TRUE(next_goal_available);

	// Cancelling the second goal
	EXPECT_TRUE(qserv->isActive());
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
 	finishExecuting(); // finish 1st goal
 	ros::Duration(0.5).sleep(); // Needs to wait so the executeCallback can finish

	EXPECT_TRUE(goal_preempted); // Must be checked in the goal-thread that is cancelled
	finishExecuting(); // Finish the cancelled goal
	ros::Duration(0.5).sleep();
	ASSERT_FALSE(qserv->isActive());

// 	- if a cancel request on the "next_goal" received, remove it from the queue and set it as cancelled
}

// Two more TEST_F missing

int main(int argc, char **argv) {
    ros::init(argc, argv, "goal_queueing_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <move_basic/queued_action_server.h>
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

class GoalQueueSuite : public ::testing::Test {
protected:
	virtual void SetUp() {
		resetFlags();
		ros::NodeHandle actionNh("");
		qserv.reset(new actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> (actionNh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)));
		cli.reset(new actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> ("queue_server", true)); // true -> don't need ros::spin()

		qserv->start();
	}

	virtual void TearDown() {
		// Kill the executeCallback if it is running
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); // Releases one waiting thread
		}
		qserv->shutdown();
	}

	// TODO: Making sure it gets called at the right time (flags!) - in its own thread
	void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg) {
		resetFlags();
		got_goal = true;
		received_goal = msg;
		while (true) {
			if (qserv->isPreemptRequested()) {
				goal_preempted = true;
			} else {
				goal_preempted = false;
			}
			if (qserv->isNewGoalAvailable()) {
				next_goal_available = true;
			} else {
				next_goal_available = false;
			}

			// Wait until signalled to end
			std::unique_lock<std::mutex> lk(execute_lock);
			execute_cv.wait(lk,
				//lambda function to wait on our bool variables
				[this](){return finish_executing || resume_executing;} // blocks only if lambda returns false
			);
			// We were requested to stop, so we stop
			if (finish_executing) {
				break;
			}
		}

		// Signal that we are done here
		std::lock_guard<std::mutex> lk(execute_done_lock);
		execute_done = true;
		execute_done_cv.notify_all(); // Releases all waiting thread
	}

	// Helper function to signal the executeCallback to end
	void finishExecuting() {
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); //unlocks lambda waiting function in ExecuteCallback
		}

		// Wait for execute callback to actually finish
		std::unique_lock<std::mutex> lk2(execute_done_lock);
		execute_done_cv.wait(lk2, [this]() {return execute_done;}); // at the end of ExecuteCallback
	}

	// Helper function to signal the executeCallback to resume
	// This is useful for seeing if the callback code sees a preempt
	void resumeExecuting() {
		std::lock_guard<std::mutex> lk(execute_lock);
		resume_executing = true;
		execute_cv.notify_one();
	}

	void resetFlags() {
		got_goal = false;
		goal_preempted = false;
		next_goal_available = false;
		received_goal = nullptr;

		// Signal flags
		finish_executing = false;
		resume_executing = false;
		execute_done = false;

	}

	// Flags for assertions
	bool got_goal;
	bool goal_preempted;
	bool next_goal_available;
	move_base_msgs::MoveBaseGoalConstPtr received_goal;

	// Signaling variables
	bool finish_executing;
	bool resume_executing;
	bool execute_done;
	std::mutex execute_lock;
	std::mutex execute_done_lock;
	std::condition_variable execute_cv;
	std::condition_variable execute_done_cv;

	std::unique_ptr<actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction>> qserv;
	std::unique_ptr<actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>> cli;
};

// IMPORTANT: Time delays and ros::spinOnce() sequence should stay the same, otherwise, strange things happen
TEST_F(GoalQueueSuite, establishDuplex) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	finishExecuting();
	ASSERT_TRUE(got_goal);
	ASSERT_FALSE(goal_preempted);
	ASSERT_FALSE(next_goal_available);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
}

TEST_F(GoalQueueSuite, addGoalWhileExecuting) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	// First goal
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Second goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	resumeExecuting();
	// Make sure that the first goal is still executing, but a new goal is seen
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_FALSE(goal_preempted);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
	ASSERT_TRUE(next_goal_available);
	// Finish the first goal, then the 2nd goal should start executing
	finishExecuting();
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_FALSE(goal_preempted);
	ASSERT_FALSE(next_goal_available);
	ASSERT_EQ(7.0, received_goal->target_pose.pose.position.x);
	finishExecuting(); // Finish the 2nd goal
/*
	- if another goal is received add it to the queue (DONE)
	- if the queue full, set the current goal as preempted - explicitly called! - so cancelling the current goal and start executing the next one
	- start executing the next goal in queue (the one after the preempted)
*/
}

TEST_F(GoalQueueSuite, goalPreempting) {
/*
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	// One goal -> Cancel request -> Stop
	cli->sendGoal(goal);
	ros::spinOnce();
	ASSERT_TRUE(qserv->isNewGoalAvailable()); // If moved, strange things happen
	ros::Duration(1.0).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(got_goal1);
	ASSERT_TRUE(qserv->isActive());
	ASSERT_EQ(3.0, current_goal->target_pose.pose.position.x);

	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
<<<<<<< HEAD
	ASSERT_TRUE(qserv->isPreemptRequested());
	ros::Duration(1.0).sleep();
	ASSERT_FALSE(qserv->isActive());
=======
	ASSERT_TRUE(qserv->isPreemptRequested());
	*/

	//TODO: Two goals -> Cancel request(current goal) -> Execute next goal

	/*
	- if a cancel request is received for the current goal, set it as preempted (DONE)
	- if there another goal, start executing it
	- if no goal, stop (DONE)
	*/
}

// TODO: How can I cancel the second goal??? CANCEL REQUEST CANCELS THE LAST GOAL SENT
TEST_F(GoalQueueSuite, goalCancelling) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	cli->sendGoal(goal);
	ros::spinOnce();
	ASSERT_TRUE(qserv->isNewGoalAvailable()); // If moved, strange things happen
	ros::Duration(1.0).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(got_goal);
	ASSERT_TRUE(qserv->isActive());
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	/*
	- if a cancel request on the "next_goal" received, remove it from the queue and set it as cancelled
	- TODO: How to check next goal is executing? It becomes current, so isActive()
	*/
}

// Two more TEST_F missing and a pitfall

int main(int argc, char **argv) {
    ros::init(argc, argv, "goal_queueing_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<commit_msg>Second goal finished.<commit_after>#include <gtest/gtest.h>
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <actionlib/client/terminal_state.h>
#include <move_base_msgs/MoveBaseAction.h>
#include <move_basic/queued_action_server.h>
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

class GoalQueueSuite : public ::testing::Test {
protected:
	virtual void SetUp() {
		resetFlags();
		ros::NodeHandle actionNh("");
		qserv.reset(new actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction> (actionNh, "queue_server", boost::bind(&GoalQueueSuite::executeCallback, this, _1)));
		cli.reset(new actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction> ("queue_server", true)); // true -> don't need ros::spin()

		qserv->start();
	}

	virtual void TearDown() {
		// Kill the executeCallback if it is running
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); // Releases one waiting thread
		}
		qserv->shutdown();
	}

	// TODO: Making sure it gets called at the right time (flags!) - in its own thread
	void executeCallback(const move_base_msgs::MoveBaseGoalConstPtr &msg) {
		resetFlags();
		got_goal = true;
		received_goal = msg;
		while (true) {
			if (qserv->isPreemptRequested()) {
				goal_preempted = true;
			} else {
				goal_preempted = false;
			}
			if (qserv->isNewGoalAvailable()) {
				next_goal_available = true;
			} else {
				next_goal_available = false;
			}

			// Wait until signalled to end
			std::unique_lock<std::mutex> lk(execute_lock);
			execute_cv.wait(lk,
				//lambda function to wait on our bool variables
				[this](){return finish_executing || resume_executing;} // blocks only if lambda returns false
			);
			// We were requested to stop, so we stop
			if (finish_executing) {
				break;
			}
		}

		// Signal that we are done here
		std::lock_guard<std::mutex> lk(execute_done_lock);
		execute_done = true;
		execute_done_cv.notify_all(); // Releases all waiting thread
	}

	// Helper function to signal the executeCallback to end
	void finishExecuting() {
		// New Scope so that lock_guard destructs and unlocks
		{
			std::lock_guard<std::mutex> lk1(execute_lock);
			finish_executing = true;
			execute_cv.notify_one(); //unlocks lambda waiting function in ExecuteCallback
		}

		// Wait for execute callback to actually finish
		std::unique_lock<std::mutex> lk2(execute_done_lock);
		execute_done_cv.wait(lk2, [this]() {return execute_done;}); // at the end of ExecuteCallback
	}

	// Helper function to signal the executeCallback to resume
	// This is useful for seeing if the callback code sees a preempt
	void resumeExecuting() {
		std::lock_guard<std::mutex> lk(execute_lock);
		resume_executing = true;
		execute_cv.notify_one();
	}

	void resetFlags() {
		got_goal = false;
		goal_preempted = false;
		next_goal_available = false;
		received_goal = nullptr;

		// Signal flags
		finish_executing = false;
		resume_executing = false;
		execute_done = false;
	}

	// Flags for assertions
	bool got_goal;
	bool goal_preempted;
	bool next_goal_available;
	move_base_msgs::MoveBaseGoalConstPtr received_goal;

	// Signaling variables
	bool finish_executing;
	bool resume_executing;
	bool execute_done;
	std::mutex execute_lock;
	std::mutex execute_done_lock;
	std::condition_variable execute_cv;
	std::condition_variable execute_done_cv;

	std::unique_ptr<actionlib::QueuedActionServer<move_base_msgs::MoveBaseAction>> qserv;
	std::unique_ptr<actionlib::SimpleActionClient<move_base_msgs::MoveBaseAction>> cli;
};

// IMPORTANT: Time delays and ros::spinOnce() sequence should stay the same, otherwise, strange things happen
TEST_F(GoalQueueSuite, establishDuplex) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	finishExecuting();
	ASSERT_TRUE(got_goal);
	ASSERT_FALSE(goal_preempted);
	ASSERT_FALSE(next_goal_available);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);
}

TEST_F(GoalQueueSuite, addGoalWhileExecuting) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	// First goal
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	// Cancelling the first goal - PITFALL
	resumeExecuting();
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
	ASSERT_TRUE(goal_preempted);
	// Finish the preempted goal
	finishExecuting();

	// "Second" goal
	goal.target_pose.pose.position.x = 7.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(7.0, received_goal->target_pose.pose.position.x); // call FINISH!

	// Third goal
	goal.target_pose.pose.position.x = 13.0;
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	resumeExecuting();
	// Make sure that the "second" goal is still executing, but a new goal is seen
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_EQ(7.0, received_goal->target_pose.pose.position.x);
	ASSERT_FALSE(goal_preempted);
	ASSERT_TRUE(next_goal_available);
	// Finish the "second" goal, then the 3nd goal should start executing
	finishExecuting();
	ros::spinOnce();
	ros::Duration(0.5).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(qserv->isActive());
	ASSERT_TRUE(got_goal);
	ASSERT_FALSE(goal_preempted);
	ASSERT_FALSE(next_goal_available);
	ASSERT_EQ(13.0, received_goal->target_pose.pose.position.x);
	finishExecuting(); // Finish the 3nd goal
/*
	- if another goal is received add it to the queue (DONE)
	- if the queue full, set the current goal as preempted - explicitly called! - so cancelling the current goal and start executing the next one
	- start executing the next goal in queue (the one after the preempted)
*/
}

TEST_F(GoalQueueSuite, goalPreempting) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;
	// One goal -> Cancel request -> Stop
	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(1.0).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(got_goal);
	ASSERT_TRUE(qserv->isActive());
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	resumeExecuting();
	cli->cancelGoal();
	ros::Duration(1.0).sleep();
	ros::spinOnce();
	//ros::Duration(1.0).sleep();
	ASSERT_TRUE(goal_preempted);
	//ASSERT_FALSE(qserv->isActive());
	//ASSERT_TRUE(qserv->isPreemptRequested());
	finishExecuting(); // Finish the goal

	//TODO: Two goals -> Cancel request(current goal) -> Execute next goal

//	- if a cancel request is received for the current goal, set it as preempted (DONE)
//	- if there another goal, start executing it
//	- if no goal, stop (DONE)
}

// TODO: How can I cancel the second goal??? CANCEL REQUEST CANCELS THE LAST GOAL SENT
TEST_F(GoalQueueSuite, goalCancelling) {
	move_base_msgs::MoveBaseGoal goal;
	goal.target_pose.pose.position.x = 3.0;

	cli->sendGoal(goal);
	ros::spinOnce();
	ros::Duration(1.0).sleep(); // TODO: Make this disappear
	ASSERT_TRUE(got_goal);
	ASSERT_TRUE(qserv->isActive());
	ASSERT_EQ(3.0, received_goal->target_pose.pose.position.x);

	/*
	- if a cancel request on the "next_goal" received, remove it from the queue and set it as cancelled
	- TODO: How to check next goal is executing? It becomes current, so isActive()
	*/
}

// Two more TEST_F missing and a pitfall

int main(int argc, char **argv) {
    ros::init(argc, argv, "goal_queueing_test");
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Tests.h"

#include "Media.h"
#include "File.h"

class Files : public Tests
{
protected:
    std::shared_ptr<File> f;
    std::shared_ptr<Media> m;
    virtual void SetUp() override
    {
        Tests::SetUp();
        m = ml->addFile( "media.mkv" );
        auto files = m->files();
        ASSERT_EQ( 1u, files.size() );
        f = std::static_pointer_cast<File>( files[0] );
    }
};

TEST_F( Files, Create )
{
    ASSERT_NE( 0u, f->id() );
    ASSERT_FALSE( f->isParsed() );
    ASSERT_EQ( "media.mkv", f->mrl() );
    ASSERT_NE( 0u, f->lastModificationDate() );
    ASSERT_EQ( File::Type::Entire, f->type() );
}

TEST_F( Files, Remove )
{
    m->removeFile( *f );
    // The instance should now have 0 files listed:
    auto files = m->files();
    ASSERT_EQ( 0u, files.size() );
    auto media = ml->media( m->id() );
    // This file should now be removed from the DB
    ASSERT_EQ( nullptr, media );
}
<commit_msg>tests: Add a File::media() test<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#include "Tests.h"

#include "Media.h"
#include "File.h"

class Files : public Tests
{
protected:
    std::shared_ptr<File> f;
    std::shared_ptr<Media> m;
    virtual void SetUp() override
    {
        Tests::SetUp();
        m = ml->addFile( "media.mkv" );
        auto files = m->files();
        ASSERT_EQ( 1u, files.size() );
        f = std::static_pointer_cast<File>( files[0] );
    }
};

TEST_F( Files, Create )
{
    ASSERT_NE( 0u, f->id() );
    ASSERT_FALSE( f->isParsed() );
    ASSERT_EQ( "media.mkv", f->mrl() );
    ASSERT_NE( 0u, f->lastModificationDate() );
    ASSERT_EQ( File::Type::Entire, f->type() );
}

TEST_F( Files, Remove )
{
    m->removeFile( *f );
    // The instance should now have 0 files listed:
    auto files = m->files();
    ASSERT_EQ( 0u, files.size() );
    auto media = ml->media( m->id() );
    // This file should now be removed from the DB
    ASSERT_EQ( nullptr, media );
}

TEST_F( Files, Media )
{
    ASSERT_EQ( f->id(), f->media()->id() );

    Reload();

    auto m = ml->media( "media.mkv" );
    auto files = m->files();
    ASSERT_EQ( 1u, files.size() );
    f = std::static_pointer_cast<File>( files[0] );
    ASSERT_EQ( m->id(), f->media()->id() );
}
<|endoftext|>


<commit_before>/*
*
* Copyright 2013 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Fermin Galan
*/

#include "testInit.h"

#include "logMsg/logMsg.h"

#include "mongoBackend/MongoGlobal.h"
#include "mongo/client/dbclient.h"

using namespace mongo;

/* ****************************************************************************
*
* setupDatabase -
*
* This function (which is called before every test) cleans the database
*/
extern DBClientBase* mongoInitialConnectionGetForUnitTest();
extern void          setMongoConnectionForUnitTest(DBClientBase*);
void setupDatabase(void)
{
    DBClientBase*  connection   = NULL;
    static bool    mongoStarted = false;

    /* mongoStart is needed one time to create the connection pool */
    if (mongoStarted == false)
    {
      mongoStart("localhost", "", "", "", "", false, 0, 10);
      mongoStarted = true;
    }

    connection = getMongoConnection();
    if (connection == NULL)
    {
      connection = mongoInitialConnectionGetForUnitTest();
      setMongoConnectionForUnitTest(connection);
    }

    connection->dropCollection(REGISTRATIONS_COLL);
    connection->dropCollection(ENTITIES_COLL);
    connection->dropCollection(SUBSCRIBECONTEXT_COLL);
    connection->dropCollection(SUBSCRIBECONTEXTAVAIL_COLL);
    connection->dropCollection(ASSOCIATIONS_COLL);

    releaseMongoConnection(connection);

    setDbPrefix(DBPREFIX);
    setRegistrationsCollectionName("registrations");
    setEntitiesCollectionName("entities");
    setSubscribeContextCollectionName("csubs");
    setSubscribeContextAvailabilityCollectionName("casubs");
    setAssociationsCollectionName("associations");
}

/* ****************************************************************************
*
* equalEntity -
*/
static bool equalEntity(EntityId enExpected, EntityId enArg) {

    LM_M(("enArg '%s', '%s', '%s'",
          enArg.id.c_str(),
          enArg.type.c_str(),
          enArg.isPattern.c_str()
          ));
    LM_M(("enExpected '%s', '%s', '%s'",
          enExpected.id.c_str(),
          enExpected.type.c_str(),
          enExpected.isPattern.c_str()
          ));
    if (enExpected.id == enArg.id &&
        enExpected.type == enArg.type &&
        enExpected.isPattern == enArg.isPattern) {

        return true;
    }
    else {
        return false;
    }

}

/* ****************************************************************************
*
* equalContextAttribute -
*/
static bool equalContextAttribute(ContextAttribute* caExpected, ContextAttribute* caArg) {

    LM_M(("caArg '%s', '%s', '%s'",
          caArg->name.c_str(),
          caArg->type.c_str(),
          caArg->toStringValue().c_str()
          ));
    LM_M(("caExpected '%s', '%s', '%s'",
          caExpected->name.c_str(),
          caExpected->type.c_str(),
          caExpected->toStringValue().c_str()
          ));

    if (caArg->name == caExpected->name &&
        caArg->type == caExpected->type &&
        caArg->stringValue == caExpected->stringValue) // FIXME P10: automacit value -> stringValue change, please review to check if it is safe
    {
        return true;
    }
    else
    {
        return false;
    }
}

/* ****************************************************************************
*
* equalContextAttributeVector -
*/
static bool equalContextAttributeVector(ContextAttributeVector caExpectedV, ContextAttributeVector caArgV) {

    /* Check vector size */
    if (caExpectedV.size() != caArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", caExpectedV.size(), caArgV.size()));
        return false;
    }

    /* Check that every attribute in 'caExpectedV' is in 'caArgV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < caArgV.size(); ++ix) {
        bool attributeMatch = false;
        for (unsigned int jx = 0; jx < caExpectedV.size(); ++jx) {
            ContextAttribute* caArg = caArgV.get(ix);
            ContextAttribute* caExpected = caExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalContextAttribute(caExpected, caArg)) {
                LM_M(("attribute matches in ContextAttributeVector comparison, check next one..."));
                attributeMatch = true;
                break; /* loop in jx */
            }
        }
        if (!attributeMatch) {
            LM_M(("after looking everyone, attribute doesn't match in ContextAttributeVector comparison"));
            return false;
        }
    }

    LM_M(("ContextAttributeVector comparison ok"));
    return true;

}

/* ****************************************************************************
*
* equalContextElementResponseVector -
*
*/
static bool equalContextElementResponseVector(ContextElementResponseVector cerExpectedV, ContextElementResponseVector cerArgV) {

    /* Check vector size */
    if (cerExpectedV.size() != cerArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", cerExpectedV.size(), cerArgV.size()));
        return false;
    }

    /* Check that every entity in 'cerArgV' is in 'cerExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < cerArgV.size(); ++ix) {
        bool entityMatch = false;
        for (unsigned int jx = 0; jx < cerExpectedV.size(); ++jx) {
            ContextElementResponse* cerArg = cerArgV.get(ix);
            ContextElementResponse* cerExpected = cerExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (!equalEntity(cerExpected->contextElement.entityId, cerArg->contextElement.entityId)) {
                LM_M(("entity doesn't match in ContextElementResponseVector comparison, continue..."));
                continue; /* loop in jx */
            }

            /* If there aren't attributes to check, then early exits the loop */
            if (cerExpected->contextElement.contextAttributeVector.size() == 0) {
                LM_M(("entity (without attributes) matches in ContextElementResponseVector comparison, check next one..."));
                entityMatch = true;
                break; /* loop in jx */
            }

            if (equalContextAttributeVector(cerExpected->contextElement.contextAttributeVector, cerArg->contextElement.contextAttributeVector)) {
                LM_M(("entity (with attributes) matches in ContextElementResponseVector comparison, check next one..."));
                entityMatch = true;
                break; /* loop in jx */
            }
        }

        if (!entityMatch) {
            LM_M(("after looking everyone, entity doesn't matches in ContextElementResponseVector comparison"));
            return false;
        }
    }

    LM_M(("ContextElementResponseVector comparison ok"));
    return true;

}

/* ****************************************************************************
*
* matchNotifyContextRequest -
*
* We need a matcher to compare NotifyContextRequest in EXPECT_CALL() for sendNotifyContextRequest, due
* to NotifyContextRequest is not yet a full fledged object and we can not use the '==' method and
* Eq() matcher. FIXME
*
*/
bool matchNotifyContextRequest(NotifyContextRequest* expected, NotifyContextRequest* arg) {

    LM_M(("inside MatchNcr"));

    /* The isEmpty() check is needed because, in some occasion, we don't have any expectations on
     * subscriptionId and, in these cases, we don't check its value */
    if (!expected->subscriptionId.isEmpty() && (expected->subscriptionId.get() != arg->subscriptionId.get())) {
        return false;
    }

    if (expected->originator.get() != arg->originator.get()) {
        return false;
    }

    if (!equalContextElementResponseVector(expected->contextElementResponseVector, arg->contextElementResponseVector)) {
        return false;
    }

    return true;

}

/* ****************************************************************************
*
* equalContextRegistrationAttribute -
*
*/
static bool equalContextRegistrationAttribute(ContextRegistrationAttribute* craExpected, ContextRegistrationAttribute* craArg) {
    LM_M(("craArg '%s', '%s'",
          craArg->name.c_str(),
          craArg->type.c_str()
          ));
    LM_M(("craExpected '%s', '%s'",
          craExpected->name.c_str(),
          craExpected->type.c_str()
          ));

    if (craArg->name == craExpected->name && craArg->type == craExpected->type) {
        return true;
    }
    else {
        return false;
    }
}

/* ****************************************************************************
*
* equalContextRegistrationAttributeVector -
*
*/
static bool equalContextRegistrationAttributeVector(ContextRegistrationAttributeVector craExpectedV, ContextRegistrationAttributeVector craArgV) {

    /* Check vector size */
    if (craExpectedV.size() != craArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", craExpectedV.size(), craArgV.size()));
        return false;
    }

    /* Check that every context registration attribute in 'craArgV' is in 'craExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < craArgV.size(); ++ix) {
        bool contextRegistrationAttributeMatches = false;
        for (unsigned int jx = 0; jx < craExpectedV.size(); ++jx) {
            ContextRegistrationAttribute* craArg = craArgV.get(ix);
            ContextRegistrationAttribute* craExpected = craExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalContextRegistrationAttribute(craExpected, craArg)) {
                LM_M(("context registration attribute matches in ContextRegistrationAttributeVector comparison, check next one..."));
                contextRegistrationAttributeMatches = true;
                break; /* loop in jx */
            }
        }

        if (!contextRegistrationAttributeMatches) {
            LM_M(("after looking everyone, context registration attribute doesn't match in ContextRegistrationAttributeVector comparison"));
            return false;
        }
    }

    LM_M(("ContextRegistrationAttributeVector comparison ok"));
    return true;
}

/* ****************************************************************************
*
* equalEntityIdVector -
*
*/
static bool equalEntityIdVector(EntityIdVector enExpectedV, EntityIdVector enArgV) {

    /* Check vector size */
    if (enExpectedV.size() != enArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", enExpectedV.size(), enArgV.size()));
        return false;
    }

    /* Check that every entity in 'enArgV' is in 'enExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < enArgV.size(); ++ix) {
        bool entityMatch = false;
        for (unsigned int jx = 0; jx < enExpectedV.size(); ++jx) {
            EntityId enArg = *enArgV.get(ix);
            EntityId enExpected = *enExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalEntity(enExpected, enArg)) {
                LM_M(("entity matches in EntityIdVector comparison, check next one..."));
                entityMatch = true;
                break; /* loop in jx */
            }
        }

        if (!entityMatch) {
            LM_M(("after looking everyone, entity doesn't match in EntityIdVector"));
            return false;
        }
    }

    LM_M(("EntityIdVector comparison ok"));
    return true;
}

/* ****************************************************************************
*
* equalContextRegistrationResponseVector -
*
*/
static bool equalContextRegistrationResponseVector(ContextRegistrationResponseVector crrExpectedV, ContextRegistrationResponseVector crrArgV) {

    /* Check vector size */
    if (crrExpectedV.size() != crrArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", crrExpectedV.size(), crrArgV.size()));
        return false;
    }

    /* Check that every context registration in 'crrArgV' is in 'crrExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < crrArgV.size(); ++ix) {
        bool contextRegistrationMatch = false;
        for (unsigned int jx = 0; jx < crrExpectedV.size(); ++jx) {
            ContextRegistration crArg = crrArgV.get(ix)->contextRegistration;
            ContextRegistration crExpected = crrExpectedV.get(jx)->contextRegistration;
            LM_M(("%d == %d?", ix, jx));
            if (!equalEntityIdVector(crExpected.entityIdVector, crArg.entityIdVector)) {
                LM_M(("entity vector doesn't match in ContextRegistrationResponseVector comparison, continue..."));
                continue; /* loop in jx */
            }

            if (!equalContextRegistrationAttributeVector(crExpected.contextRegistrationAttributeVector, crArg.contextRegistrationAttributeVector)) {
                LM_M(("context registration attribute vector doesn't match in ContextRegistrationResponseVector comparison, continue..."));
                continue; /* loop in jx */
            }

            if (crExpected.providingApplication.get() == crArg.providingApplication.get()) {
                contextRegistrationMatch = true;
                LM_M(("context registration match in ContextRegistrationResponseVector comparison, check next one..."));
                break; /* loop in jx */
            }
        }

        if (!contextRegistrationMatch) {
            LM_M(("after looking everyone, context registration doesn't matches in ContextElementResponseVector comparison"));
            return false;
        }
    }

    LM_M(("ContextElementResponseVector comparison ok"));
    return true;

}

/* ****************************************************************************
*
* matchNotifyContextAvailabilityRequest -
*
* We need a matcher to compare NotifyContextAvailabilityRequest in EXPECT_CALL() for
* sendNotifyContextAvailabilityRequest, due to NotifyContextAvailabilityRequest is
* not yet a full fledged object and we can not use the '==' method and Eq() matcher.
* FIXME
*
*/
bool matchNotifyContextAvailabilityRequest(NotifyContextAvailabilityRequest* expected, NotifyContextAvailabilityRequest* arg) {

    LM_M(("inside MatchNcar"));

    /* The isEmpty() check is needed because, in some occasion, we don't have any expectations on
     * subscriptionId and, in these cases, we don't check its value */
    if (!expected->subscriptionId.isEmpty() && (expected->subscriptionId.get() != arg->subscriptionId.get())) {
        return false;
    }

    if (!equalContextRegistrationResponseVector(expected->contextRegistrationResponseVector, arg->contextRegistrationResponseVector)) {
        return false;
    }

    return true;

}

<commit_msg>fixed equalContextAttribute<commit_after>/*
*
* Copyright 2013 Telefonica Investigacion y Desarrollo, S.A.U
*
* This file is part of Orion Context Broker.
*
* Orion Context Broker is free software: you can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* Orion Context Broker is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero
* General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Orion Context Broker. If not, see http://www.gnu.org/licenses/.
*
* For those usages not covered by this license please contact with
* iot_support at tid dot es
*
* Author: Fermin Galan
*/

#include "testInit.h"

#include "logMsg/logMsg.h"

#include "mongoBackend/MongoGlobal.h"
#include "mongo/client/dbclient.h"

using namespace mongo;

/* ****************************************************************************
*
* setupDatabase -
*
* This function (which is called before every test) cleans the database
*/
extern DBClientBase* mongoInitialConnectionGetForUnitTest();
extern void          setMongoConnectionForUnitTest(DBClientBase*);
void setupDatabase(void)
{
    DBClientBase*  connection   = NULL;
    static bool    mongoStarted = false;

    /* mongoStart is needed one time to create the connection pool */
    if (mongoStarted == false)
    {
      mongoStart("localhost", "", "", "", "", false, 0, 10);
      mongoStarted = true;
    }

    connection = getMongoConnection();
    if (connection == NULL)
    {
      connection = mongoInitialConnectionGetForUnitTest();
      setMongoConnectionForUnitTest(connection);
    }

    connection->dropCollection(REGISTRATIONS_COLL);
    connection->dropCollection(ENTITIES_COLL);
    connection->dropCollection(SUBSCRIBECONTEXT_COLL);
    connection->dropCollection(SUBSCRIBECONTEXTAVAIL_COLL);
    connection->dropCollection(ASSOCIATIONS_COLL);

    releaseMongoConnection(connection);

    setDbPrefix(DBPREFIX);
    setRegistrationsCollectionName("registrations");
    setEntitiesCollectionName("entities");
    setSubscribeContextCollectionName("csubs");
    setSubscribeContextAvailabilityCollectionName("casubs");
    setAssociationsCollectionName("associations");
}

/* ****************************************************************************
*
* equalEntity -
*/
static bool equalEntity(EntityId enExpected, EntityId enArg) {

    LM_M(("enArg '%s', '%s', '%s'",
          enArg.id.c_str(),
          enArg.type.c_str(),
          enArg.isPattern.c_str()
          ));
    LM_M(("enExpected '%s', '%s', '%s'",
          enExpected.id.c_str(),
          enExpected.type.c_str(),
          enExpected.isPattern.c_str()
          ));
    if (enExpected.id == enArg.id &&
        enExpected.type == enArg.type &&
        enExpected.isPattern == enArg.isPattern) {

        return true;
    }
    else {
        return false;
    }

}

/* ****************************************************************************
*
* equalContextAttribute -
*/
static bool equalContextAttribute(ContextAttribute* caExpected, ContextAttribute* caArg)
{
  if (caArg->name != caExpected->name)
  {
    return false;
  }

  if (caArg->type != caExpected->type)
  {
    return false;
  }

  if (caArg->valueType != caExpected->valueType)
  {
    return false;
  }

  if ((caArg->valueType == orion::ValueTypeString) && (caArg->stringValue != caExpected->stringValue))
  {
    return false;
  }

  if ((caArg->valueType == orion::ValueTypeNumber) && (caArg->numberValue != caExpected->numberValue))
  {
    return false;
  }

  if ((caArg->valueType == orion::ValueTypeBoolean) && (caArg->boolValue != caExpected->boolValue))
  {
    return false;
  }

  LM_M(("caArg '%s', '%s', '%s'", caArg->name.c_str(), caArg->type.c_str(), caArg->toStringValue().c_str()));
  LM_M(("caExpected '%s', '%s', '%s'", caExpected->name.c_str(), caExpected->type.c_str(), caExpected->toStringValue().c_str()));

  return true;
}

/* ****************************************************************************
*
* equalContextAttributeVector -
*/
static bool equalContextAttributeVector(ContextAttributeVector caExpectedV, ContextAttributeVector caArgV) {

    /* Check vector size */
    if (caExpectedV.size() != caArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", caExpectedV.size(), caArgV.size()));
        return false;
    }

    /* Check that every attribute in 'caExpectedV' is in 'caArgV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < caArgV.size(); ++ix) {
        bool attributeMatch = false;
        for (unsigned int jx = 0; jx < caExpectedV.size(); ++jx) {
            ContextAttribute* caArg = caArgV.get(ix);
            ContextAttribute* caExpected = caExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalContextAttribute(caExpected, caArg)) {
                LM_M(("attribute matches in ContextAttributeVector comparison, check next one..."));
                attributeMatch = true;
                break; /* loop in jx */
            }
        }
        if (!attributeMatch) {
            LM_M(("after looking everyone, attribute doesn't match in ContextAttributeVector comparison"));
            return false;
        }
    }

    LM_M(("ContextAttributeVector comparison ok"));
    return true;

}

/* ****************************************************************************
*
* equalContextElementResponseVector -
*
*/
static bool equalContextElementResponseVector(ContextElementResponseVector cerExpectedV, ContextElementResponseVector cerArgV) {

    /* Check vector size */
    if (cerExpectedV.size() != cerArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", cerExpectedV.size(), cerArgV.size()));
        return false;
    }

    /* Check that every entity in 'cerArgV' is in 'cerExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < cerArgV.size(); ++ix) {
        bool entityMatch = false;
        for (unsigned int jx = 0; jx < cerExpectedV.size(); ++jx) {
            ContextElementResponse* cerArg = cerArgV.get(ix);
            ContextElementResponse* cerExpected = cerExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (!equalEntity(cerExpected->contextElement.entityId, cerArg->contextElement.entityId)) {
                LM_M(("entity doesn't match in ContextElementResponseVector comparison, continue..."));
                continue; /* loop in jx */
            }

            /* If there aren't attributes to check, then early exits the loop */
            if (cerExpected->contextElement.contextAttributeVector.size() == 0) {
                LM_M(("entity (without attributes) matches in ContextElementResponseVector comparison, check next one..."));
                entityMatch = true;
                break; /* loop in jx */
            }

            if (equalContextAttributeVector(cerExpected->contextElement.contextAttributeVector, cerArg->contextElement.contextAttributeVector)) {
                LM_M(("entity (with attributes) matches in ContextElementResponseVector comparison, check next one..."));
                entityMatch = true;
                break; /* loop in jx */
            }
        }

        if (!entityMatch) {
            LM_M(("after looking everyone, entity doesn't matches in ContextElementResponseVector comparison"));
            return false;
        }
    }

    LM_M(("ContextElementResponseVector comparison ok"));
    return true;

}

/* ****************************************************************************
*
* matchNotifyContextRequest -
*
* We need a matcher to compare NotifyContextRequest in EXPECT_CALL() for sendNotifyContextRequest, due
* to NotifyContextRequest is not yet a full fledged object and we can not use the '==' method and
* Eq() matcher. FIXME
*
*/
bool matchNotifyContextRequest(NotifyContextRequest* expected, NotifyContextRequest* arg) {

    LM_M(("inside MatchNcr"));

    /* The isEmpty() check is needed because, in some occasion, we don't have any expectations on
     * subscriptionId and, in these cases, we don't check its value */
    if (!expected->subscriptionId.isEmpty() && (expected->subscriptionId.get() != arg->subscriptionId.get())) {
        return false;
    }

    if (expected->originator.get() != arg->originator.get()) {
        return false;
    }

    if (!equalContextElementResponseVector(expected->contextElementResponseVector, arg->contextElementResponseVector)) {
        return false;
    }

    return true;

}

/* ****************************************************************************
*
* equalContextRegistrationAttribute -
*
*/
static bool equalContextRegistrationAttribute(ContextRegistrationAttribute* craExpected, ContextRegistrationAttribute* craArg) {
    LM_M(("craArg '%s', '%s'",
          craArg->name.c_str(),
          craArg->type.c_str()
          ));
    LM_M(("craExpected '%s', '%s'",
          craExpected->name.c_str(),
          craExpected->type.c_str()
          ));

    if (craArg->name == craExpected->name && craArg->type == craExpected->type) {
        return true;
    }
    else {
        return false;
    }
}

/* ****************************************************************************
*
* equalContextRegistrationAttributeVector -
*
*/
static bool equalContextRegistrationAttributeVector(ContextRegistrationAttributeVector craExpectedV, ContextRegistrationAttributeVector craArgV) {

    /* Check vector size */
    if (craExpectedV.size() != craArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", craExpectedV.size(), craArgV.size()));
        return false;
    }

    /* Check that every context registration attribute in 'craArgV' is in 'craExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < craArgV.size(); ++ix) {
        bool contextRegistrationAttributeMatches = false;
        for (unsigned int jx = 0; jx < craExpectedV.size(); ++jx) {
            ContextRegistrationAttribute* craArg = craArgV.get(ix);
            ContextRegistrationAttribute* craExpected = craExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalContextRegistrationAttribute(craExpected, craArg)) {
                LM_M(("context registration attribute matches in ContextRegistrationAttributeVector comparison, check next one..."));
                contextRegistrationAttributeMatches = true;
                break; /* loop in jx */
            }
        }

        if (!contextRegistrationAttributeMatches) {
            LM_M(("after looking everyone, context registration attribute doesn't match in ContextRegistrationAttributeVector comparison"));
            return false;
        }
    }

    LM_M(("ContextRegistrationAttributeVector comparison ok"));
    return true;
}

/* ****************************************************************************
*
* equalEntityIdVector -
*
*/
static bool equalEntityIdVector(EntityIdVector enExpectedV, EntityIdVector enArgV) {

    /* Check vector size */
    if (enExpectedV.size() != enArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", enExpectedV.size(), enArgV.size()));
        return false;
    }

    /* Check that every entity in 'enArgV' is in 'enExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < enArgV.size(); ++ix) {
        bool entityMatch = false;
        for (unsigned int jx = 0; jx < enExpectedV.size(); ++jx) {
            EntityId enArg = *enArgV.get(ix);
            EntityId enExpected = *enExpectedV.get(jx);
            LM_M(("%d == %d?", ix, jx));
            if (equalEntity(enExpected, enArg)) {
                LM_M(("entity matches in EntityIdVector comparison, check next one..."));
                entityMatch = true;
                break; /* loop in jx */
            }
        }

        if (!entityMatch) {
            LM_M(("after looking everyone, entity doesn't match in EntityIdVector"));
            return false;
        }
    }

    LM_M(("EntityIdVector comparison ok"));
    return true;
}

/* ****************************************************************************
*
* equalContextRegistrationResponseVector -
*
*/
static bool equalContextRegistrationResponseVector(ContextRegistrationResponseVector crrExpectedV, ContextRegistrationResponseVector crrArgV) {

    /* Check vector size */
    if (crrExpectedV.size() != crrArgV.size()) {
        LM_M(("different sizes: expected %d, actual %d", crrExpectedV.size(), crrArgV.size()));
        return false;
    }

    /* Check that every context registration in 'crrArgV' is in 'crrExpectedV'. Order doesn't matter */
    for (unsigned int ix = 0; ix < crrArgV.size(); ++ix) {
        bool contextRegistrationMatch = false;
        for (unsigned int jx = 0; jx < crrExpectedV.size(); ++jx) {
            ContextRegistration crArg = crrArgV.get(ix)->contextRegistration;
            ContextRegistration crExpected = crrExpectedV.get(jx)->contextRegistration;
            LM_M(("%d == %d?", ix, jx));
            if (!equalEntityIdVector(crExpected.entityIdVector, crArg.entityIdVector)) {
                LM_M(("entity vector doesn't match in ContextRegistrationResponseVector comparison, continue..."));
                continue; /* loop in jx */
            }

            if (!equalContextRegistrationAttributeVector(crExpected.contextRegistrationAttributeVector, crArg.contextRegistrationAttributeVector)) {
                LM_M(("context registration attribute vector doesn't match in ContextRegistrationResponseVector comparison, continue..."));
                continue; /* loop in jx */
            }

            if (crExpected.providingApplication.get() == crArg.providingApplication.get()) {
                contextRegistrationMatch = true;
                LM_M(("context registration match in ContextRegistrationResponseVector comparison, check next one..."));
                break; /* loop in jx */
            }
        }

        if (!contextRegistrationMatch) {
            LM_M(("after looking everyone, context registration doesn't matches in ContextElementResponseVector comparison"));
            return false;
        }
    }

    LM_M(("ContextElementResponseVector comparison ok"));
    return true;

}

/* ****************************************************************************
*
* matchNotifyContextAvailabilityRequest -
*
* We need a matcher to compare NotifyContextAvailabilityRequest in EXPECT_CALL() for
* sendNotifyContextAvailabilityRequest, due to NotifyContextAvailabilityRequest is
* not yet a full fledged object and we can not use the '==' method and Eq() matcher.
* FIXME
*
*/
bool matchNotifyContextAvailabilityRequest(NotifyContextAvailabilityRequest* expected, NotifyContextAvailabilityRequest* arg) {

    LM_M(("inside MatchNcar"));

    /* The isEmpty() check is needed because, in some occasion, we don't have any expectations on
     * subscriptionId and, in these cases, we don't check its value */
    if (!expected->subscriptionId.isEmpty() && (expected->subscriptionId.get() != arg->subscriptionId.get())) {
        return false;
    }

    if (!equalContextRegistrationResponseVector(expected->contextRegistrationResponseVector, arg->contextRegistrationResponseVector)) {
        return false;
    }

    return true;

}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "memory"

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"

namespace {

const unsigned int kWidth = 160;
const unsigned int kHeight = 90;
const unsigned int kFramerate = 50;
const unsigned int kFrames = 20;
const int kBitrate = 500;
// List of psnr thresholds for speed settings 0-7 and 5 encoding modes
const double kPsnrThreshold[][5] = {
  { 36.0, 37.0, 37.0, 37.0, 37.0 }, { 35.0, 36.0, 36.0, 36.0, 36.0 },
  { 34.0, 35.0, 35.0, 35.0, 35.0 }, { 33.0, 34.0, 34.0, 34.0, 34.0 },
  { 32.0, 33.0, 33.0, 33.0, 33.0 }, { 28.0, 32.0, 32.0, 32.0, 32.0 },
  { 28.5, 31.0, 31.0, 31.0, 31.0 }, { 28.0, 30.0, 30.0, 30.0, 30.0 },
};

typedef struct {
  const char *filename;
  unsigned int input_bit_depth;
  vpx_img_fmt fmt;
  vpx_bit_depth_t bit_depth;
  unsigned int profile;
} TestVideoParam;

const TestVideoParam kTestVectors[] = {
  { "park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420, VPX_BITS_8, 0 },
  { "park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422, VPX_BITS_8, 1 },
  { "park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444, VPX_BITS_8, 1 },
  { "park_joy_90p_8_440.yuv", 8, VPX_IMG_FMT_I440, VPX_BITS_8, 1 },
#if CONFIG_VP9_HIGHBITDEPTH
  { "park_joy_90p_10_420_20f.y4m", 10, VPX_IMG_FMT_I42016, VPX_BITS_10, 2 },
  { "park_joy_90p_10_422_20f.y4m", 10, VPX_IMG_FMT_I42216, VPX_BITS_10, 3 },
  { "park_joy_90p_10_444_20f.y4m", 10, VPX_IMG_FMT_I44416, VPX_BITS_10, 3 },
  { "park_joy_90p_10_440.yuv", 10, VPX_IMG_FMT_I44016, VPX_BITS_10, 3 },
  { "park_joy_90p_12_420_20f.y4m", 12, VPX_IMG_FMT_I42016, VPX_BITS_12, 2 },
  { "park_joy_90p_12_422_20f.y4m", 12, VPX_IMG_FMT_I42216, VPX_BITS_12, 3 },
  { "park_joy_90p_12_444_20f.y4m", 12, VPX_IMG_FMT_I44416, VPX_BITS_12, 3 },
  { "park_joy_90p_12_440.yuv", 12, VPX_IMG_FMT_I44016, VPX_BITS_12, 3 },
#endif  // CONFIG_VP9_HIGHBITDEPTH
};

// Encoding modes tested
const libvpx_test::TestMode kEncodingModeVectors[] = {
  ::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood,
  ::libvpx_test::kRealTime
};

// Speed settings tested
const int kCpuUsedVectors[] = { 1, 2, 3, 5, 6, 7 };

int is_extension_y4m(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename) {
    return 0;
  } else {
    return !strcmp(dot, ".y4m");
  }
}

class EndToEndTestAdaptiveRDThresh
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith2Params<int, int> {
 protected:
  EndToEndTestAdaptiveRDThresh()
      : EncoderTest(GET_PARAM(0)), cpu_used_start_(GET_PARAM(1)),
        cpu_used_end_(GET_PARAM(2)) {}

  virtual ~EndToEndTestAdaptiveRDThresh() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(::libvpx_test::kRealTime);
    cfg_.g_lag_in_frames = 0;
    cfg_.rc_end_usage = VPX_CBR;
    cfg_.rc_buf_sz = 1000;
    cfg_.rc_buf_initial_sz = 500;
    cfg_.rc_buf_optimal_sz = 600;
    dec_cfg_.threads = 4;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(VP8E_SET_CPUUSED, cpu_used_start_);
      encoder->Control(VP9E_SET_ROW_MT, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
    }
    if (video->frame() == 100)
      encoder->Control(VP8E_SET_CPUUSED, cpu_used_end_);
  }

 private:
  int cpu_used_start_;
  int cpu_used_end_;
};

class EndToEndTestLarge
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith3Params<libvpx_test::TestMode,
                                                 TestVideoParam, int> {
 protected:
  EndToEndTestLarge()
      : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(2)),
        cpu_used_(GET_PARAM(3)), psnr_(0.0), nframes_(0),
        encoding_mode_(GET_PARAM(1)) {
    cyclic_refresh_ = 0;
    denoiser_on_ = 0;
  }

  virtual ~EndToEndTestLarge() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(encoding_mode_);
    if (encoding_mode_ != ::libvpx_test::kRealTime) {
      cfg_.g_lag_in_frames = 5;
      cfg_.rc_end_usage = VPX_VBR;
    } else {
      cfg_.g_lag_in_frames = 0;
      cfg_.rc_end_usage = VPX_CBR;
      cfg_.rc_buf_sz = 1000;
      cfg_.rc_buf_initial_sz = 500;
      cfg_.rc_buf_optimal_sz = 600;
    }
    dec_cfg_.threads = 4;
  }

  virtual void BeginPassHook(unsigned int) {
    psnr_ = 0.0;
    nframes_ = 0;
  }

  virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
    psnr_ += pkt->data.psnr.psnr[0];
    nframes_++;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
      encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
      if (encoding_mode_ != ::libvpx_test::kRealTime) {
        encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
        encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
        encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
        encoder->Control(VP8E_SET_ARNR_TYPE, 3);
      } else {
        encoder->Control(VP9E_SET_NOISE_SENSITIVITY, denoiser_on_);
        encoder->Control(VP9E_SET_AQ_MODE, cyclic_refresh_);
      }
    }
  }

  double GetAveragePsnr() const {
    if (nframes_) return psnr_ / nframes_;
    return 0.0;
  }

  double GetPsnrThreshold() {
    return kPsnrThreshold[cpu_used_][encoding_mode_];
  }

  TestVideoParam test_video_param_;
  int cpu_used_;
  int cyclic_refresh_;
  int denoiser_on_;

 private:
  double psnr_;
  unsigned int nframes_;
  libvpx_test::TestMode encoding_mode_;
};

TEST_P(EndToEndTestLarge, EndtoEndPSNRTest) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_profile = test_video_param_.profile;
  cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
  cfg_.g_bit_depth = test_video_param_.bit_depth;
  init_flags_ = VPX_CODEC_USE_PSNR;
  if (cfg_.g_bit_depth > 8) init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;

  std::unique_ptr<libvpx_test::VideoSource> video;
  if (is_extension_y4m(test_video_param_.filename)) {
    video.reset(new libvpx_test::Y4mVideoSource(test_video_param_.filename, 0,
                                                kFrames));
  } else {
    video.reset(new libvpx_test::YUVVideoSource(
        test_video_param_.filename, test_video_param_.fmt, kWidth, kHeight,
        kFramerate, 1, 0, kFrames));
  }
  ASSERT_TRUE(video.get() != NULL);

  ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
  const double psnr = GetAveragePsnr();
  EXPECT_GT(psnr, GetPsnrThreshold());
}

TEST_P(EndToEndTestLarge, EndtoEndPSNRDenoiserAQTest) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_profile = test_video_param_.profile;
  cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
  cfg_.g_bit_depth = test_video_param_.bit_depth;
  init_flags_ = VPX_CODEC_USE_PSNR;
  cyclic_refresh_ = 3;
  denoiser_on_ = 1;
  if (cfg_.g_bit_depth > 8) init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;

  std::unique_ptr<libvpx_test::VideoSource> video;
  if (is_extension_y4m(test_video_param_.filename)) {
    video.reset(new libvpx_test::Y4mVideoSource(test_video_param_.filename, 0,
                                                kFrames));
  } else {
    video.reset(new libvpx_test::YUVVideoSource(
        test_video_param_.filename, test_video_param_.fmt, kWidth, kHeight,
        kFramerate, 1, 0, kFrames));
  }
  ASSERT_TRUE(video.get() != NULL);

  ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
  const double psnr = GetAveragePsnr();
  EXPECT_GT(psnr, GetPsnrThreshold());
}

TEST_P(EndToEndTestAdaptiveRDThresh, EndtoEndAdaptiveRDThreshRowMT) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_threads = 2;
  ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
                                       0, 400);

  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}

VP9_INSTANTIATE_TEST_CASE(EndToEndTestLarge,
                          ::testing::ValuesIn(kEncodingModeVectors),
                          ::testing::ValuesIn(kTestVectors),
                          ::testing::ValuesIn(kCpuUsedVectors));

VP9_INSTANTIATE_TEST_CASE(EndToEndTestAdaptiveRDThresh,
                          ::testing::Values(5, 6, 7), ::testing::Values(8, 9));
}  // namespace
<commit_msg>vp9 rtc: change PSNR thresh.<commit_after>/*
 *  Copyright (c) 2014 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "memory"

#include "third_party/googletest/src/include/gtest/gtest.h"

#include "test/codec_factory.h"
#include "test/encode_test_driver.h"
#include "test/i420_video_source.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "test/yuv_video_source.h"

namespace {

const unsigned int kWidth = 160;
const unsigned int kHeight = 90;
const unsigned int kFramerate = 50;
const unsigned int kFrames = 20;
const int kBitrate = 500;
// List of psnr thresholds for speed settings 0-7 and 5 encoding modes
const double kPsnrThreshold[][5] = {
  { 36.0, 37.0, 37.0, 37.0, 37.0 }, { 35.0, 36.0, 36.0, 36.0, 36.0 },
  { 34.0, 35.0, 35.0, 35.0, 35.0 }, { 33.0, 34.0, 34.0, 34.0, 34.0 },
  { 32.0, 33.0, 33.0, 33.0, 33.0 }, { 28.0, 32.0, 32.0, 32.0, 32.0 },
  { 28.5, 31.0, 31.0, 31.0, 31.0 }, { 27.5, 30.0, 30.0, 30.0, 30.0 },
};

typedef struct {
  const char *filename;
  unsigned int input_bit_depth;
  vpx_img_fmt fmt;
  vpx_bit_depth_t bit_depth;
  unsigned int profile;
} TestVideoParam;

const TestVideoParam kTestVectors[] = {
  { "park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420, VPX_BITS_8, 0 },
  { "park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422, VPX_BITS_8, 1 },
  { "park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444, VPX_BITS_8, 1 },
  { "park_joy_90p_8_440.yuv", 8, VPX_IMG_FMT_I440, VPX_BITS_8, 1 },
#if CONFIG_VP9_HIGHBITDEPTH
  { "park_joy_90p_10_420_20f.y4m", 10, VPX_IMG_FMT_I42016, VPX_BITS_10, 2 },
  { "park_joy_90p_10_422_20f.y4m", 10, VPX_IMG_FMT_I42216, VPX_BITS_10, 3 },
  { "park_joy_90p_10_444_20f.y4m", 10, VPX_IMG_FMT_I44416, VPX_BITS_10, 3 },
  { "park_joy_90p_10_440.yuv", 10, VPX_IMG_FMT_I44016, VPX_BITS_10, 3 },
  { "park_joy_90p_12_420_20f.y4m", 12, VPX_IMG_FMT_I42016, VPX_BITS_12, 2 },
  { "park_joy_90p_12_422_20f.y4m", 12, VPX_IMG_FMT_I42216, VPX_BITS_12, 3 },
  { "park_joy_90p_12_444_20f.y4m", 12, VPX_IMG_FMT_I44416, VPX_BITS_12, 3 },
  { "park_joy_90p_12_440.yuv", 12, VPX_IMG_FMT_I44016, VPX_BITS_12, 3 },
#endif  // CONFIG_VP9_HIGHBITDEPTH
};

// Encoding modes tested
const libvpx_test::TestMode kEncodingModeVectors[] = {
  ::libvpx_test::kTwoPassGood, ::libvpx_test::kOnePassGood,
  ::libvpx_test::kRealTime
};

// Speed settings tested
const int kCpuUsedVectors[] = { 1, 2, 3, 5, 6, 7 };

int is_extension_y4m(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename) {
    return 0;
  } else {
    return !strcmp(dot, ".y4m");
  }
}

class EndToEndTestAdaptiveRDThresh
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith2Params<int, int> {
 protected:
  EndToEndTestAdaptiveRDThresh()
      : EncoderTest(GET_PARAM(0)), cpu_used_start_(GET_PARAM(1)),
        cpu_used_end_(GET_PARAM(2)) {}

  virtual ~EndToEndTestAdaptiveRDThresh() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(::libvpx_test::kRealTime);
    cfg_.g_lag_in_frames = 0;
    cfg_.rc_end_usage = VPX_CBR;
    cfg_.rc_buf_sz = 1000;
    cfg_.rc_buf_initial_sz = 500;
    cfg_.rc_buf_optimal_sz = 600;
    dec_cfg_.threads = 4;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(VP8E_SET_CPUUSED, cpu_used_start_);
      encoder->Control(VP9E_SET_ROW_MT, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 2);
    }
    if (video->frame() == 100)
      encoder->Control(VP8E_SET_CPUUSED, cpu_used_end_);
  }

 private:
  int cpu_used_start_;
  int cpu_used_end_;
};

class EndToEndTestLarge
    : public ::libvpx_test::EncoderTest,
      public ::libvpx_test::CodecTestWith3Params<libvpx_test::TestMode,
                                                 TestVideoParam, int> {
 protected:
  EndToEndTestLarge()
      : EncoderTest(GET_PARAM(0)), test_video_param_(GET_PARAM(2)),
        cpu_used_(GET_PARAM(3)), psnr_(0.0), nframes_(0),
        encoding_mode_(GET_PARAM(1)) {
    cyclic_refresh_ = 0;
    denoiser_on_ = 0;
  }

  virtual ~EndToEndTestLarge() {}

  virtual void SetUp() {
    InitializeConfig();
    SetMode(encoding_mode_);
    if (encoding_mode_ != ::libvpx_test::kRealTime) {
      cfg_.g_lag_in_frames = 5;
      cfg_.rc_end_usage = VPX_VBR;
    } else {
      cfg_.g_lag_in_frames = 0;
      cfg_.rc_end_usage = VPX_CBR;
      cfg_.rc_buf_sz = 1000;
      cfg_.rc_buf_initial_sz = 500;
      cfg_.rc_buf_optimal_sz = 600;
    }
    dec_cfg_.threads = 4;
  }

  virtual void BeginPassHook(unsigned int) {
    psnr_ = 0.0;
    nframes_ = 0;
  }

  virtual void PSNRPktHook(const vpx_codec_cx_pkt_t *pkt) {
    psnr_ += pkt->data.psnr.psnr[0];
    nframes_++;
  }

  virtual void PreEncodeFrameHook(::libvpx_test::VideoSource *video,
                                  ::libvpx_test::Encoder *encoder) {
    if (video->frame() == 0) {
      encoder->Control(VP9E_SET_FRAME_PARALLEL_DECODING, 1);
      encoder->Control(VP9E_SET_TILE_COLUMNS, 4);
      encoder->Control(VP8E_SET_CPUUSED, cpu_used_);
      if (encoding_mode_ != ::libvpx_test::kRealTime) {
        encoder->Control(VP8E_SET_ENABLEAUTOALTREF, 1);
        encoder->Control(VP8E_SET_ARNR_MAXFRAMES, 7);
        encoder->Control(VP8E_SET_ARNR_STRENGTH, 5);
        encoder->Control(VP8E_SET_ARNR_TYPE, 3);
      } else {
        encoder->Control(VP9E_SET_NOISE_SENSITIVITY, denoiser_on_);
        encoder->Control(VP9E_SET_AQ_MODE, cyclic_refresh_);
      }
    }
  }

  double GetAveragePsnr() const {
    if (nframes_) return psnr_ / nframes_;
    return 0.0;
  }

  double GetPsnrThreshold() {
    return kPsnrThreshold[cpu_used_][encoding_mode_];
  }

  TestVideoParam test_video_param_;
  int cpu_used_;
  int cyclic_refresh_;
  int denoiser_on_;

 private:
  double psnr_;
  unsigned int nframes_;
  libvpx_test::TestMode encoding_mode_;
};

TEST_P(EndToEndTestLarge, EndtoEndPSNRTest) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_profile = test_video_param_.profile;
  cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
  cfg_.g_bit_depth = test_video_param_.bit_depth;
  init_flags_ = VPX_CODEC_USE_PSNR;
  if (cfg_.g_bit_depth > 8) init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;

  std::unique_ptr<libvpx_test::VideoSource> video;
  if (is_extension_y4m(test_video_param_.filename)) {
    video.reset(new libvpx_test::Y4mVideoSource(test_video_param_.filename, 0,
                                                kFrames));
  } else {
    video.reset(new libvpx_test::YUVVideoSource(
        test_video_param_.filename, test_video_param_.fmt, kWidth, kHeight,
        kFramerate, 1, 0, kFrames));
  }
  ASSERT_TRUE(video.get() != NULL);

  ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
  const double psnr = GetAveragePsnr();
  EXPECT_GT(psnr, GetPsnrThreshold());
}

TEST_P(EndToEndTestLarge, EndtoEndPSNRDenoiserAQTest) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_profile = test_video_param_.profile;
  cfg_.g_input_bit_depth = test_video_param_.input_bit_depth;
  cfg_.g_bit_depth = test_video_param_.bit_depth;
  init_flags_ = VPX_CODEC_USE_PSNR;
  cyclic_refresh_ = 3;
  denoiser_on_ = 1;
  if (cfg_.g_bit_depth > 8) init_flags_ |= VPX_CODEC_USE_HIGHBITDEPTH;

  std::unique_ptr<libvpx_test::VideoSource> video;
  if (is_extension_y4m(test_video_param_.filename)) {
    video.reset(new libvpx_test::Y4mVideoSource(test_video_param_.filename, 0,
                                                kFrames));
  } else {
    video.reset(new libvpx_test::YUVVideoSource(
        test_video_param_.filename, test_video_param_.fmt, kWidth, kHeight,
        kFramerate, 1, 0, kFrames));
  }
  ASSERT_TRUE(video.get() != NULL);

  ASSERT_NO_FATAL_FAILURE(RunLoop(video.get()));
  const double psnr = GetAveragePsnr();
  EXPECT_GT(psnr, GetPsnrThreshold());
}

TEST_P(EndToEndTestAdaptiveRDThresh, EndtoEndAdaptiveRDThreshRowMT) {
  cfg_.rc_target_bitrate = kBitrate;
  cfg_.g_error_resilient = 0;
  cfg_.g_threads = 2;
  ::libvpx_test::I420VideoSource video("niklas_640_480_30.yuv", 640, 480, 30, 1,
                                       0, 400);

  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
}

VP9_INSTANTIATE_TEST_CASE(EndToEndTestLarge,
                          ::testing::ValuesIn(kEncodingModeVectors),
                          ::testing::ValuesIn(kTestVectors),
                          ::testing::ValuesIn(kCpuUsedVectors));

VP9_INSTANTIATE_TEST_CASE(EndToEndTestAdaptiveRDThresh,
                          ::testing::Values(5, 6, 7), ::testing::Values(8, 9));
}  // namespace
<|endoftext|>


<commit_before>#include "common.th"

// c <- multiplicand
// d <- multiplier
// b -> product
.global imul
imul:
    pushall(h,i,j)

    b <- 0
#if IMUL_EARLY_EXITS
    i <- d == 0
    i <- c == 0 + i
    i <- i <> 0
    jnzrel(i, L_done)
#endif

    h <- 1

    j <- d >> 31    // save sign bit in j
    j <- -j         // convert sign to flag
    d <- d ^ j      // adjust multiplier
    d <- d - j

L_top:
    // use constant 1 in h to combine instructions
    i <- d & h - 1
    i <- c &~ i
    b <- b + i
    c <- c << 1
    d <- d >> 1
    i <- d <> 0
    jnzrel(i, L_top)

    b <- b ^ j      // adjust product for signed math
    b <- b - j

L_done:
    popall(h,i,j)
    ret

<commit_msg>Make early exits, when active, more efficient<commit_after>#include "common.th"

// c <- multiplicand
// d <- multiplier
// b -> product
.global imul
imul:
#if IMUL_EARLY_EXITS
    b <- c == 0
    d <- d &~ b     // d = (c == 0) ? 0 : d
    b <- d <> 0
    jzrel(b, L_done)
#endif

    pushall(h,i,j)

    b <- 0
    h <- 1

    j <- d >> 31    // save sign bit in j
    j <- -j         // convert sign to flag
    d <- d ^ j      // adjust multiplier
    d <- d - j

L_top:
    // use constant 1 in h to combine instructions
    i <- d & h - 1
    i <- c &~ i
    b <- b + i
    c <- c << 1
    d <- d >> 1
    i <- d <> 0
    jnzrel(i, L_top)

    b <- b ^ j      // adjust product for signed math
    b <- b - j

    popall(h,i,j)
L_done:
    ret

<|endoftext|>