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

WFCatVolumeAgentQueryHelperTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2021 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.

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

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

	-- WF.core.utils
local KSData = require 'KSData'
local KSDate = require 'KSDate'
local KSIdGenerator = require 'KSIdGenerator'
local KSPathUtils = require 'KSPathUtils'
local KSTableUtils = require 'KSTableUtils'
local WFFileUtils = require 'WFFileUtils'
local WFPlatformInfo = require 'WFPlatformInfo'

	-- WF.oz_client.managed_catalog
local WFCatAlbumTestUtils = require 'WFCatAlbumTestUtils'
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local WFCatDelete = require 'WFCatDelete'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFCatPurgeHelper = require 'WFCatPurgeHelper'
local WFCatVersionTestUtils = require 'WFCatVersionTestUtils'
local WFCatVolumeAgentQueryHelper = require 'WFCatVolumeAgentQueryHelper'

local LrmCatalogTestHelper, LrmConfig

if WFPlatformInfo.isMobile() then
	LrmCatalogTestHelper = require 'LrmCatalogTestHelper'
	LrmConfig = require 'LrmConfig'
end

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

local getBatchOfInactiveBinaries =
		assert( WFCatVolumeAgentQueryHelper.getBatchOfInactiveBinaries )
		
local getBatchOfPurgeableBinaries =
		assert( WFCatVolumeAgentQueryHelper.getBatchOfPurgeableBinaries )

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

local WFCatVolumeAgentQueryHelperTest = {}

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

local basePath = KSPathUtils.getStandardFilePath( 'carouselDocuments' )
local volumeGuid = WFPlatformInfo.isDesktop and WFFileUtils.getVolumeGuidForPath( basePath ) or nil

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

local function extractLocalId( rows )

	local mappedTbl = {}

	for k, row in pairs( rows ) do 
		
		mappedTbl[ k ] = row[ 1 ]

	end
	
	return mappedTbl

end

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

local function setUp( rxTest )

	local optArgs = {}

	if WFPlatformInfo.isMobile() then
		optArgs.indexDefinitions = 'LrmCatalogIndexDefinitions.lua'
	end

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest , nil, nil, optArgs )

	rxTest:finally( function()

		wfCatalog:close()

	end )

	return wfCatalog

end

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

local function getDateNDaysAgo( n )

	local daysToSeconds = function( days )
		return days * 24 * 60 * 60
	end

	local nDaysAgoInSeconds = KSDate.timeNow() - daysToSeconds( n )

	return KSDate.timeInIso8601Format( nDaysAgoInSeconds )

end

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

local function createAssetDoc( rxTest, wfCatalog, overrides )

	overrides = overrides or {}

	local assetId = overrides.assetId or KSIdGenerator.uuidInLowercaseHex()
	
	return WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, overrides )

end

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

local function createVersionDoc( rxTest, wfCatalog, overrides )

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	return WFCatVersionTestUtils.createVersionDocument( rxTest, wfCatalog, assetId, overrides )

end

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

-- @mark purgeCandidates Index Store Table Tests

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

function WFCatVolumeAgentQueryHelperTest.rxTestVerifyPurgeableBinariesTable( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = setUp( rxTest )
	local indexStore = wfCatalog:indexStore()
	
	-- Basic Original / Proxy / Develop Settings / Aux Test
	
	local doc
	local overrides = { hasAllAuxType = true }
	local purgeableDoc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	KSTableUtils.setNested( purgeableDoc, getDateNDaysAgo( 5 ), '_serverProvidedMetadata', 'updated' )
	rxTest:waitFor( wfCatalog:docStore():setDocValue( purgeableDoc ) )
	
	local originalSize = docInfo.originalFileSize
	
	if WFPlatformInfo.isDesktop then
		originalSize = originalSize + docInfo.xmpSidecarFileSize
	end
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							binarySize, fileSize, contentIdOrSha256
						FROM purgeCandidates
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
		}
		:map( function( rows )
		
			for _, row in ipairs( rows ) do
			
				if row[ 3 ] == 'aux' then
				
					rxTest:expectEqual( row[ 6 ] == docInfo.mask1Fingerprint
							or row[ 6 ] == docInfo.mask2Fingerprint
							or row[ 6 ] == docInfo.filter1Fingerprint
							or row[ 6 ] == docInfo.filter2Fingerprint
							or row[ 6 ] == docInfo.c2paFingerprint, true )
							
					row[ 6 ] = '<fingerprint>'
				
				end
			
			end
			
			return rows
		
		end ),
		
		{
			{ 1, 1, 'aux', nil, docInfo.mask1FileSize, '<fingerprint>' },
			{ 1, 1, 'aux', nil, docInfo.mask2FileSize, '<fingerprint>' },
			{ 1, 1, 'aux', nil, docInfo.filter1FileSize, '<fingerprint>' },
			{ 1, 1, 'aux', nil, docInfo.filter2FileSize, '<fingerprint>' },
			{ 1, 1, 'aux', nil, docInfo.c2paFileSize, '<fingerprint>' },
			{ 1, 1, 'original', nil, originalSize},
			{ 1, 1, 'proxy', '2560', docInfo.proxyFileSize },
			{ 1, 1, 'xmp_develop', nil, docInfo.xmpDevelopSettingsFileSize, docInfo.developSettingsSha256 }
		} )
	
	-- Marked For Offline Use Test
	
	if WFPlatformInfo.isDesktop then
	
		-- Mobile platforms do not include marked-for-offline-use status
		-- within the purgeCandidates table.
	
		overrides = { 
			hasAllAuxType = true,
			markedForOfflineUse = true
		}
		
		doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
		rxTest:waitFor( wfCatalog:docStore():setDocValue( doc ) )
		
		rxTest:expectSingleValue( indexStore:queryOnce {
				sql = [[ SELECT hasLocalFile, isPurgeable, binaryType, contentIdOrSha256
							FROM purgeCandidates
							WHERE docId == ?
							ORDER BY binaryType ]],
				quiesceUntilUpToDate = true,
				doc._id
			}
			:map( function( rows )
			
				for _, row in ipairs( rows ) do
				
					if row[ 3 ] == 'aux' then
					
						rxTest:expectEqual( row[ 4 ] == docInfo.mask1Fingerprint
								or row[ 4 ] == docInfo.mask2Fingerprint
								or row[ 4 ] == docInfo.filter1Fingerprint
								or row[ 4 ] == docInfo.filter2Fingerprint
								or row[ 4 ] == docInfo.c2paFingerprint, true )
								
						row[ 4 ] = '<fingerprint>'
					
					end
				
				end
				
				return rows
			
			end ),
			
			{
				{ 1, 0, 'aux', '<fingerprint>' },
				{ 1, 0, 'aux', '<fingerprint>' },
				{ 1, 0, 'aux', '<fingerprint>' },
				{ 1, 0, 'aux', '<fingerprint>' },
				{ 1, 0, 'aux', '<fingerprint>' },
				{ 1, 0, 'original' },
				{ 1, 0, 'proxy' },
				{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 }
			} )
	
	end

	-- Has resampled aux in _localOnly

	overrides = {
		hasSourceOnlyFilters = true,
		hasLocalResampledFilter  = true
	}
	
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():setDocValue( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							binarySize, fileSize, contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		}
		:map( function( rows )
		
			for _, row in ipairs( rows ) do
			
				if row[ 3 ] == 'aux' then
				
					rxTest:expectEqual( row[ 6 ] == docInfo.filter1Fingerprint
							or row[ 6 ] == docInfo.filter2Fingerprint, true )
							
					row[ 6 ] = '<fingerprint>'
				
				end
			
			end
			
			return rows
		
		end ),
		
		{
			{ 1, 1, 'aux', nil, docInfo.filter1FileSize, '<fingerprint>' },
			{ 1, 1, 'aux', nil, docInfo.filter2FileSize, '<fingerprint>' },
			{ 1, 1, 'original', nil, originalSize},
			{ 1, 1, 'proxy', '2560', docInfo.proxyFileSize },
			{ 1, 1, 'xmp_develop', nil, docInfo.xmpDevelopSettingsFileSize, docInfo.developSettingsSha256 }
		} )

	
	-- Oz Has No Original
	
	overrides = { noMasterLink = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
		
	-- Oz Has An Invalid Original
	
	overrides = { ozOriginalIsInvalid = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- Oz Has Corrupt Original (Sha256 Mismatch Error)
	
	overrides = { corruptMaster = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Local Original
	
	overrides = { noLocalOriginal = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 0, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
		
	-- Local Original is Invalid
	
	overrides = { localOriginalIsInvalid = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Renditions on Oz
	
	overrides = { 
		noSufficientRenditionFoundOnOz = true,
	}
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 1, 0, 'proxy' },
			{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Renditions on Oz & No Local Proxy
	
	overrides = { 
		noSufficientRenditionFoundOnOz = true,
		noLocalProxy = true
	}
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'original' },
			{ 0, 0, 'proxy' },
			{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Local Proxy
	
	overrides = { noLocalProxy = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 0, 1, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Proxy On Oz
	
	overrides = { noProxyLink = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 1, 0, 'proxy' },
			{ 1, 1, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Local Develop Settings
	
	overrides = { noLocalDevelopSettings = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 0, 1, 'xmp_develop' },
		} )
	
	-- No Develop Settings on Oz
	
	overrides = { noDevelopSettingsLink = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- Invalid Develop Settings on Oz
	
	overrides = { ozDevelopSettingsAreInvalid = true }
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- No Mask, filters, c2pa On Oz
	
	overrides = { 
		hasAllAuxType = true,
		noAllAuxTypeLinks = true
	}
	
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'aux' },
			{ 1, 0, 'aux' },
			{ 1, 0, 'aux' },
			{ 1, 0, 'aux' },
			{ 1, 0, 'aux' },
			{ 1, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop' }
		} )
	
	-- No Local Masks, filters and c2pa
	
	overrides = { 
		hasAllAuxType = true,
		noLocalAllAuxType = true
	}
	
	doc, docInfo = createAssetDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType
						FROM purgeCandidates
						WHERE docId == ?
						ORDER BY binaryType ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 0, 1, 'aux' },
			{ 0, 1, 'aux' },
			{ 0, 1, 'aux' },
			{ 0, 1, 'aux' },
			{ 0, 1, 'aux' },
			{ 1, 1, 'original' },
			{ 1, 1, 'proxy' },
			{ 1, 1, 'xmp_develop' }
		} )
	
end

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

function WFCatVolumeAgentQueryHelperTest.rxTestVerifyPurgeableBinariesTable_Versions( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = setUp( rxTest )
	local indexStore = wfCatalog:indexStore()
	
	-- Basic Develop Settings Test
	
	local doc
	local overrides = { hasAllAuxType = true }
	local purgeableDoc, docInfo = createVersionDoc( rxTest, wfCatalog, overrides )
	KSTableUtils.setNested( purgeableDoc, getDateNDaysAgo( 5 ), '_serverProvidedMetadata', 'updated' )
	rxTest:waitFor( wfCatalog:docStore():setDocValue( purgeableDoc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							binarySize, fileSize, contentIdOrSha256
						FROM purgeCandidates ]],
			quiesceUntilUpToDate = true,
		},	
		{
			{ 1, 1, 'xmp_develop', nil, docInfo.xmpDevelopSettingsFileSize, docInfo.developSettingsSha256 },
		} )
	
	-- No Local Develop Settings
	
	overrides = { noLocalDevelopSettings = true }
	doc, docInfo = createVersionDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ? ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 0, 1, 'xmp_develop' },
		} )
	
	-- No Develop Settings on Oz
	
	overrides = { noDevelopSettingsLink = true }
	doc, docInfo = createVersionDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ? ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
	-- Invalid Develop Settings on Oz
	
	overrides = { ozDevelopSettingsAreInvalid = true }
	doc, docInfo = createVersionDoc( rxTest, wfCatalog, overrides )
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( doc ) )
	
	rxTest:expectSingleValue( indexStore:queryOnce {
			sql = [[ SELECT hasLocalFile, isPurgeable, binaryType,
							contentIdOrSha256
						FROM purgeCandidates
						WHERE docId == ? ]],
			quiesceUntilUpToDate = true,
			doc._id
		},
		{
			{ 1, 0, 'xmp_develop', docInfo.developSettingsSha256 },
		} )
	
