--[[----------------------------------------------------------------------------

WFRxIndexStorePerformanceTest.lua

--------------------------------------------------------------------------------

ADOBE CONFIDENTIAL
------------------
Copyright 2020 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.

------------------------------------------------------------------------------]]

	-- Rx
local Rx = require 'Rx'
local Observable = Rx.Observable

	-- WF.core.os
local KSPathUtils = require 'KSPathUtils'
local WFFileUtils = require 'WFFileUtils'
local KSIdGenerator = require 'KSIdGenerator'

	-- WF.core.self_test
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFRxTestCase = require 'WFRxTestCase'
local WFTestFileUtils = require 'WFTestFileUtils'

	-- WF.core.utils
local WFRxDocStore = require 'WFRxDocStore'
local WFRxIndexStore = require 'WFRxIndexStore'


--------------------------------------------------------------------------------


--============================================================================--

local WFRxIndexStorePerformanceTest = {}

--------------------------------------------------------------------------------
local fakeCatalogId = KSIdGenerator.uuidInLowercaseHex()

local function getAssets( n ) 
	local assets = {}
	for i = 1, n do
		local assetId = KSIdGenerator.uuidInLowercaseHex()
		local revId = KSIdGenerator.uuidInLowercaseHex()
		local docValue = WFCatAssetTestUtils.createBaseAssetDocument( fakeCatalogId, assetId, revId, 'fakeSha256', '/fakePath' )
		docValue = WFCatAssetTestUtils.addBasicOzMetadataUpdate( docValue, fakeCatalogId, assetId, revId )
		docValue = WFCatAssetTestUtils.addOriginalPathToDocument( docValue, 'fakeSha256', '/fakePath' )
		assets[ i ] = docValue
	end
	return assets
end 

--------------------------------------------------------------------------------

local function getAlbumAssets( n )
	
	local albumAssets = {}
	for i = 1, n do
		albumAssets[ i ] = {
			_id = KSIdGenerator.uuidInLowercaseHex(),
			type = 'album_asset',
			asset = {
				id = KSIdGenerator.uuidInLowercaseHex()
			},
			album = {
				id = KSIdGenerator.uuidInLowercaseHex()
			}
		}
	 
	end
	
	return albumAssets
end

--------------------------------------------------------------------------------

local function addManyRxQueriesPerformanceTest( numReadThreads )
	local testName =  'rxTestManyRxQueries_' .. tostring( numReadThreads ) .. 'ROThreads_testPerformance'
	
	WFRxIndexStorePerformanceTest[ testName ] = function( rxTest )
	
		rxTest:setTimeLimit( 2000 )
		
		local folder = WFTestFileUtils.createTestFolder( rxTest, testName )
		
		local docStore = WFRxDocStore( KSPathUtils.child( folder, 'Managed Catalog.mcat' ) )
		
		local indexStore = WFRxIndexStore( docStore, 'WFCatIndexDefinitions.lua', numReadThreads )
		
		for i = 1, 500 do
			rxTest:waitFor( docStore:bulkSetDocValue( getAssets( 100 ) ) )
		end
		
		rxTest:expectSingleValue( indexStore:query( { sql = [[SELECT docId FROM assets]], quiesceUntilUpToDate = true } ):take(1):map( function( results ) return #results end ),
									50000 )
		
		rxTest:finally( function()
			docStore:close()
			indexStore:close()
			WFFileUtils.delete( folder )
		end )
		rxTest:sleep( 5 )
	
		rxTest:measurePerformance( 
			function()
				
				local numQueries = 1000
				local allQueries = {}
				for i = 1, numQueries do
					if i % 2 == 0 then
						allQueries[ i ] = indexStore:queryOnce( { 
											sql = [[SELECT docId FROM assets]],
						} )
					else
						allQueries[ i ] = docStore:bulkSetDocValue( getAlbumAssets( 100 ) ):map( function() return {} end ) 
					end
				end
		
				rxTest:expectSingleValue( Observable.combineLatest( unpack( allQueries ) )
					:map( function( ... )
						local results = { ... }
						local total = 0
						for _, result in ipairs( results ) do
							total = total + #result
						end
						return total
					end ), 50000 * ( numQueries / 2 ) )
					
			end )	
	end
	
end

addManyRxQueriesPerformanceTest( 0 )
addManyRxQueriesPerformanceTest( 1 )
addManyRxQueriesPerformanceTest( 2 )
addManyRxQueriesPerformanceTest( 4 )

--------------------------------------------------------------------------------

local function testQueryPerformance( rxTest, singleColumnQuery )

	rxTest:setTimeLimit( 2000 )

	local folder = WFTestFileUtils.createTestFolder( rxTest, rxTest:testName() )
		
	local docStore = WFRxDocStore( KSPathUtils.child( folder, 'Managed Catalog.mcat' ) )
		
	local indexStore = WFRxIndexStore( docStore, 'WFCatIndexDefinitions.lua', 0 )
		
	rxTest:finally( function()
		docStore:close()
		indexStore:close()
		WFFileUtils.delete( folder )
	end )
		
	for i = 1, 100 do
		rxTest:waitFor( docStore:bulkSetDocValue( getAssets( 100 ) ) )
	end

	rxTest:expectSingleValue( indexStore:query( { 
				sql = [[SELECT docId FROM assets]], 
				quiesceUntilUpToDate = true 
			} )
			:take(1)
			:map( function( results ) 
				return #results 
			end ), 10000 )

	rxTest:measurePerformance( 
		function()
			
			local numQueries = 1000
			local allQueries = {}
			
			for i = 1, numQueries do
				if singleColumnQuery then
					allQueries[ i ] = indexStore:queryOnce( { 
							sql = [[SELECT docId FROM assets]],
							singleColumnQuery = true,
					} )
				else
					allQueries[ i ] = indexStore:queryOnce( { 
							sql = [[SELECT docId FROM assets ]],
					} )
				end
			end
	
			rxTest:expectSingleValue( Observable.combineLatest( unpack( allQueries ) )
				:map( function( ... )
					local results = { ... }
					local total = 0
					for _, result in ipairs( results ) do
						total = total + #result
					end
					return total
				end ), 10000 * numQueries )
				
		end )	


end

--------------------------------------------------------------------------------

function WFRxIndexStorePerformanceTest.rxTestSingleColumnQuery_testPerformance( rxTest )

	testQueryPerformance( rxTest, true )

end

--------------------------------------------------------------------------------

function WFRxIndexStorePerformanceTest.rxTestNormalQuery_testPerformance( rxTest )

	testQueryPerformance( rxTest, false )

end

--------------------------------------------------------------------------------

return WFRxTestCase.wrapSuite( 'WFRxIndexStorePerformanceTest', WFRxIndexStorePerformanceTest )
