/*
 * Tests for the sys.process_updates() function
 */
BEGIN;
	-- Delete all registered update types and targets
	DELETE FROM sys.update_types;
	DELETE FROM sys.update_targets;
	
	-- Create a new update target / type which will be used in tests
	CREATE SCHEMA test
		CREATE TABLE test( test_id INT NOT NULL PRIMARY KEY );
	INSERT INTO sys.update_targets VALUES ( 1 , 'Test' , 'test' , 'test' );
	INSERT INTO sys.update_types VALUES ( 1 , 1 , 'Test 1' , 2 , '' , NULL , NULL );
	INSERT INTO sys.update_types VALUES ( 2 , 1 , 'Test 2' , 4 , '' , NULL , NULL );

	-- Replace sys.end_tick() with a function that inserts into some table
	CREATE TABLE end_tick_calls( tick_id BIGINT NOT NULL );
	CREATE OR REPLACE FUNCTION sys.end_tick( tick_id BIGINT )
		RETURNS VOID LANGUAGE SQL
		AS 'INSERT INTO end_tick_calls VALUES( $1 );';

	-- Create a sys.process_dummy_update() function that inserts into some other table
	CREATE TABLE process_update_calls( tick_id BIGINT NOT NULL );
	CREATE OR REPLACE FUNCTION sys.process_dummy_update( tick_id BIGINT )
		RETURNS VOID LANGUAGE SQL
		AS 'INSERT INTO process_update_calls VALUES( $1 );';

	-- Set the general batch size to 1
	SELECT sys.uoc_constant( 'game.batchSize' , '(test)' , 'Game updates' , 1 );
	
	-- Insert a few entries in the test table
	INSERT INTO test.test
		SELECT * FROM generate_series( 1 , 10 );

	-- ***** TESTS BEGIN HERE *****
	SELECT plan( 21 );
	
	/*
	 * Case:
	 *		Updates have not been processed yet,
	 *
	 * Expected results:
	 *		1) New updates of the first type have been marked for processing,
	 *		2) The quantity of updates marked for processing corresponds to game.batchSize
	 */
	UPDATE sys.updates
		SET update_state = 'FUTURE' , update_last = 1;
	SELECT diag_test_name( 'sys.process_updates() - General batch size - Return value' );
	SELECT ok( sys.process_updates( 1 ) = ROW( TRUE , 'Test 1'::TEXT ) );
	SELECT diag_test_name( 'sys.process_updates() - General batch size - Update type' );
	SELECT set_eq(
		$$ SELECT DISTINCT updtype_id FROM sys.updates WHERE update_state = 'PROCESSING'; $$ ,
		$$ VALUES ( 1 ) $$
	);
	SELECT diag_test_name( 'sys.process_updates() - General batch size - Update count' );
	SELECT is( COUNT(*)::INT , 1 ) FROM sys.updates WHERE update_state = 'PROCESSING';
	SELECT diag_test_name( 'sys.process_updates() - General batch size - sys.end_tick() not called' );
	SELECT is_empty( $$ SELECT * FROM end_tick_calls $$ );
	DELETE FROM end_tick_calls;

	/*
	 * Case:
	 *		Updates have not been processed yet,
	 *		Update type has a specific batch size,
	 *
	 * Expected results:
	 *		1) New updates have been marked for processing,
	 *		2) The quantity of updates marked for processing corresponds to the specific batch size 
	 *		3) sys.end_tick() has not been called 
	 */
	UPDATE sys.update_types SET updtype_batch_size = 2 WHERE updtype_id = 1;
	UPDATE sys.updates SET update_state = 'FUTURE' , update_last = 1;
	SELECT diag_test_name( 'sys.process_updates() - Specific batch size - Return value' );
	SELECT ok( sys.process_updates( 1 ) = ROW( TRUE , 'Test 1'::TEXT ) );
	SELECT diag_test_name( 'sys.process_updates() - Specific batch size - Update type' );
	SELECT set_eq(
		$$ SELECT DISTINCT updtype_id FROM sys.updates WHERE update_state = 'PROCESSING'; $$ ,
		$$ VALUES ( 1 ) $$
	);
	SELECT diag_test_name( 'sys.process_updates() - Specific batch size - Update count' );
	SELECT is( COUNT(*)::INT , 2 ) FROM sys.updates WHERE update_state = 'PROCESSING';
	SELECT diag_test_name( 'sys.process_updates() - Specific batch size - sys.end_tick() not called' );
	SELECT is_empty( $$ SELECT * FROM end_tick_calls $$ );
	DELETE FROM end_tick_calls;

	/*
	 * Case:
	 *		Some but not all updates of the first type have been processed,
	 *		Batch size is greater than the quantity of updates left to process for the type.
	 *
	 * Expected results:
	 *		1) All updates of the first type are marked either for processing or as processed.
	 *		2) sys.end_tick() has not been called
	 */
	UPDATE sys.update_types SET updtype_batch_size = 2 WHERE updtype_id = 1;
	UPDATE sys.updates SET update_state = 'FUTURE' , update_last = 1;
	UPDATE sys.updates
		SET update_state = 'PROCESSED'
		WHERE update_id IN (
			SELECT update_id FROM sys.updates WHERE updtype_id = 1 LIMIT 9
		);
	UPDATE sys.update_types SET updtype_batch_size = 2 WHERE updtype_id = 1;
	SELECT diag_test_name( 'sys.process_updates() - End of type updates - Return value' );
	SELECT ok( sys.process_updates( 1 ) = ROW( TRUE , 'Test 1'::TEXT ) );
	SELECT diag_test_name( 'sys.process_updates() - End of type updates - Update type' );
	SELECT set_eq(
		$$ SELECT DISTINCT updtype_id FROM sys.updates WHERE update_state <> 'FUTURE'; $$ ,
		$$ VALUES ( 1 ) $$
	);
	SELECT diag_test_name( 'sys.process_updates() - End of type updates - Update count' );
	SELECT is( COUNT(*)::INT , 10 ) FROM sys.updates WHERE update_state <> 'FUTURE';
	SELECT diag_test_name( 'sys.process_updates() - End of type updates - sys.end_tick() not called' );
	SELECT is_empty( $$ SELECT * FROM end_tick_calls $$ );
	DELETE FROM end_tick_calls;

	/*
	 * Case:
	 *		All updates of the first type have been processed.
	 *		No updates of the second type have been processed.
	 *
	 * Expected results:
	 *		1) Some updates from the second type have been marked for processing.
	 *		2) sys.end_tick() has not been called 
	 */
	UPDATE sys.updates SET update_state = 'FUTURE' , update_last = 1;
	UPDATE sys.updates
		SET update_state = 'PROCESSED'
		WHERE updtype_id = 1;
	SELECT diag_test_name( 'sys.process_updates() - Update type transition - Return value' );
	SELECT ok( sys.process_updates( 1 ) = ROW( TRUE , 'Test 2'::TEXT ) );
	SELECT diag_test_name( 'sys.process_updates() - Update type transition - Update type' );
	SELECT set_eq(
		$$ SELECT DISTINCT updtype_id FROM sys.updates WHERE update_state = 'PROCESSING'; $$ ,
		$$ VALUES ( 2 ) $$
	);
	SELECT diag_test_name( 'sys.process_updates() - Update type transition - Update count' );
	SELECT is( COUNT(*)::INT , 1 ) FROM sys.updates WHERE update_state = 'PROCESSING';
	SELECT diag_test_name( 'sys.process_updates() - Update type transition - sys.end_tick() not called' );
	SELECT is_empty( $$ SELECT * FROM end_tick_calls $$ );
	DELETE FROM end_tick_calls;

	/*
	 * Case:
	 *		There no updates to process
	 *		Updates are marked as 'PROCESSING'
	 *
	 * Expected results:
	 *		1) _has_more return value is FALSE,
	 *		2) All updates are marked as 'PROCESSED'
	 *		3) sys.end_tick() has been called.
	 */
	UPDATE sys.updates SET update_state = 'PROCESSING' , update_last = 1;
	SELECT diag_test_name( 'sys.process_updates() - No updates left - Return value' );
	SELECT ok( sys.process_updates( 1 ) = ROW( FALSE , NULL::TEXT ) );
	SELECT diag_test_name( 'sys.process_updates() - No updates left - All updates processed' );
	SELECT is_empty( $$ SELECT * FROM sys.updates WHERE update_state <> 'PROCESSED' $$ );
	SELECT diag_test_name( 'sys.process_updates() - No updates left - sys.end_tick() called' );
	SELECT set_eq( $$ SELECT * FROM end_tick_calls $$ , $$ VALUES ( 1 ) $$ );
	DELETE FROM end_tick_calls;
	
	/*
	 * Case:
	 *		The update type has an in-base processing function
	 *
	 * Expected result:
	 *		1) _process_externally return value is NULL
	 *		2) The processing function has been called.
	 */
	UPDATE sys.updates SET update_state = 'FUTURE' , update_last = 1;
	UPDATE sys.update_types
		SET updtype_batch_size = NULL , updtype_proc_name = 'process_dummy_update'
		WHERE updtype_id = 1;
	SELECT diag_test_name( 'sys.process_updates() - In-base processing - Return value' );
	SELECT ok( sys.process_updates( 1 ) = ROW( TRUE , NULL::TEXT ) );
	SELECT diag_test_name( 'sys.process_updates() - In-base processing - Processing function called' );
	SELECT set_eq( $$ SELECT * FROM process_update_calls $$ , $$ VALUES ( 1 ) $$ );

	SELECT * FROM finish( );
ROLLBACK;