end

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

-- @mark Basic API Tests

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfPurgeableBinaries( rxTest )

	local wfCatalog = setUp( rxTest )
	
	rxTest:setTimeLimit( 10 )

	local docs = {}
	
	for i=1, 10, 1 do
	
		local doc = createAssetDoc( rxTest, wfCatalog )
		
		if i % 2 == 0 then
			KSTableUtils.setNested( doc, getDateNDaysAgo( i / 10 ), '_serverProvidedMetadata', 'updated' )
				-- Even Assets should be important because they've been updated recently
		else
			KSTableUtils.setNested( doc, getDateNDaysAgo( i * 100 ), '_serverProvidedMetadata', 'updated' )
				-- Odd Assets should *not* be important because they have not been updated recently.
		end
		
		docs[ #docs + 1 ] = doc
		
	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	-- Verify Sort Order: dateLastUpdatedInSeconds

	local expectedLocalIds = { 9, 7, 5, 3, 1, 10, 8, 6, 4, 2 }
	
	local purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'original', volumeGuid )

	rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )
	
	-- Verify Batching
	
	expectedLocalIds = { 9, 7, 5 }
	
	local limit = 3 
	local offset = nil
	
	local getNextBatch
	
	rxTest:expectSingleValue( getBatchOfPurgeableBinaries( wfCatalog, 'original', volumeGuid, limit, offset )
	
		:map( function( results, nextBatchFn )
		
			getNextBatch = nextBatchFn
			return results
		
		end )
		:map( extractLocalId ), expectedLocalIds )
	
	expectedLocalIds = { 3, 1, 10 }
	
	rxTest:expectSingleValue( getNextBatch()
		:map( extractLocalId ), expectedLocalIds )
		
	-- Verify Offset
	
	expectedLocalIds = { 4 }
	
	limit = 1 
	offset = 8
	
	rxTest:expectSingleValue( getBatchOfPurgeableBinaries( wfCatalog, 'original', volumeGuid, limit, offset )
	
		:map( function( results, nextBatchFn )
		
			getNextBatch = nextBatchFn
			return results
		
		end )
		:map( extractLocalId ), expectedLocalIds )
	
	expectedLocalIds = { 2 }
	
	rxTest:expectSingleValue( getNextBatch()
		:map( function( results, nextBatchFn )
		
			getNextBatch = nextBatchFn
			return results
		
		end )
		:map( extractLocalId ), expectedLocalIds )
	
	expectedLocalIds = {}
	
	rxTest:expectSingleValue( getNextBatch()
		:map( extractLocalId ), expectedLocalIds )
	
end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfInactiveBinaries( rxTest )

	local wfCatalog = setUp( rxTest )
	
	rxTest:setTimeLimit( 10 )

	local docs = {}


	for i=1, 10, 1 do
	
		local doc = createAssetDoc( rxTest, wfCatalog )
		
		if i % 2 == 0 then
			KSTableUtils.setNested( doc, getDateNDaysAgo( i / 10 ), '_serverProvidedMetadata', 'updated' )
				-- Even Assets should be important because they've been updated recently
		else
			KSTableUtils.setNested( doc, getDateNDaysAgo( i * 100 ), '_serverProvidedMetadata', 'updated' )
				-- Odd Assets should *not* be important because they have not been updated recently.
		end
		
		docs[ #docs + 1 ] = doc
		
	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	-- Verify Sort Order: dateLastUpdatedInSeconds

	local expectedLocalIds = { 9, 7, 5, 3, 1 }
	
	local purgeCandidatesStream = getBatchOfInactiveBinaries( wfCatalog, 'original', volumeGuid )

	rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )
	
	-- Verify Batching
	
	expectedLocalIds = { 9, 7, 5 }
	
	local limit = 3 
	local offset = nil
	
	local getNextBatch
	
	rxTest:expectSingleValue( getBatchOfInactiveBinaries( wfCatalog, 'original', volumeGuid, limit, offset )
	
		:map( function( results, nextBatchFn )
		
			getNextBatch = nextBatchFn
			return results
		
		end )
		:map( extractLocalId ), expectedLocalIds )
	
	expectedLocalIds = { 3, 1 }
	
	rxTest:expectSingleValue( getNextBatch()
		:map( extractLocalId ), expectedLocalIds )
		
	-- Verify Offset
	
	expectedLocalIds = { 3 }
	
	limit = 1 
	offset = 3
	
	rxTest:expectSingleValue( getBatchOfInactiveBinaries( wfCatalog, 'original', volumeGuid, limit, offset )
	
		:map( function( results, nextBatchFn )
		
			getNextBatch = nextBatchFn
			return results
		
		end )
		:map( extractLocalId ), expectedLocalIds )
	
	expectedLocalIds = { 1 }
	
	rxTest:expectSingleValue( getNextBatch()
		:map( function( results, nextBatchFn )
		
			getNextBatch = nextBatchFn
			return results
		
		end )
		:map( extractLocalId ), expectedLocalIds )
	
	expectedLocalIds = {}
	
	rxTest:expectSingleValue( getNextBatch()
		:map( extractLocalId ), expectedLocalIds )
	
end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfPurgeableBinaries_DifferentBinaryTypes( rxTest )

	local wfCatalog = setUp( rxTest )

	rxTest:setTimeLimit( 10 )

	local docs = {}
	
	for i=1, 10, 1 do
	
		local overrides

		if i % 3 == 0 then
			overrides = { hasMasks = true }
		elseif i % 3 == 1 then
			overrides = { hasFilters = true }
		else
			overrides = { hasC2pa = true }
		end

		local doc = createAssetDoc( rxTest, wfCatalog, overrides )
		
		if i % 2 == 0 then
			KSTableUtils.setNested( doc, getDateNDaysAgo( i / 10 ), '_serverProvidedMetadata', 'updated' )
				-- Even Assets should be important because they've been updated recently
		else
			KSTableUtils.setNested( doc, getDateNDaysAgo( i * 100 ), '_serverProvidedMetadata', 'updated' )
				-- Odd Assets should *not* be important because they have not been updated recently.
		end
		
		docs[ #docs + 1 ] = doc
		
	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	-- Verify Sort Order: dateLastUpdatedInSeconds

	local expectedLocalIds = { 9, 7, 5, 3, 1, 10, 8, 6, 4, 2 }
	
	local purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'original', volumeGuid )
	rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )

	purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'proxy', volumeGuid )
	rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )
	
	purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'xmp_develop', volumeGuid )
	rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )
	
	purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'aux', volumeGuid )
	rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )
	
	if WFPlatformInfo.isMobile() then
	
		purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'thumbnail2x', volumeGuid )
		rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )
		
		purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'preview', volumeGuid )
		rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )

		purgeCandidatesStream = getBatchOfPurgeableBinaries( wfCatalog, 'fullsize', volumeGuid )
		rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), expectedLocalIds )

	end
	
end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGroupResultsByDoc( rxTest )

	local rows = {
		 { 1, '111', 5, 'a' },
		 { 1, '111', 10, 'b' },
		 { 2, '222', 50, 'c' },
		 { 2, '222', 100, 'd' },
		 { 1, '111', 1, 'e' },
		 { 2, '222', 7, 'f' },
		 { 3, '333', 1000, 'y' },
		 { 3, '333', 500, 'x' },
		 { 4, '444', 2000, 'z' },
	 }
	
	local expected = {
		{ 1, '111', 16, { 'a', 'b', 'e' } },
		{ 2, '222', 157, { 'c', 'd', 'f' } },
		{ 3, '333', 1500, { 'y', 'x' } },
		{ 4, '444', 2000, { 'z' } },
	}
	
	local actual = WFCatVolumeAgentQueryHelper._DEBUG_groupResultsByDoc( rows )
	
	rxTest:expectEqual( expected, actual )
	
end

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

-- @mark BinaryType Specific API Tests

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

local function generateAlbumAsset( albumId, assetId )

	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()

	return {

		type = 'album_asset',
		_id = albumAssetId,
		album = {
			id = albumId,
		},
		asset = {
			id = assetId,
		}

	}
		
end

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

local function addAssetDocToOfflineAlbum( doc, optAbumId )

	local albumId = optAbumId or KSIdGenerator.uuidInLowercaseHex()

	local albumDoc = {
		type = 'album',
		subtype = 'collection',
		_id = albumId,
		name = 'foo',
		_localOnly = {
			useOffline = true,
		}
	}
		
	local albumAssetDoc = generateAlbumAsset( albumId, doc._id )
	
	return { doc, albumDoc, albumAssetDoc }

end

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

