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

WFRxIndexStoreImpUtilsTest.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'

	-- WF.core.rxlua
local WFRxTestCase = require 'WFRxTestCase'

	-- WF.core.utils
local KSDate = require 'KSDate'
local KSTableUtils = require 'KSTableUtils'
local KSIdGenerator = require 'KSIdGenerator'

	-- WF.oz_client
local WFCatMockCatalog = require 'WFCatMockCatalog'

	-- WF.sqlite.index_store
local WFRxIndexStoreImpUtils = require 'WFRxIndexStoreImpUtils'

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

local WFRxIndexStoreImpUtilsTest = {}

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

function WFRxIndexStoreImpUtilsTest.rxTestThrottledQuery_throttleTimeRatio( rxTest )
	
	rxTest:setTimeLimit( 30 )
	
	local now = KSDate.timeNowForAnimation
	
	local updateObservable = Rx.ReplaySubject(10)
	
	local counter = 0
	
	local queryFn = function()
		local spinUntil = now() + 1
		while true do
			if now() > spinUntil then
				break
			end
		end
		counter = counter + 1
		return counter
	end
	
	local observer = rxTest:observe( WFRxIndexStoreImpUtils.throttledQuery( updateObservable, 4, queryFn ) )
	
	-- ensure multiple updates are squelched by the time ratio
	updateObservable:onNext( 1 )
	updateObservable:onNext( 1 )
	
	-- query time is 1s + 4s of delay, so wait up to 6s to get the second update
	observer:expectDataWithinTime( 6, 2 )
	
	-- ensure multiple updates are squelched by the time ratio
	updateObservable:onNext( 1 )
	updateObservable:onNext( 1 )
	updateObservable:onNext( 1 )
	updateObservable:onNext( 1 )
	
	-- query time is 1s + 4s of delay, so wait up to 6s to get the third update
	observer:expectDataWithinTime( 6, 3 )

end

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

function WFRxIndexStoreImpUtilsTest.rxTestFilterAndFormatQueryRequestStats( rxTest )

	-- Verifies the basic formatting and limiting of filterAndFormatQueryRequestStats

	local mockQueryResults = {}
	local expected = {}

	for i = 1, 2 do

		local stream = Rx.Subject()

		rxTest:finally( function()
			stream:dispose()
		end )

		local queryInfo = {
			sql = [[ SELECT FOO FROM BAR ]],
			relevantTables = { 'albums', 'assets' },
			nUpdatesSent = i,
			calm = i
		}

		local expectedEntry = KSTableUtils.deepCopy( queryInfo )
		expectedEntry.args = {}

		-- Add more than the maximum number of arguments returned by filterAndFormatQueryRequestStats
		-- This also tests the nested table limiting mechanism.

		for j = 1, 200 do

			if j == 1 then

				queryInfo[ j ] = {}
				expectedEntry.args[ j ] = {}

				for k = 1, 110 do

					queryInfo[ j ][ k ] = k

					if k <= 100 then
						expectedEntry.args[ j ][ k ] = k
					end

				end

				expectedEntry.args[ j ][ "_warning_" ]
						= string.format( "Only 100 of 110 arguments are included in this log." )

			else

				queryInfo[ j ] = j

				if j <= 100 then
					expectedEntry.args[ j ] = j
				end

			end

		end

		expectedEntry.args[ "_warning_" ]
				= string.format( "Only 100 of 200 arguments are included in this log." )

		mockQueryResults[ stream ] = queryInfo
		expected[ #expected + 1 ] = expectedEntry

	end

	local actual = WFRxIndexStoreImpUtils.filterAndFormatQueryRequestStats( mockQueryResults )

	rxTest:expectEqual( expected, actual )

end

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

function WFRxIndexStoreImpUtilsTest.rxTestGenericIndexStoreQuery( rxTest )
	
	local optArgs = {
		indexDefinitions = 'RxTestKeywords.lua'
	}

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, optArgs )
	
	local docId1 = KSIdGenerator.uuidInLowercaseHex()
	local docId2 = KSIdGenerator.uuidInLowercaseHex()
	local docId3 = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue {
		_id = docId1,
		keywords = {
			foo = true,
			bar = true,
			baz = true,
		}
	} )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue {
		_id = docId2,
		keywords = {
			bar = true,
			baz = true,
		}
	} )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue {
		_id = docId3,
		keywords = {
			bar = true,
		}
	} )
	
	local keys = { 'foo', 'bar' }
	
	local expectedBar = { docId1, docId2, docId3 }
	table.sort( expectedBar )
	
	rxTest:expectSingleValue( WFRxIndexStoreImpUtils.genericIndexStoreQuery( wfCatalog, 'keywords', 'keyword', keys )
			:map( function( result )
				for _, list in pairs( result ) do
					table.sort( list )
				end
				return result
			end ),
			{
				foo = {
					docId1
				},
				bar = expectedBar
			} 
		)
	
end

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

return WFRxTestCase.wrapSuite( 'WFRxIndexStoreImpUtilsTest', WFRxIndexStoreImpUtilsTest )