local function createAssetDocs( rxTest, wfCatalog, binaryType, optArgs )

	local docs = {}
	
	local docOverrides = {
		hasMasks = true,
		noMaskLinks = binaryType ~= 'aux',
		hasFilters = true,
		noFilterLinks = binaryType ~= 'aux',
		hasC2pa = true,
		noC2paLink = binaryType ~= 'aux',
		noLocalOriginal = binaryType ~= 'original',
		noLocalProxy = binaryType ~= 'proxy',
		noLocalDevelopSettings = binaryType ~= 'xmp_develop',
		noLocalPreview = binaryType ~= 'preview',
		noLocalThumbnail2x = binaryType ~= 'thumbnail2x',
		noLocalFullsize = binaryType ~= 'fullsize',	
	}
	
	
	if binaryType == 'proxy' then
	
		local binarySize = optArgs.binarySize
	
		docOverrides.hasLocal2560Proxy = false
		docOverrides.isPanorama = false
		docOverrides.hasLocalFullsizeProxy = false
		docOverrides.hasLocal1080p = false
		docOverrides.hasLocal720p = false
		docOverrides.hasLocal360p = false
		
		if binarySize == 'mixed' then
			docOverrides.docSubtype = 'video'
			docOverrides.hasLocal1080p = true
			docOverrides.hasLocal360p = true
		elseif binarySize == '2560' then
			docOverrides.hasLocal2560Proxy = true
		elseif binarySize == 'panorama' then
			docOverrides.isPanorama = true
			docOverrides.hasLocalPanoramaProxy = true
		elseif binarySize == 'fullsize' then
			docOverrides.hasLocalFullsizeProxy = true
		elseif binarySize == '1080p709' then
			docOverrides.docSubtype = 'video'
			docOverrides.hasLocal1080p709 = true
		elseif binarySize == '1080p' then
			docOverrides.docSubtype = 'video'
			docOverrides.hasLocal1080p = true
		elseif binarySize == '720p' then
			docOverrides.docSubtype = 'video'
			docOverrides.hasLocal720p = true
		elseif binarySize == '360p' then
			docOverrides.docSubtype = 'video'
			docOverrides.hasLocal360p = true
		end
	
	end
	
	if optArgs.sharedDevelopSettings then
		docOverrides.sharedDevelopSettings = true
	end
	
	if optArgs.sharedMasks then
		docOverrides.sharedMasks = true
		docOverrides.hasFilters = nil
		docOverrides.noFilterLinks = nil
		docOverrides.hasC2pa = nil
		docOverrides.noC2paLink = nil
	end
	
	local function markForOfflineUseAndAppendToDocs( doc )
	
		if WFPlatformInfo.isMobile() then
			
			docs = KSTableUtils.appendArray( docs, addAssetDocToOfflineAlbum( doc ) )
		
		else
		
			KSTableUtils.setNested( doc, true, '_localOnly', 'isMarkedForOfflineUse' )
			docs[ #docs + 1 ] = doc
		
		end
		
	end
	
	for i = 1, 4, 1 do
	
		local doc = createAssetDoc( rxTest, wfCatalog, docOverrides )
		
		if i == 1 then
		
			KSTableUtils.setNested( doc, getDateNDaysAgo( i * 100 ), '_serverProvidedMetadata', 'updated' )
				-- Should *not* be important because they have not been updated recently.
				-- Unimportant assets are considered inactive.
				
			docs[ #docs + 1 ] = doc
				
		elseif i == 2 then
		
			KSTableUtils.setNested( doc, getDateNDaysAgo( i / 10 ), '_serverProvidedMetadata', 'updated' )
				-- Should be important because they've been updated recently.
				-- This should not be considered for INACTIVE purge.
		
			if optArgs.noDevelopSettingsLink or optArgs.noAuxLinks then
				doc._serverProvidedMetadata = nil
			end
		
			if optArgs.markedForOfflineUse then
				markForOfflineUseAndAppendToDocs( doc )
			else
				docs[ #docs + 1 ] = doc
			end
			
		elseif binaryType ~= 'aux' and binaryType ~= 'xmp_develop' then
		
			if i == 3 then
			
				-- Should not be considered for purge because the asset is marked for offline use.
				
				markForOfflineUseAndAppendToDocs( doc )
			
			elseif i == 4 then
			
				-- Should not be considered for purge because the asset is not synced.
			
				doc._serverProvidedMetadata = nil
				docs[ #docs + 1 ] = doc
			
			end
		
		end

	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )
	
	return docs

end

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

local function mapAwayDocIdAndSize( results )

	-- These fields are verified in other tests.

	for i, result in ipairs( results ) do
			
		result[ 2 ] = '<docId>'
		result[ 3 ] = '<size>'
		
	end

	return results

end

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

local function setupGetBatchOfBinariesTest( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )

	-- Create some documents with only local binaries of the specified type.

	local wfCatalog = setUp( rxTest )
	
	optArgs = optArgs or {}
	
	local docs = createAssetDocs( rxTest, wfCatalog, binaryType, optArgs )
	
		-- Verify the results from WFCatVolumeAgentQueryHelper
	
	local getBatchFn = getBatchOfPurgeableBinaries
	
	if optArgs.inactiveAssetsOnly then
	
		getBatchFn = getBatchOfInactiveBinaries
		
	end
	
	-- Verify that no other binaries are purgeable.
	
	local otherBinaryTypes = {
		original = true,
		proxy = true,
		xmp_develop = true,
		preview = true,
		thumbnail2x = true,
		fullsize = true,
		aux = true
	}
	
	otherBinaryTypes[ binaryType ] = nil
	
	for otherBinaryType in pairs( otherBinaryTypes ) do
	
		local purgeCandidatesStream = getBatchFn( wfCatalog, otherBinaryType, volumeGuid )
		rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), {} )
	
	end
	
	local purgeCandidatesStream = getBatchFn( 
			wfCatalog, binaryType, volumeGuid )
			
		:map( mapAwayDocIdAndSize )
	
	return purgeCandidatesStream, docs
	
end

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

local function setupGetBatchOfInactiveBinariesTest( rxTest, binaryType, optArgs )

	optArgs = optArgs or {}
	
	optArgs.inactiveAssetsOnly = true

	return setupGetBatchOfBinariesTest( rxTest, binaryType, optArgs )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Originals( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'original' )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", {}
		},
		{
			2, "<docId>", "<size>", {}
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Originals( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'original' )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", {}
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Mixed( rxTest )
	
	local optArgs = {
		binarySize = 'mixed',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '1080p', '360p' }
		},
		{
			2, "<docId>", "<size>", { '1080p', '360p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Mixed( rxTest )
	
	local optArgs = {
		binarySize = 'mixed',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '1080p', '360p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Image_2560( rxTest )
	
	local optArgs = {
		binarySize = '2560',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '2560' }
		},
		{
			2, "<docId>", "<size>", { '2560' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Image_2560( rxTest )
	
	local optArgs = {
		binarySize = '2560',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '2560' }
		}
	} )

end

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

if WFPlatformInfo.isDesktop then

-- Mobile Does not currently support Panorama or Full Size Proxies

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Image_Panoroma( rxTest )
	
	local optArgs = {
		binarySize = 'panorama',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { 'panorama' }
		},
		{
			2, "<docId>", "<size>", { 'panorama' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Image_Panorama( rxTest )
	
	local optArgs = {
		binarySize = 'panorama',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { 'panorama' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Image_Fullsize( rxTest )
	
	local optArgs = {
		binarySize = 'fullsize',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { 'fullsize' }
		},
		{
			2, "<docId>", "<size>", { 'fullsize' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Image_Fullsize( rxTest )
	
	local optArgs = {
		binarySize = 'fullsize',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { 'fullsize' }
		}
	} )

end

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Video_1080p( rxTest )
	
	local optArgs = {
		binarySize = '1080p',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '1080p' }
		},
		{
			2, "<docId>", "<size>", { '1080p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Video_1080p( rxTest )
	
	local optArgs = {
		binarySize = '1080p',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '1080p' }
		}
	} )

end

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

if WFPlatformInfo.isDesktop then

-- 720p "proxies" only exist within LrD.

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Video_720p( rxTest )
	
	local optArgs = {
		binarySize = '720p',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '720p' }
		},
		{
			2, "<docId>", "<size>", { '720p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Video_720p( rxTest )
	
	local optArgs = {
		binarySize = '720p',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '720p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Video_1080p709( rxTest )
	
	local optArgs = {
		binarySize = '1080p709',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '1080p709' }
		},
		{
			2, "<docId>", "<size>", { '1080p709' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Video_1080p709( rxTest )
	
	local optArgs = {
		binarySize = '1080p709',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '1080p709' }
		}
	} )

end

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Proxies_Video_360p( rxTest )
	
	local optArgs = {
		binarySize = '360p',
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'proxy', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '360p' }
		},
		{
			2, "<docId>", "<size>", { '360p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Proxies_Video_360p( rxTest )
	
	local optArgs = {
		binarySize = '360p',
	}
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'proxy', optArgs )
		
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", { '360p' }
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_DevelopSettings( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'xmp_develop' )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_DevelopSettings( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'xmp_develop' )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_DevelopSettings_Shared( rxTest )
	
	local optArgs = {
		sharedDevelopSettings = true,
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'xmp_develop', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_DevelopSettings_Shared_NotPurgeable( rxTest )
	
	local optArgs = {
		sharedDevelopSettings = true,
		noDevelopSettingsLink = true
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'xmp_develop', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_DevelopSettings_Shared_OfflineUse( rxTest )
	
	local optArgs = {
		sharedDevelopSettings = true,
		markedForOfflineUse = true
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'xmp_develop', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {} )

end

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

local function getAuxFingerprints( docs, docIndex )
	
	local docValue = docs[ docIndex ]

	local auxObjects = KSTableUtils.derefOpt( docValue, 'aux' )

	local fingerprints = {}

	for _, aux in pairs( auxObjects ) do
	
		fingerprints[ #fingerprints + 1 ] = aux.digest
		
	end

	table.sort( fingerprints )

	return fingerprints

end

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

local function sortFingerprints( purgeCandidates )

	for _, candidate in pairs( purgeCandidates ) do

		local fingerprints = candidate[ 4 ] or {}

		table.sort( fingerprints )

	end

	return purgeCandidates

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Masks( rxTest )
	
	local purgeCandidatesStream, docs = setupGetBatchOfBinariesTest( rxTest, 'aux' )
	
	purgeCandidatesStream = purgeCandidatesStream:map( sortFingerprints )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", getAuxFingerprints( docs, 1 )
		},
		{
			2, "<docId>", "<size>", getAuxFingerprints( docs, 2 )
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Masks( rxTest )
	
	local purgeCandidatesStream, docs = setupGetBatchOfInactiveBinariesTest( rxTest, 'aux' )
	
	purgeCandidatesStream = purgeCandidatesStream:map( sortFingerprints )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", getAuxFingerprints( docs, 1 )
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Masks_Shared( rxTest )
	
	local optArgs = {
		sharedMasks = true 
	}
	
	local purgeCandidatesStream, docs = setupGetBatchOfBinariesTest( rxTest, 'aux', optArgs )
	
	purgeCandidatesStream = purgeCandidatesStream:map( sortFingerprints )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>", getAuxFingerprints( docs, 1 )
		},
		{
			2, "<docId>", "<size>", getAuxFingerprints( docs, 2 )
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Masks_Shared_NotPurgeable( rxTest )
	
	local optArgs = {
		sharedMasks = true,
		noAuxLinks = true
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'aux', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Masks_Shared_OfflineUse( rxTest )
	
	local optArgs = {
		sharedMasks = true,
		markedForOfflineUse = true
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'aux', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {} )

end

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

-- @mark Mobile BinaryType Specific API Tests

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

if WFPlatformInfo.isMobile() then

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Previews( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'preview' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Previews( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'preview' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Thumbnail2xs( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'thumbnail2x' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Thumbnail2xs( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'thumbnail2x' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Fullsize( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest( rxTest, 'fullsize' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Inactive_Fullsize( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest( rxTest, 'fullsize' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		}
	} )

end

end

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

-- @mark Version BinaryType Specific API Tests

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

local function addVersionDocToOfflineAlbum( rxTest, wfCatalog, versionDoc )

	local assetId = versionDoc.asset.id

	local albumId = KSIdGenerator.uuidInLowercaseHex()

	local albumDoc = {
		type = 'album',
		subtype = 'collection',
		_id = albumId,
		name = 'foo',
		_localOnly = {
			useOffline = true,
		}
	}
	
	local overrides = {
		assetId = assetId
	}
	
	local assetDoc = createAssetDoc( rxTest, wfCatalog, overrides )
	
	local albumAssetDoc = generateAlbumAsset( albumId, assetId )
	
	return { versionDoc, assetDoc, albumDoc, albumAssetDoc }

end

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

local function createVersionDocs( rxTest, wfCatalog, binaryType, optArgs )

	local docs = {}
	
	local docOverrides = {
		hasMasks = true,
		noMaskLinks = binaryType ~= 'aux',
		hasFilters = true,
		noFilterLinks = binaryType ~= 'aux',
		noLocalThumbnail2x = binaryType ~= 'thumbnail2x',
		noLocalDevelopSettings = binaryType ~= 'xmp_develop'
	}
	
	if optArgs.sharedDevelopSettings then
		docOverrides.sharedDevelopSettings = true
	end
	
	if optArgs.sharedMasks then
		docOverrides.sharedMasks = true
		docOverrides.hasFilters = nil
		docOverrides.noFilterLinks = nil
	end
	
	local function markForOfflineUseAndAppendToDocs( doc )
	
		if WFPlatformInfo.isMobile() then
			
			docs = KSTableUtils.appendArray( docs, addVersionDocToOfflineAlbum( rxTest, wfCatalog, doc ) )
		
		else
		
			KSTableUtils.setNested( doc, true, '_localOnly', 'isMarkedForOfflineUse' )
			docs[ #docs + 1 ] = doc
		
		end
		
	end
	
	for i = 1, 4, 1 do
	
		local doc = createVersionDoc( rxTest, wfCatalog, docOverrides )
		
		if i == 1 then
		
			KSTableUtils.setNested( doc, getDateNDaysAgo( i * 100 ), '_serverProvidedMetadata', 'updated' )
				-- Should *not* be important because they have not been updated recently.
				-- Unimportant assets are considered inactive.
				
			docs[ #docs + 1 ] = doc
				
		elseif i == 2 then
		
			KSTableUtils.setNested( doc, getDateNDaysAgo( i / 10 ), '_serverProvidedMetadata', 'updated' )
				-- Should be important because they've been updated recently.
				-- This should not be considered for INACTIVE purge.
		
			if optArgs.noDevelopSettingsLink or optArgs.noMaskLinks then
				doc._serverProvidedMetadata = nil
			end
		
			if optArgs.markedForOfflineUse then
				markForOfflineUseAndAppendToDocs( doc )
			else
				docs[ #docs + 1 ] = doc
			end
			
		elseif binaryType ~= 'aux' and binaryType ~= 'xmp_develop' then
		
			if i == 3 then
			
				-- Should not be considered for purge because the asset is marked for offline use.
				
				markForOfflineUseAndAppendToDocs( doc )
			
			elseif i == 4 then
			
				-- Should not be considered for purge because the asset is not synced.
			
				doc._serverProvidedMetadata = nil
				docs[ #docs + 1 ] = doc
			
			end
		
		end

	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	return docs

end

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

local function setupGetBatchOfBinariesTest_Versions( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )

	-- Create some documents with only local binaries of the specified type.

	local wfCatalog = setUp( rxTest )
	
	optArgs = optArgs or {}
	
	local docs = createVersionDocs( rxTest, wfCatalog, binaryType, optArgs )
	
		-- Verify the results from WFCatVolumeAgentQueryHelper
	
	local getBatchFn = getBatchOfPurgeableBinaries
	
	if optArgs.inactiveAssetsOnly then
	
		getBatchFn = getBatchOfInactiveBinaries
		
	end
	
	-- Verify that no other binaries are purgeable.
	
	local otherBinaryTypes = {
		xmp_develop = true,
		thumbnail2x = true,
		aux = true
	}
	
	otherBinaryTypes[ binaryType ] = nil
	
	for otherBinaryType in pairs( otherBinaryTypes ) do
	
		local purgeCandidatesStream = getBatchFn( wfCatalog, otherBinaryType, volumeGuid )
		rxTest:expectSingleValue( purgeCandidatesStream:map( extractLocalId ), {} )
	
	end
	
	local purgeCandidatesStream = getBatchFn( 
			wfCatalog, binaryType, volumeGuid )
			
		:map( mapAwayDocIdAndSize )
	
	return purgeCandidatesStream, docs
	
end

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

local function setupGetBatchOfInactiveBinariesTest_Versions( rxTest, binaryType, optArgs )

	optArgs = optArgs or {}
	
	optArgs.inactiveAssetsOnly = true

	return setupGetBatchOfBinariesTest_Versions( rxTest, binaryType, optArgs )

end

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

if WFPlatformInfo.isMobile() then

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_Thumbnail2xs( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest_Versions( rxTest, 'thumbnail2x' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_Inactive_Thumbnail2xs( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest_Versions( rxTest, 'thumbnail2x' )

	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		}
	} )

end

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_DevelopSettings( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest_Versions( rxTest, 'xmp_develop' )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_Inactive_DevelopSettings( rxTest )
	
	local purgeCandidatesStream = setupGetBatchOfInactiveBinariesTest_Versions( rxTest, 'xmp_develop' )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_DevelopSettings_Shared( rxTest )
	
	local optArgs = {
		sharedDevelopSettings = true,
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest_Versions( rxTest, 'xmp_develop', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {
		{
			1, "<docId>", "<size>"
		},
		{
			2, "<docId>", "<size>"
		}
	} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_DevelopSettings_Shared_NotPurgeable( rxTest )
	
	local optArgs = {
		sharedDevelopSettings = true,
		noDevelopSettingsLink = true
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest_Versions( rxTest, 'xmp_develop', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetBatchOfBinaries_Versions_DevelopSettings_Shared_OfflineUse( rxTest )
	
	local optArgs = {
		sharedDevelopSettings = true,
		markedForOfflineUse = true
	}
	
	local purgeCandidatesStream = setupGetBatchOfBinariesTest_Versions( rxTest, 'xmp_develop', optArgs )
	
	rxTest:expectSingleValue( purgeCandidatesStream, {} )

end

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

-- @mark Size API Tests

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

local function createFakeWFCatalog( rxTest )

	if WFPlatformInfo.isAndroid then
	
		local catalogService, wfCatalog = LrmCatalogTestHelper.makeCatalogService( rxTest )
		local dataCache = rxTest:getFirstValue( catalogService:getDataCache() )

		return wfCatalog, dataCache

	else

		local optArgs = {}
			
		if WFPlatformInfo.isiOS then
			optArgs.indexDefinitions = 'LrmCatalogIndexDefinitions.lua'
		end

		return WFCatMockCatalog.createFakeWFCatalog( rxTest , nil, nil, optArgs )

	end

end

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

local function markForOfflineUseAndAppendToDocs( docs, assetDoc, optAlbumId )

	if WFPlatformInfo.isDesktop then
		KSTableUtils.setNested( assetDoc, true, '_localOnly', 'isMarkedForOfflineUse' )
	end

	docs = KSTableUtils.appendArray( docs, addAssetDocToOfflineAlbum( assetDoc, optAlbumId ) )

end

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

local function fillDataCacheForImageAsset( rxTest, dataCache, expectedData )

	local previewData = KSData.memoryMappedContentsOfFile( expectedData.previewFilePath )
	local thumbnail2xData = KSData.memoryMappedContentsOfFile( expectedData.thumbnailFilePath )
	local fullsizeData = KSData.memoryMappedContentsOfFile( expectedData.fullsizeFilePath )
	
	expectedData.previewMd5 = previewData:digest( 'MD5' )
	expectedData.thumbMd5 = thumbnail2xData:digest( 'MD5' )
	expectedData.fullsizeMd5 = fullsizeData:digest( 'MD5' )
	
	rxTest:waitFor( dataCache:put( expectedData.previewMd5, previewData ) )
	rxTest:waitFor( dataCache:put( expectedData.thumbMd5, thumbnail2xData ) )
	rxTest:waitFor( dataCache:put( expectedData.fullsizeMd5, fullsizeData ) )
	
	rxTest:finally( function()
	
		previewData:close()
		thumbnail2xData:close()
		fullsizeData:close()
		
	end )

end

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

-- @mark getSizeOfPurgeableBinariesForType Tests

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

local function testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )

	optArgs = optArgs or {}
	optArgs.hasMasks = true

	if not optArgs.sharedMasks then
		optArgs.hasFilters = true
		optArgs.hasC2pa = true
	end
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )

	local numberOfDocumentsToCreate = 5
	
	local sizeOfOriginals = 0
	local sizeOfProxies = 0
	local sizeOfDevelopSettings = 0
	local sizeOfAuxes = 0
	local sizeOfFullSizeRenditions = 0
	local sizeOfPreviews = 0
		
	local docs = {}
		
	local binaryStrategy = optArgs.binaryStrategy
		
	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()
		
		optArgs.noLocalMasks = optArgs.noLocalFiles
		optArgs.noLocalFilters = optArgs.noLocalFiles
		optArgs.noLocalC2pa = optArgs.noLocalFiles
		
		local assetArgs = KSTableUtils.deepCopy( optArgs )
		
		if binaryStrategy and i == 1 then
		
			if binaryStrategy == LrmConfig.StrategyPreferMaster then
				
				-- Test fallback to proxy logic in StrategyPreferMaster mode.
				
				assetArgs.noMasterLink = true
				assetArgs.noLocalOriginal = true
			
			elseif binaryStrategy == LrmConfig.StrategyPreferProxy then
			
				-- Test fallback to original logic in StrategyPreferProxy mode.
				
				assetArgs.noProxyLink = true
				assetArgs.noLocalProxy = true
			
			end
			
		end
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, docId, assetArgs )
		
		if optArgs.noLocalFiles then
			assetDocValue._localOnly = nil
		end
		
		if optArgs.markedForOfflineUse then
			 markForOfflineUseAndAppendToDocs( docs, assetDocValue )
		else
			docs[ #docs + 1 ] = assetDocValue
		end
		
		if optArgs.notSynced then
			assetDocValue._serverProvidedMetadata = nil
		end

		sizeOfOriginals = sizeOfOriginals + expectedData.originalFileSize + expectedData.xmpSidecarFileSize
		
		sizeOfProxies = sizeOfProxies + expectedData.proxyFileSize
		
		sizeOfDevelopSettings = sizeOfDevelopSettings + expectedData.xmpDevelopSettingsFileSize
		
		sizeOfAuxes = sizeOfAuxes + expectedData.mask1FileSize + expectedData.mask2FileSize

		if not optArgs.sharedMasks then

			sizeOfAuxes = sizeOfAuxes + expectedData.filter1FileSize + expectedData.filter2FileSize + expectedData.c2paFileSize
		
		end
		
		sizeOfFullSizeRenditions = sizeOfFullSizeRenditions + expectedData.fullsizeFileSize
		
		sizeOfPreviews = sizeOfPreviews + expectedData.previewFileSize
		
		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end

	end
	
	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )
	
	local expectedSize = 0
	
	if optArgs.markedForOfflineUse and binaryStrategy then
		
		if binaryType == 'original' then

			if binaryStrategy == LrmConfig.StrategyPreferMaster then
			
				expectedSize = 0
				
			elseif binaryStrategy == LrmConfig.StrategyPreferProxy then
			
				-- In StrategyPreferProxy mode, if an album is marked for local use, originals
				-- associated with assets in that album are considered purgeable - and therefore
				-- a part of the photo cache - as long as they have an associated proxy 
				-- (either locally, or on Oz).
			
				expectedSize = sizeOfOriginals - sizeOfOriginals / numberOfDocumentsToCreate
					-- One document has no proxy locally or on Oz, so it cannot be purged.
			
			end
		
		elseif binaryType == 'proxy' then
		
			if binaryStrategy == LrmConfig.StrategyPreferMaster then
			
				-- In StrategyPreferMaster mode, if an album is marked for local use, proxies
				-- associated with assets in that album are considered purgeable - and therefore
				-- a part of the photo cache - as long as they have an associated original 
				-- (either locally, or on Oz).
			
				expectedSize = sizeOfProxies - sizeOfProxies / numberOfDocumentsToCreate
					-- One document has no original locally or on Oz, so it cannot be purged.
					
			elseif binaryStrategy == LrmConfig.StrategyPreferProxy then
			
				expectedSize = 0
			
			end
		
		end
		
	elseif optArgs.markedForOfflineUse
			or optArgs.notSynced 
			or optArgs.noLocalFiles then
		
		expectedSize = 0
		
	elseif binaryType == 'original' then
	
		expectedSize = sizeOfOriginals
		
	elseif binaryType == 'proxy' then
	
		expectedSize = sizeOfProxies
		
	elseif binaryType == 'xmp_develop' then
	
		if optArgs.sharedDevelopSettings then
			expectedSize = sizeOfDevelopSettings / numberOfDocumentsToCreate
		else
			expectedSize = sizeOfDevelopSettings
		end
		
	elseif binaryType == 'aux' then
	
		if optArgs.sharedMasks then
			expectedSize = sizeOfAuxes / numberOfDocumentsToCreate
		else
			expectedSize = sizeOfAuxes
		end
		
	elseif WFPlatformInfo.isMobile() then
	
		if binaryType == 'fullsize' then
			expectedSize = sizeOfFullSizeRenditions
		elseif binaryType == 'preview' then
			expectedSize = sizeOfPreviews
		end
		
	end

	local baseBinariesPath = wfCatalog:fileSpec():catalogPath()

	local volumeGuid = WFFileUtils.getVolumeGuidForPath( baseBinariesPath )

	local indexStore = wfCatalog:indexStore()
	
	rxTest:expectSingleValue( WFCatVolumeAgentQueryHelper.getSizeOfPurgeableBinariesForType(
			indexStore, binaryType, volumeGuid, binaryStrategy ),
		expectedSize )

end

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

local binaryTypes = {
	'original',
	'proxy',
	'xmp_develop',
	'aux',
	'fullsize',
	'preview'
}

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

for _, binaryType in ipairs( binaryTypes ) do

	local testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		testGetSizeOfPurgeableBinariesForType( rxTest, binaryType )
	
	end
	
	testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s_storedLocally", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			markedForOfflineUse = true
		}
	
		testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s_notSynced", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			notSynced = true
		}
	
		testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s_noLocalFiles", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			noLocalFiles = true
		}
	
		testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	if binaryType == 'xmp_develop' or binaryType == 'aux' then
	
		testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s_sharedFiles", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
			local optArgs = {
				sharedMasks = true,
				sharedDevelopSettings = true
			}
		
			testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )
	
		end
		
	end
	
	if ( binaryType == 'proxy' or binaryType == 'original' ) and WFPlatformInfo.isMobile() then
	
		testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s_preferMaster", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
			local optArgs = {
				markedForOfflineUse = true,
				binaryStrategy = LrmConfig.StrategyPreferMaster,
			}
		
			testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )
	
		end
		
		testName = string.format( "rxTestGetSizeOfPurgeableBinariesForType_%s_preferProxy", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
			local optArgs = {
				markedForOfflineUse = true,
				binaryStrategy = LrmConfig.StrategyPreferProxy,
			}
		
			testGetSizeOfPurgeableBinariesForType( rxTest, binaryType, optArgs )
	
		end
		
	end

end

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

local function testGetSizeOfPurgeableAuxInAlbum( rxTest, optArgs )

	rxTest:setTimeLimit( 10 )

	optArgs = optArgs or {}
	optArgs.hasMasks = true

	if not optArgs.sharedMasks then
		optArgs.hasFilters = true
		optArgs.hasC2pa = true
	end

	local wfCatalog = createFakeWFCatalog( rxTest )

	local numberOfDocumentsToCreate = 5

	local sizeOfAuxes = 0

	local docs = {}

	local albumDoc = WFCatAlbumTestUtils.createEmptyCollection( rxTest )

	docs[ #docs + 1 ] = albumDoc

	for i = 1, numberOfDocumentsToCreate, 1 do

		local docId = KSIdGenerator.uuidInLowercaseHex()

		optArgs.noLocalMasks = optArgs.noLocalFiles
		
		if not optArgs.sharedMasks then
			optArgs.noLocalFilters = optArgs.noLocalFiles
			optArgs.noLocalC2pa = optArgs.noLocalFiles
		end

		local assetArgs = KSTableUtils.deepCopy( optArgs )

		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, docId, assetArgs )

		local albumId = albumDoc._id

		if optArgs.notInAlbum then
			albumId = KSIdGenerator.uuidInLowercaseHex()
		end

		local albumAssetDoc1 = WFCatAlbumTestUtils.createAlbumAsset( rxTest, albumId, docId )
		docs[ #docs + 1 ] = albumAssetDoc1

		if optArgs.noLocalFiles then
			assetDocValue._localOnly = nil
		end

		if optArgs.markedForOfflineUse then
			 markForOfflineUseAndAppendToDocs( docs, assetDocValue )
		else
			docs[ #docs + 1 ] = assetDocValue
		end

		if optArgs.notSynced then
			assetDocValue._serverProvidedMetadata = nil
		end

		sizeOfAuxes = sizeOfAuxes + expectedData.mask1FileSize + expectedData.mask2FileSize

		if not optArgs.sharedMasks then
			sizeOfAuxes = sizeOfAuxes + expectedData.filter1FileSize + expectedData.filter2FileSize + expectedData.c2paFileSize
		end
	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	local expectedSize = 0

	if optArgs.markedForOfflineUse
			or optArgs.notSynced 
			or optArgs.noLocalFiles
			or optArgs.notInAlbum then
		
		expectedSize = 0

	else

		if optArgs.sharedMasks then
			expectedSize = sizeOfAuxes / numberOfDocumentsToCreate
		else
			expectedSize = sizeOfAuxes
		end

	end

	local indexStore = wfCatalog:indexStore()

	rxTest:expectSingleValue( WFCatVolumeAgentQueryHelper.getSizeOfPurgeableAuxInAlbum(
			indexStore, albumDoc._id ), expectedSize )

end

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

for _, binaryType in ipairs( { 'aux' } ) do

	local testName = string.format( "rxTestGetSizeOfPurgeableAuxInAlbum_%s", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

		testGetSizeOfPurgeableAuxInAlbum( rxTest )

	end

	testName = string.format( "rxTestGetSizeOfPurgeableAuxInAlbum_%s_notInAlbum", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

		local optArgs = {
			markedForOfflineUse = true,
			notInAlbum = true
		}

		testGetSizeOfPurgeableAuxInAlbum( rxTest, optArgs )

	end

	testName = string.format( "rxTestGetSizeOfPurgeableAuxInAlbum_%s_storedLocally", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

		local optArgs = {
			markedForOfflineUse = true
		}

		testGetSizeOfPurgeableAuxInAlbum( rxTest, optArgs )
	
	end

	testName = string.format( "rxTestGetSizeOfPurgeableAuxInAlbum_%s_notSynced", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			notSynced = true
		}

		testGetSizeOfPurgeableAuxInAlbum( rxTest, optArgs )

	end

	testName = string.format( "rxTestGetSizeOfPurgeableAuxInAlbum_%s_noLocalFiles", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

		local optArgs = {
			noLocalFiles = true
		}

		testGetSizeOfPurgeableAuxInAlbum( rxTest, optArgs )

	end

	testName = string.format( "rxTestGetSizeOfPurgeableAuxInAlbum_%s_sharedFiles", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

		local optArgs = {
			sharedMasks = true,
			sharedDevelopSettings = true
		}

		testGetSizeOfPurgeableAuxInAlbum( rxTest, optArgs )

	end

end

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

-- @mark getSizeOfUnsyncedBinariesForType Tests

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

local function testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )

	optArgs = optArgs or {}
	optArgs.hasMasks = true

	if not optArgs.sharedMasks then
		optArgs.hasFilters = true
		optArgs.hasC2pa = true
	end
	
	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )

	local numberOfDocumentsToCreate = 5
	
	local sizeOfOriginals = 0
	local sizeOfProxies = 0
	local sizeOfDevelopSettings = 0
	local sizeOfAuxes = 0
		
	local docs = {}
		
	local binaryStrategy = optArgs.binaryStrategy
		
	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()
		
		optArgs.noLocalMasks = optArgs.noLocalFiles

		if not optArgs.sharedMasks then
			optArgs.noLocalFilters = optArgs.noLocalFiles
			optArgs.noLocalC2pa = optArgs.noLocalFiles
		end
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, docId, optArgs )
		
		if optArgs.noLocalFiles then
			assetDocValue._localOnly = nil
		end
		
		if optArgs.markedForOfflineUse then
			 markForOfflineUseAndAppendToDocs( docs, assetDocValue )
		else
			docs[ #docs + 1 ] = assetDocValue
		end
		
		if optArgs.notSynced then
			assetDocValue._serverProvidedMetadata = nil
		end

		sizeOfOriginals = sizeOfOriginals + expectedData.originalFileSize + expectedData.xmpSidecarFileSize
		
		sizeOfProxies = sizeOfProxies + expectedData.proxyFileSize
		
		sizeOfDevelopSettings = sizeOfDevelopSettings + expectedData.xmpDevelopSettingsFileSize
		
		sizeOfAuxes = sizeOfAuxes + expectedData.mask1FileSize + expectedData.mask2FileSize 
		
		if not optArgs.sharedMasks then
			sizeOfAuxes = sizeOfAuxes + expectedData.filter1FileSize + expectedData.filter2FileSize + expectedData.c2paFileSize
		end

		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end

	end
	
	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )
	
	local expectedSize = 0
	
	if optArgs.notSynced
		and not optArgs.noLocalFiles
		and not optArgs.markedForOfflineUse then
		
		if binaryType == 'original' then
		
			expectedSize = sizeOfOriginals
			
		elseif binaryType == 'proxy' then
		
			expectedSize = sizeOfProxies
			
		elseif binaryType == 'xmp_develop' then
		
			if optArgs.sharedDevelopSettings then
				expectedSize = sizeOfDevelopSettings / numberOfDocumentsToCreate
			else
				expectedSize = sizeOfDevelopSettings
			end
			
		elseif binaryType == 'aux' then
		
			if optArgs.sharedMasks then
				expectedSize = sizeOfAuxes / numberOfDocumentsToCreate
			else
				expectedSize = sizeOfAuxes
			end

		end

	end

	local baseBinariesPath = wfCatalog:fileSpec():catalogPath()

	local volumeGuid = WFFileUtils.getVolumeGuidForPath( baseBinariesPath )

	local indexStore = wfCatalog:indexStore()
	
	rxTest:expectSingleValue( WFCatVolumeAgentQueryHelper.getSizeOfUnsyncedBinariesForType(
			indexStore, binaryType, volumeGuid, binaryStrategy ),
		expectedSize )

end

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

local unsyncedBinaryTypes = {
	'original',
	'proxy',
	'xmp_develop',
	'aux'
}

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

for _, binaryType in ipairs( unsyncedBinaryTypes ) do

	local testName = string.format( "rxTestGetSizeOfUnsyncedBinariesForType_%s_Synced", binaryType )

	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType )
	
	end
	
	testName = string.format( "rxTestGetSizeOfUnsyncedBinariesForType_%s_Unsynced", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			notSynced = true
		}
	
		testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	testName = string.format( "rxTestGetSizeOfUnsyncedBinariesForType_%s_storedLocallyAndUnsynced", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			markedForOfflineUse = true,
			notSynced = true
		}
	
		testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	testName = string.format( "rxTestGetSizeOfUnsyncedBinariesForType_%s_storedLocally", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			markedForOfflineUse = true
		}
	
		testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	testName = string.format( "rxTestGetSizeOfUnsyncedBinariesForType_%s_noLocalFilesAndUnsynced", binaryType )
	
	WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
		local optArgs = {
			noLocalFiles = true,
			notSynced = true
		}
	
		testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType, optArgs )
	
	end
	
	if binaryType == 'xmp_develop' or binaryType == 'aux' then
	
		testName = string.format( "rxTestGetSizeOfUnsyncedBinariesForType_%s_sharedFiles_Unsynced", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
	
			local optArgs = {
				sharedMasks = true,
				sharedDevelopSettings = true,
				notSynced = true
			}
		
			testGetSizeOfUnsyncedBinariesForType( rxTest, binaryType, optArgs )
	
		end
		
	end
	
end

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

-- @mark getSizeOfStoredLocalBinariesForType Tests

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

local function testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )

	optArgs = optArgs or {}
	optArgs.hasMasks = true
	
	if not optArgs.sharedMasks then
		optArgs.hasFilters = true
		optArgs.hasC2pa = true
	end

	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )

	local numberOfDocumentsToCreate = 5
	
	local sizeOfOriginals = 0
	local sizeOfProxies = 0
	local sizeOfDevelopSettings = 0
	local sizeOfAuxes = 0
	local sizeOfFullSizeRenditions = 0
	local sizeOfPreviews = 0
		
	local docs = {}
		
	local binaryStrategy = optArgs.binaryStrategy

	local onlyInAlbumId

	if optArgs.onlyInAlbum then

		-- When onlyInAlbum is set, we add a single asset to a specific album, and
		-- then calculate the size of the binaries with only the specified album.

		onlyInAlbumId = KSIdGenerator.uuidInLowercaseHex()

	end

	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()

		optArgs.noLocalMasks = optArgs.noLocalFiles

		if not optArgs.sharedMasks then
			optArgs.noLocalFilters = optArgs.noLocalFiles
			optArgs.noLocalC2pa = optArgs.noLocalFiles
		end

		local assetArgs = KSTableUtils.deepCopy( optArgs )

		if binaryStrategy and i == 1 then
		
			if binaryType == 'proxy' and binaryStrategy == LrmConfig.StrategyPreferMaster then
				
				-- Test fallback to proxy logic in StrategyPreferMaster mode.
				
				assetArgs.noMasterLink = true
				assetArgs.noLocalOriginal = true
			
			elseif binaryType == 'original' and binaryStrategy == LrmConfig.StrategyPreferProxy then
			
				-- Test fallback to original logic in StrategyPreferProxy mode.
				
				assetArgs.localXmpSidecarDoesNotExist = true
				assetArgs.noProxyLink = true
				assetArgs.noLocalProxy = true
			
			end
			
		end
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, docId, assetArgs )
		
		if optArgs.noLocalFiles then
			assetDocValue._localOnly = nil
		end
		
		local albumId = i == 1 and onlyInAlbumId or KSIdGenerator.uuidInLowercaseHex()
		
		if optArgs.markedForOfflineUse then
			 markForOfflineUseAndAppendToDocs( docs, assetDocValue, albumId )
		else
			docs[ #docs + 1 ] = assetDocValue
		end
		
		if optArgs.notSynced then
			assetDocValue._serverProvidedMetadata = nil
		end

		sizeOfOriginals = sizeOfOriginals + expectedData.originalFileSize + expectedData.xmpSidecarFileSize
		
		sizeOfProxies = sizeOfProxies + expectedData.proxyFileSize
		
		sizeOfDevelopSettings = sizeOfDevelopSettings + expectedData.xmpDevelopSettingsFileSize
		
		sizeOfAuxes = sizeOfAuxes + expectedData.mask1FileSize + expectedData.mask2FileSize 
		
		if not optArgs.sharedMasks then
			sizeOfAuxes = sizeOfAuxes + expectedData.filter1FileSize + expectedData.filter2FileSize + expectedData.c2paFileSize
		end

		sizeOfFullSizeRenditions = sizeOfFullSizeRenditions + expectedData.fullsizeFileSize
		
		sizeOfPreviews = sizeOfPreviews + expectedData.previewFileSize
		
		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end

	end
	
	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )
	
	local expectedSize = 0

	local onlyCountLocalBinaries = not not optArgs.onlyCountLocalBinaries

	if optArgs.markedForOfflineUse then

		if binaryType == 'original' then

			if binaryStrategy and binaryStrategy == LrmConfig.StrategyPreferProxy or onlyInAlbumId then

				expectedSize = sizeOfOriginals / numberOfDocumentsToCreate
					-- Only one document has no proxy locally or on Oz
					-- Only one document is in the specified album.

			elseif not binaryStrategy or binaryStrategy == LrmConfig.StrategyPreferMaster then

				expectedSize = sizeOfOriginals

			end

		elseif binaryType == 'proxy' then

			if binaryStrategy and binaryStrategy == LrmConfig.StrategyPreferMaster or onlyInAlbumId then

				expectedSize = sizeOfProxies / numberOfDocumentsToCreate
					-- Only one document has no master locally or on Oz
					-- Only one document is in the specified album.

			elseif not binaryStrategy or binaryStrategy == LrmConfig.StrategyPreferProxy then

				expectedSize = sizeOfProxies

			end

		elseif binaryType == 'xmp_develop' then

			if optArgs.sharedDevelopSettings or onlyInAlbumId then
				expectedSize = sizeOfDevelopSettings / numberOfDocumentsToCreate
			else
				expectedSize = sizeOfDevelopSettings
			end

		elseif binaryType == 'aux' then

			if optArgs.sharedMasks or onlyInAlbumId then
				expectedSize = sizeOfAuxes / numberOfDocumentsToCreate
			else
				expectedSize = sizeOfAuxes
			end

		elseif WFPlatformInfo.isMobile() then

			if binaryType == 'fullsize' then

				if onlyInAlbumId then
					expectedSize = sizeOfFullSizeRenditions / numberOfDocumentsToCreate
				else
					expectedSize = sizeOfFullSizeRenditions
				end

			elseif binaryType == 'preview' then

				if onlyInAlbumId then
					expectedSize = sizeOfPreviews / numberOfDocumentsToCreate
				else
					expectedSize = sizeOfPreviews
				end

			end

		end

	end

	if onlyCountLocalBinaries and optArgs.noLocalFiles then
		expectedSize = 0
	end

	local indexStore = wfCatalog:indexStore()

	local actualSize = rxTest:getFirstValue( WFCatVolumeAgentQueryHelper.getSizeOfStoredLocalBinariesForType(
			indexStore, binaryType, onlyCountLocalBinaries, binaryStrategy, onlyInAlbumId ) )

	rxTest:expectEqual( expectedSize, actualSize )

end

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

for _, binaryType in ipairs( binaryTypes ) do

	for _, onlyInAlbum in ipairs( { false, true } ) do

		local inAlbumStr = onlyInAlbum and "_InAlbum" or ""

		local testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_storedLocally",
				binaryType, inAlbumStr )

		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

			local optArgs = {
				onlyInAlbum = onlyInAlbum,
				markedForOfflineUse = true
			}

			testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

		end

		testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_notStoredLocally",
				binaryType, inAlbumStr )

		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

			local optArgs = {
				onlyInAlbum = onlyInAlbum,
				markedForOfflineUse = false
			}

			testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

		end

		testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_onlyCountLocalBinaries",
				binaryType, inAlbumStr )

		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

			local optArgs = {
				onlyInAlbum = onlyInAlbum,
				onlyCountLocalBinaries = true
			}

			testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

		end

		testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_onlyCountLocalBinaries_noLocalFiles",
				binaryType, inAlbumStr )

		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

			local optArgs = {
				onlyInAlbum = onlyInAlbum,
				onlyCountLocalBinaries = true,
				noLocalFiles = true
			}

			testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

		end

		if binaryType == 'xmp_develop' or binaryType == 'aux' then
	
			testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_sharedFiles",
					binaryType, inAlbumStr )

			WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

				local optArgs = {
					onlyInAlbum = onlyInAlbum,
					markedForOfflineUse = true,
					sharedMasks = true,
					sharedDevelopSettings = true
				}

				testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

			end

		end

		if ( binaryType == 'proxy' or binaryType == 'original' ) and WFPlatformInfo.isMobile() then

			testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_preferMaster",
					binaryType, inAlbumStr )

			WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

				local optArgs = {
					onlyInAlbum = onlyInAlbum,
					markedForOfflineUse = true,
					binaryStrategy = LrmConfig.StrategyPreferMaster,
				}

				testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

			end

			testName = string.format( "rxTestGetSizeOfStoredLocalBinariesForType_%s%s_preferProxy",
					binaryType, inAlbumStr )

			WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )

				local optArgs = {
					onlyInAlbum = onlyInAlbum,
					markedForOfflineUse = true,
					binaryStrategy = LrmConfig.StrategyPreferProxy,
				}

				testGetSizeOfStoredLocalBinariesForType( rxTest, binaryType, optArgs )

			end

		end

	end

end

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

-- @mark getSizeOfKeepAllBinariesForType Tests

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

local function testGetSizeOfKeepAllBinariesForType( rxTest, binaryType, optArgs )

	rxTest:setTimeLimit( 10 )

	local wfCatalog, maybeDataCache = createFakeWFCatalog( rxTest )

	local numberOfDocumentsToCreate = 5
	
	local sizeOfOriginals = 0
	local sizeOfProxies = 0
		
	optArgs = optArgs or {}
		
	local docs = {}
		
	for i = 1, numberOfDocumentsToCreate, 1 do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()
		
		optArgs.noLocalMasks = optArgs.noLocalFiles
		optArgs.noLocalFilters = optArgs.noLocalFiles
		optArgs.noLocalC2pa = optArgs.noLocalFiles
		
		local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, docId, optArgs )
		docs[ #docs + 1 ] = assetDocValue
		
		if optArgs.noLocalFiles then
			assetDocValue._localOnly = nil
		end
		
		sizeOfOriginals = sizeOfOriginals + expectedData.originalFileSize + expectedData.xmpSidecarFileSize
		
		sizeOfProxies = sizeOfProxies + expectedData.proxyFileSize
		
		if maybeDataCache then
			fillDataCacheForImageAsset( rxTest, maybeDataCache, expectedData )
		end

	end
	
	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )
	
	local expectedSize = 0
	
	if binaryType == 'original' then
		expectedSize = sizeOfOriginals
	elseif binaryType == 'proxy' then
		expectedSize = sizeOfProxies
	end

	local onlyCountLocalBinaries = not not optArgs.onlyCountLocalBinaries

	local indexStore = wfCatalog:indexStore()
	
	local actualSize = rxTest:getFirstValue( WFCatVolumeAgentQueryHelper.getSizeOfKeepAllBinariesForType(
			indexStore, binaryType, onlyCountLocalBinaries ) )
	
	if onlyCountLocalBinaries and optArgs.noLocalFiles then
	
		rxTest:expectEqual( 0, actualSize )
	
	elseif optArgs.noLocalFiles then
	
		rxTest:expectEqual( true, actualSize > 0 )
	
	else
	
		rxTest:expectEqual( expectedSize, actualSize )
	
	end

end

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

if WFPlatformInfo.isDesktop then

	for _, binaryType in ipairs( { 'original', 'proxy' } ) do

		local testName = string.format( "rxTestGetSizeOfKeepAllBinariesForType_%s", binaryType )
		
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
		
			testGetSizeOfKeepAllBinariesForType( rxTest, binaryType )
		
		end
		
		testName = string.format( "rxTestGetSizeOfKeepAllBinariesForType_%s_noLocalFiles", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
		
			local optArgs = {
				noLocalFiles = true
			}
		
			testGetSizeOfKeepAllBinariesForType( rxTest, binaryType, optArgs )
		
		end
		
		testName = string.format( "rxTestGetSizeOfKeepAllBinariesForType_%s_onlyCountLocalBinaries", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
		
			local optArgs = {
				onlyCountLocalBinaries = true
			}
		
			testGetSizeOfKeepAllBinariesForType( rxTest, binaryType, optArgs )
		
		end
		
		testName = string.format( "rxTestGetSizeOfKeepAllBinariesForType_%s_onlyCountLocalBinaries_noLocalFiles", binaryType )
	
		WFCatVolumeAgentQueryHelperTest[ testName ] = function( rxTest )
		
			local optArgs = {
				onlyCountLocalBinaries = true,
				noLocalFiles = true
			}
		
			testGetSizeOfKeepAllBinariesForType( rxTest, binaryType, optArgs )
		
		end
		
	end

end

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

--@mark UntrackedBinariesPurgeListStream Tests

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

function WFCatVolumeAgentQueryHelperTest.rxTestUntrackedBinariesPurgeListStream( rxTest )

	local wfCatalog = setUp( rxTest )
	
	rxTest:setTimeLimit( 10 )

	-- Listen on the untrackedBinariesPurgeListStream API for untracked binaries.
	
	local untrackedBinariesObserver = rxTest:observe( 
			WFCatVolumeAgentQueryHelper.untrackedBinariesPurgeListStream( wfCatalog ) 
				:map( function( purgeList )
					for _, purgeListForBinaryType in ipairs( purgeList ) do
						for i in ipairs( purgeListForBinaryType ) do
							table.sort( purgeListForBinaryType[ i ] )
						end
					end
					return purgeList
				end ) )

	-- Create 3 documents that all have unique masks, filters and c2pa. Each document has two masks.
	
	local docs = {}
	local expectedDataForDocs = {}
	
	local overrides = {
		hasAllAuxType = true
	}

	for i=1, 3, 1 do
	
		local doc, expectedData = createAssetDoc( rxTest, wfCatalog, overrides )
		docs[ #docs + 1 ] = doc
		expectedDataForDocs[ doc._id ] = expectedData
		
	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	-- There should be no untracked binaries
			
	untrackedBinariesObserver:expectData( {} )

	-- Now delete one asset. There should now be two untracked mask binaries.

	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), { docs[ 1 ]._id } ) )

	local function getExpectedAuxObjectsForLocalId( localId )
	
		local expected = {
			expectedDataForDocs[ docs[ localId ]._id ].mask1Fingerprint,
			expectedDataForDocs[ docs[ localId ]._id ].mask2Fingerprint,
			expectedDataForDocs[ docs[ localId ]._id ].filter1Fingerprint,
			expectedDataForDocs[ docs[ localId ]._id ].filter2Fingerprint,
			expectedDataForDocs[ docs[ localId ]._id ].c2paFingerprint,
		}
	
		table.sort( expected )
		
		return expected
		
	end

	local firstPurgeList = {
		{
			binaryType = 'aux',
			getExpectedAuxObjectsForLocalId( 1 )
		}
	}

	untrackedBinariesObserver:expectDataWithinTime( 3, firstPurgeList )

	-- Now delete the rest of the assets and verify.
	
	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), {
			docs[ 2 ]._id,
			docs[ 3 ]._id
		} ) )

	local secondPurgeList = {
		{
			binaryType = 'aux',
			getExpectedAuxObjectsForLocalId( 1 ),
			getExpectedAuxObjectsForLocalId( 2 ),
			getExpectedAuxObjectsForLocalId( 3 )
		}
	}

	untrackedBinariesObserver:expectDataWithinTime( 3, secondPurgeList )
		
	-- Now purge the binaries for asset 1 
	
	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, firstPurgeList ) )

	untrackedBinariesObserver:expectDataWithinTime( 3, {
			{
				binaryType = 'aux',
				[ 2 ] = getExpectedAuxObjectsForLocalId( 2 ),
				[ 3 ] = getExpectedAuxObjectsForLocalId( 3 )
			} 
		} )
		
	-- Now purge all binaries

	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, secondPurgeList ) )

	untrackedBinariesObserver:expectDataWithinTime( 3, {} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestUntrackedBinariesPurgeListStream_SharedMasks( rxTest )

	local wfCatalog = setUp( rxTest )
	
	rxTest:setTimeLimit( 10 )

	-- Listen on the untrackedBinariesPurgeListStream API for untracked binaries.
	
	local untrackedBinariesObserver = rxTest:observe( 
			WFCatVolumeAgentQueryHelper.untrackedBinariesPurgeListStream( wfCatalog ) 
				:map( function( purgeList )
					for _, purgeListForBinaryType in ipairs( purgeList ) do
						for i in ipairs( purgeListForBinaryType ) do
							table.sort( purgeListForBinaryType[ i ] )
						end
					end
					return purgeList
				end ) )

	-- Create 2 documents that SHARE 2 masks.
	
	local docs = {}
	local expectedDataForDocs = {}
	
	local overrides = {
		hasMasks = true,
		sharedMasks = true
	}

	for i=1, 2, 1 do
	
		local doc, expectedData = createAssetDoc( rxTest, wfCatalog, overrides )
		docs[ #docs + 1 ] = doc
		expectedDataForDocs[ doc._id ] = expectedData
		
	end

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( docs ) )

	-- There should be no untracked binaries
			
	untrackedBinariesObserver:expectData( {} )

	-- Now delete one asset. There should NO untracked binaries.

	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), { docs[ 1 ]._id } ) )

	untrackedBinariesObserver:expectDataWithinTime( 3, {} )

	-- Now delete the second doc. There should now be two untracked binaries.
	
	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), { docs[ 2 ]._id } ) )

	local function getExpectedAuxObjectsForLocalId( localId )
	
		local expected = {
			expectedDataForDocs[ docs[ localId ]._id ].mask1Fingerprint,
			expectedDataForDocs[ docs[ localId ]._id ].mask2Fingerprint
		}
	
		table.sort( expected )
		
		return expected
		
	end

	untrackedBinariesObserver:expectDataWithinTime( 3, {
			{
				binaryType = 'aux',
				[ 1 ] = getExpectedAuxObjectsForLocalId( 1 ),
				[ 2 ] = getExpectedAuxObjectsForLocalId( 2 )
			}
		} )

	-- Now purge the binaries for asset 1 
	
	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, {
			{
				binaryType = 'aux',
				[ 1 ] = getExpectedAuxObjectsForLocalId( 1 )
			}
		} ) )

	untrackedBinariesObserver:expectDataWithinTime( 3, {
			{
				binaryType = 'aux',
				[ 2 ] = getExpectedAuxObjectsForLocalId( 2 )
			} 
		} )
		
	-- Now purge all binaries

	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog,  {
			{
				binaryType = 'aux',
				[ 1 ] = getExpectedAuxObjectsForLocalId( 1 ),
				[ 2 ] = getExpectedAuxObjectsForLocalId( 2 )
			}
		} ) )

	untrackedBinariesObserver:expectDataWithinTime( 3, {} )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestUntrackedBinariesPurgeListStream_unsynced( rxTest )

	local wfCatalog = setUp( rxTest )
	
	rxTest:setTimeLimit( 10 )

	-- Listen on the untrackedBinariesPurgeListStream API for untracked binaries.
	
	local untrackedBinariesObserver = rxTest:observe( 
			WFCatVolumeAgentQueryHelper.untrackedBinariesPurgeListStream( wfCatalog ) 
				:map( function( purgeList )
					for _, purgeListForBinaryType in ipairs( purgeList ) do
						for i in ipairs( purgeListForBinaryType ) do
							table.sort( purgeListForBinaryType[ i ] )
						end
					end
					return purgeList
				end ) )

	-- Create 2 documents. One with oz links, one without

	local overrides = {
		hasDevelopAux = true
	}

	local docWithOzLinks, expectedDataForDocWithOzLink = createAssetDoc( rxTest, wfCatalog, overrides )
	
	overrides = {
		hasDevelopAux = true,
		noDevelopAuxLinks = true
	}

	local docNoOzLinks, expectedDataForDocNoOzLink = createAssetDoc( rxTest, wfCatalog, overrides )

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( { docWithOzLinks, docNoOzLinks } ) )

	-- There should be no untracked binaries
			
	untrackedBinariesObserver:expectData( {} )

	-- Now delete develop section for both asset
	-- Only asset with Oz links can be purged

	rxTest:waitFor( wfCatalog:docStore():bulkApplyOverlay( { 
		{
			_id = docWithOzLinks._id,
			develop = { _delete = true }
		},
		{
			_id = docNoOzLinks._id,
			develop = { _delete = true }
		}
	} ) )

	local function getExpectedAuxObjectsForDocId( docId )
	
		local expectedData = {}

		if docId == docWithOzLinks._id then
			expectedData = expectedDataForDocWithOzLink
		elseif docId == docNoOzLinks._id then
			expectedData = expectedDataForDocNoOzLink
		end

		local expected = {
			expectedData.mask1Fingerprint,
			expectedData.mask2Fingerprint,
			expectedData.filter1Fingerprint,
			expectedData.filter2Fingerprint
		}
	
		table.sort( expected )
		
		return expected
		
	end

	local firstPurgeList = {
		{
			binaryType = 'aux',
			getExpectedAuxObjectsForDocId( docWithOzLinks._id )
		}
	}

	untrackedBinariesObserver:expectDataWithinTime( 3, firstPurgeList )

	-- Now delete both assets and verify.

	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), {
		docWithOzLinks._id,
		docNoOzLinks._id
	} ) )

	local secondPurgeList = {
		{
			binaryType = 'aux',
			getExpectedAuxObjectsForDocId( docWithOzLinks._id ),
			getExpectedAuxObjectsForDocId( docNoOzLinks._id )
		}
	}

	untrackedBinariesObserver:expectDataWithinTime( 3, secondPurgeList )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestVerifyReferenceTrackerTable( rxTest )

	local wfCatalog = setUp( rxTest )
	
	rxTest:setTimeLimit( 10 )

	local observer = rxTest:observe( wfCatalog:indexStore():query{
		sql = [[ SELECT DISTINCT *
					FROM auxReferenceTracker
					ORDER BY fingerprint ASC ]],
		quiesceUntilUpToDate = true,
	} )

	observer:expectData( {} )

	local overrides = {
		hasMasks = true,
		sharedMasks = true
	}

	-- Create a doc with 2 masks
	
	local doc, expectedData = createAssetDoc( rxTest, wfCatalog, overrides )
	
	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( { doc } ) )

	observer:expectDataWithinTime( 3, {
		{
			doc._id,
			1,
			"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
			1,
		},
		{
			doc._id,
			1,
			"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
			1,
		},
	} )

	-- Delete the doc
	
	rxTest:waitFor( WFCatDelete.deleteDocs( wfCatalog:docStore(), { doc._id } ) )

	observer:expectDataWithinTime( 3, {
		{
			doc._id,
			1,
			"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
			0,
		},
		{
			doc._id,
			1,
			"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB",
			0,
		},
	} )

	-- Delete the files
	
	rxTest:waitFor( WFCatPurgeHelper.deleteFilesByPurgeList( wfCatalog, {
			{
				binaryType = 'aux',
				[ 1 ] = { expectedData.mask1Fingerprint, expectedData.mask2Fingerprint }
			}
		} ) )
		
	observer:expectDataWithinTime( 3, {} )

	observer:dispose()

	-- Has resampled aux

	overrides = {
		hasSourceOnlyFilters = true,
		sharedFilters = true,
		hasLocalResampledFilter  = true
	}
	
	doc = createAssetDoc( rxTest, wfCatalog, overrides )

	local nonCurrentDigest = "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
	local nonCurrentResampledAuxInfo = {
		relativePath = 'auxiliary/ZZZ/ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ',
		groupDigest = 'nonCurrentGroupDigest',
		crsSizeX = 437,
		crsSizeY = 328,
		fileSize = 32,
		targetLongEdge = 2560
	}
	KSTableUtils.setNested( doc, nonCurrentResampledAuxInfo, '_localOnly', 'files', 'aux', nonCurrentDigest )

	rxTest:waitFor( wfCatalog:docStore():setDocValue( doc ) )
	
	rxTest:expectSingleValue( wfCatalog:indexStore():queryOnce( {
		sql = [[ SELECT DISTINCT *
					FROM auxReferenceTracker
					WHERE docId = ?
					ORDER BY fingerprint ASC ]],
		quiesceUntilUpToDate = true,
		doc._id
	} ), {
		{
			doc._id,
			2,
			"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
			1,
		},
		{
			doc._id,
			2,
			"EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
			1,
		},
		{
			doc._id,
			2,
			"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
			0,
		},
	} )

end

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

--@mark Get Purge List Tests

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

local function sortPurgeList( purgeList )

	purgeList = purgeList or {}
	purgeList.binaryType = nil

	for k, v in pairs( purgeList ) do
		purgeList[ k ] = table.sort( v )
	end

	local sortedPurgeList = table.sort( purgeList )

	return sortedPurgeList

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetAuxPurgeListForDeletedOrDowngradedSpace_NoSharedAux( rxTest )

	local wfCatalog = setUp( rxTest )

	-- Create a document that has two masks.
	
	local overrides = {
		hasAllAuxType = true
	}

	local spaceId1 = KSIdGenerator.uuidInLowercaseHex()

	local doc1, expectedData1 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc1._spaceId = spaceId1

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( { doc1 } ) )

	-- getAuxPurgeListForDeletedOrDowngradedSpace should return a purge list that includes
	-- all auxiliaries associated with the asset, since they are not shared with any asset
	-- outside of the space.

	local expected = {
		[ doc1._id ] = {
			expectedData1.mask1Fingerprint,
			expectedData1.mask2Fingerprint,
			expectedData1.filter1Fingerprint,
			expectedData1.filter2Fingerprint,
			expectedData1.c2paFingerprint,
		}
	}

	rxTest:expectSingleValue(
			WFCatVolumeAgentQueryHelper.getAuxPurgeListForDeletedOrDowngradedSpace(
					wfCatalog, spaceId1, { doc1._id } )
				:map( sortPurgeList ),
			sortPurgeList( expected ) )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetAuxPurgeListForDeletedOrDowngradedSpace_SharedMasksInSpace( rxTest )

	local wfCatalog = setUp( rxTest )

	-- Create two documents in the same space that share masks.
	
	local overrides = {
		hasMasks = true,
		sharedMasks = true
	}

	local spaceId1 = KSIdGenerator.uuidInLowercaseHex()

	local doc1, expectedData1 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc1._spaceId = spaceId1

	local doc2, expectedData2 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc2._spaceId = spaceId1

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( { doc1, doc2 } ) )

	-- getAuxPurgeListForDeletedOrDowngradedSpace should return a purge list that includes
	-- all auxiliaries associated with all assets, since none of the associated auxiliaries
	-- are shared between documents that live outside of the space.

	local expected = {
		[ doc1._id ] = {
			expectedData1.mask1Fingerprint,
			expectedData1.mask2Fingerprint
		},
		[ doc2._id ] = {
			expectedData2.mask1Fingerprint,
			expectedData2.mask2Fingerprint
		}
	}

	rxTest:expectSingleValue(
			WFCatVolumeAgentQueryHelper.getAuxPurgeListForDeletedOrDowngradedSpace(
					wfCatalog, spaceId1, { doc1._id, doc2._id } )
				:map( sortPurgeList ),
			sortPurgeList( expected ) )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetAuxPurgeListForDeletedOrDowngradedSpace_SharedMasksOutsideOfSpace( rxTest )

	local wfCatalog = setUp( rxTest )

	-- Create two documents in different spaces that share masks.
	
	local overrides = {
		hasMasks = true,
		sharedMasks = true
	}

	local spaceId1 = KSIdGenerator.uuidInLowercaseHex()

	local doc1 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc1._spaceId = spaceId1
	
	local doc2 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc2._spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue( { doc1, doc2 } ) )

	-- getAuxPurgeListForDeletedOrDowngradedSpace should return nothing, because
	-- the masks are shared across spaces, and therefore they cannot be removed.
	
	local expected = {}

	rxTest:expectSingleValue( 
			WFCatVolumeAgentQueryHelper.getAuxPurgeListForDeletedOrDowngradedSpace( wfCatalog, spaceId1, { doc1._id } ),
			expected )

end

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

function WFCatVolumeAgentQueryHelperTest.rxTestGetAuxPurgeListForDeletedOrDowngradedSpace_Mixed( rxTest )

	local wfCatalog = setUp( rxTest )
	
	-- Create two documents in space1 that share masks.
	
	local overrides = {
		hasMasks = true,
		sharedMasks = true
	}

	local spaceId1 = KSIdGenerator.uuidInLowercaseHex()

	local doc1 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc1._spaceId = spaceId1

	local doc2 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc2._spaceId = spaceId1
	
	-- Create one documents in space1 that has unique masks.
	
	overrides = {
		hasMasks = true,
		sharedMasks = false
	}

	local doc3, expectedData3 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc3._spaceId = spaceId1
	
	-- Create one document outside the space that shares masks with doc1 and doc2.
	
	overrides = {
		hasMasks = true,
		sharedMasks = true
	}

	local doc4 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc4._spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	-- Create one document outside the space with no shared masks.
	
	overrides = {
		hasMasks = true,
		sharedMasks = false
	}

	local doc5 = createAssetDoc( rxTest, wfCatalog, overrides )
	doc5._spaceId = nil

	rxTest:waitFor( wfCatalog:docStore():bulkSetDocValue(
			{ doc1, doc2, doc3, doc4, doc5 } ) )

	local docIdsInSpace = { doc1._id, doc2._id, doc3._id }

	-- Doc 3 is the only asset in the space that contains masks that are not
	-- shared outside the space.

	local expected = {
		[ doc3._id ] = {
			expectedData3.mask1Fingerprint,
			expectedData3.mask2Fingerprint
		}
	}

	rxTest:expectSingleValue(
			WFCatVolumeAgentQueryHelper.getAuxPurgeListForDeletedOrDowngradedSpace(
					wfCatalog, spaceId1, docIdsInSpace )
				:map( sortPurgeList ),
			sortPurgeList( expected ) )

end

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

--@mark Develop Settings Purgeable Check

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

function WFCatVolumeAgentQueryHelperTest.rxTestIsDevelopSettingsPurgeable( rxTest )

	local wfCatalog = setUp( rxTest )
	
	local overrides = {
		sharedDevelopSettings = true
	}
	
	local doc1, localSettings = createAssetDoc( rxTest, wfCatalog, overrides )
	local docId1 = doc1._id
	local developSettingsSha256 = localSettings.developSettingsSha256
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( doc1 ) )
	
	rxTest:expectSingleValue( 
		WFCatVolumeAgentQueryHelper.isDevelopSettingsPurgeable( wfCatalog, docId1, developSettingsSha256 ),
		true )
	
	-- Add a shared develop settings doc with uploaded purgeable develop settings
	
	local doc2 = createAssetDoc( rxTest, wfCatalog, overrides )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( doc2 ) )
	
	rxTest:expectSingleValue( 
		WFCatVolumeAgentQueryHelper.isDevelopSettingsPurgeable( wfCatalog, docId1, developSettingsSha256 ),
		true )
		
	-- Add a shared develop settings doc with non-purgeable develop settings
	
	overrides = {
		sharedDevelopSettings = true,
		noDevelopSettingsLink = true
	}
	
	local doc3 = createAssetDoc( rxTest, wfCatalog, overrides )
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( doc3 ) )
	
	rxTest:expectSingleValue( 
		WFCatVolumeAgentQueryHelper.isDevelopSettingsPurgeable( wfCatalog, docId1, developSettingsSha256 ),
		false )
	
end

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

return WFRxTestCase.wrapSuite( 'WFCatVolumeAgentQueryHelperTest', WFCatVolumeAgentQueryHelperTest )
