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

WFCatSpacePurgeUtilsTest.lua

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

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

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

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

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

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

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

	-- WF.oz_client.managed_catalog
local WFCatAssetUtils = require 'WFCatAssetUtils'
local WFCatVersions = require 'WFCatVersions'
local WFCatSpacePurgeUtils = require 'WFCatSpacePurgeUtils'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'
local LrmCatalogTestHelper

	-- WF.lrmobile.modules.source
local LrmOzPurgeAgentUtils

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

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

local derefOpt = assert( KSTableUtils.derefOpt )
local derefUniversal = assert( WFCatAssetUtils.derefUniversal )

local albumAssetTable = "album_asset"
if WFPlatformInfo.isDesktop then
	albumAssetTable = "album_asset_v2"
end

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

local WFCatSpacePurgeUtilsTest = {}

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

local function createFakeWFCatalog( rxTest )

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

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

end

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

local function testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local spaceId = KSIdGenerator.uuidInLowercaseHex()

	optArgs = optArgs or {}

	local sharedMasks = optArgs.sharedMasksInSpace or optArgs.sharedMasksOutsideOfSpace or optArgs.sharedMasksWithCatalog

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

	local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, optOverrides )
	assetDocValue._spaceId = spaceId

	if sharedMasks then

		local assetDocValue2 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optOverrides )

		if optArgs.sharedMasksOutsideOfSpace then
			assetDocValue2._spaceId = KSIdGenerator.uuidInLowercaseHex()
		elseif optArgs.sharedMasksInSpace then
			assetDocValue2._spaceId = spaceId
		end

		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue2 ) )

	end

	if withRedactedOzLink then
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/master', 'href' )
		KSTableUtils.setNested( assetDocValue, true, '_serverProvidedMetadata', 'links', '/rels/master', 'exists' )
		
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'href' )
		KSTableUtils.setNested( assetDocValue, true, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'exists' )
	end
	
	if onlyHasProxyLink then
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/master' )
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( assetDocValue ), ':ignore:' )
	
	-- check if all files exist
	-- xmp_develop purging on desktop would be handled by PixelProviderFileCachePurgeWorker
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpSidecarFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask1FilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask2FilePath ) )
	
	-- create space and add asset into space
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {

		_id = albumId,
		_spaceId = spaceId,
		type = 'album',
		subtype = 'collection',
		name = 'foo',

	}

	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumDoc ), ':ignore:' )
	
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumAssetDoc = {

		_id = albumAssetId,
		_spaceId = spaceId,
		type = 'album_asset',
		asset = {
			id = assetId
		},
		album = {
			id = albumId
		}
	}
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumAssetDoc ), ':ignore:' )

	local expectedId = sharedMasks and 4 or 3

	rxTest:observe( wfCatalog:indexStore():query{
			sql = string.format( [[SELECT docId FROM %s WHERE albumId = ?]], albumAssetTable ),
			albumId
		})
		:expectDataWithinTime( 3, {{ expectedId }} )
		:dispose()
	
	-- purge assets for space
	
	rxTest:waitFor( WFCatSpacePurgeUtils.DEBUG_purgeAssetsForSpace( wfCatalog, spaceId, true, keepRedactedBinaries ) )
	
	-- check if files are purged and doc is updated
	
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.originalFilePath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.xmpSidecarFilePath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.proxyFilePath ) )
	
	if not ( optArgs.sharedMasksOutsideOfSpace or optArgs.sharedMasksWithCatalog ) then
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.mask1FilePath ) )
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.mask2FilePath ) )
	else
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask1FilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask2FilePath ) )
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( assetId )
		:map( function( assetDocValue )
			
			local result = derefOpt( assetDocValue, '_localOnly', 'files', 'original', 'master', 'relativePath' ) == nil
					and derefOpt( assetDocValue, '_localOnly', 'files', 'proxy', '2560', 'relativePath' ) == nil
					and derefOpt( assetDocValue, '_localOnly', 'files', 'original', 'xmp', 'path' ) == nil
					and WFCatAssetUtils.getLocalAuxObjectPath( assetDocValue, expectedData.mask1Fingerprint ) == nil
					and WFCatAssetUtils.getLocalAuxObjectPath( assetDocValue, expectedData.mask2Fingerprint ) == nil

			return result

		end ),
		true
	)

end 

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

local function testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	optArgs = optArgs or {}

	local sharedMasks = optArgs.sharedMasksInSpace or optArgs.sharedMasksOutsideOfSpace or optArgs.sharedMasksWithCatalog

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

	local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, optOverrides )
	assetDocValue._spaceId = spaceId

	if sharedMasks then

		local assetDocValue2 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optOverrides )

		if optArgs.sharedMasksOutsideOfSpace then
			assetDocValue2._spaceId = KSIdGenerator.uuidInLowercaseHex()
		elseif optArgs.sharedMasksInSpace then
			assetDocValue2._spaceId = spaceId
		end

		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue2 ) )

	end
	
	if withRedactedOzLink then
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/master', 'href' )
		KSTableUtils.setNested( assetDocValue, true, '_serverProvidedMetadata', 'links', '/rels/master', 'exists' )
		
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'href' )
		KSTableUtils.setNested( assetDocValue, true, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'exists' )
	end
	
	if onlyHasProxyLink then
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/master' )
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( assetDocValue ), ':ignore:' )
	
	-- check if all files exist
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.previewFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.thumbnailFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpDevelopSettingsFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask1FilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask2FilePath ) )
	
	-- create space and add asset into space
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {

		_id = albumId,
		_spaceId = spaceId,
		type = 'album',
		subtype = 'collection',
		name = 'foo',

	}

	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumDoc ), ':ignore:' )
	
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumAssetDoc = {

		_id = albumAssetId,
		_spaceId = spaceId,
		type = 'album_asset',
		asset = {
			id = assetId
		},
		album = {
			id = albumId
		}
	}
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumAssetDoc ), ':ignore:' )

	rxTest:observe( wfCatalog:indexStore():query{
			sql = string.format( [[SELECT docId FROM %s WHERE albumId = ?]], albumAssetTable ),
			albumId
		})
		:expectDataWithinTime( 2, {{ albumAssetId }} )
		:dispose()
	
	-- purge assets for space
	
	rxTest:waitFor( WFCatSpacePurgeUtils.DEBUG_purgeAssetsForSpace( wfCatalog, spaceId, true, keepRedactedBinaries ) )
	
	-- check if files are purged and doc is updated
	
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.originalFilePath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.proxyFilePath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.xmpDevelopSettingsFilePath ) )

	if not ( optArgs.sharedMasksOutsideOfSpace or optArgs.sharedMasksWithCatalog ) then
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.mask1FilePath ) )
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.mask2FilePath ) )
	else
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask1FilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask2FilePath ) )
	end
	
	if not keepRedactedBinaries then
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.previewFilePath ) )
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.thumbnailFilePath ) )
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( assetId )
		:map( function( assetDocValue )
			
			local check = derefUniversal( assetDocValue, 'files', 'original', 'master', 'relativePath' ) == nil
							and derefUniversal( assetDocValue, 'files', 'proxy', '2560', 'relativePath' ) == nil
							and derefUniversal( assetDocValue, 'files', 'xmp_develop', 'relativePath' ) == nil
							and WFCatAssetUtils.getLocalAuxObjectPath( assetDocValue, expectedData.mask1Fingerprint ) == nil
							and WFCatAssetUtils.getLocalAuxObjectPath( assetDocValue, expectedData.mask2Fingerprint ) == nil
							
			if keepRedactedBinaries then
				return check
			else
			
				return check
					and derefUniversal( assetDocValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ) == nil
					and derefUniversal( assetDocValue, 'files', 'renditions', '2048', 'relativePath' ) == nil
			
			end
			
		end ),
		true
	)

end 

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

local function testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	rxTest:setTimeLimit( 10 )

	local catalogService, wfCatalog = LrmCatalogTestHelper.makeCatalogService( rxTest )
	local catalogDataCache
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	optArgs = optArgs or {}

	local sharedMasks = optArgs.sharedMasksInSpace or optArgs.sharedMasksOutsideOfSpace or optArgs.sharedMasksWithCatalog

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

	local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId, optOverrides )
	assetDocValue._spaceId = spaceId

	if sharedMasks then

		local assetDocValue2 = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optOverrides )

		if optArgs.sharedMasksOutsideOfSpace then
			assetDocValue2._spaceId = KSIdGenerator.uuidInLowercaseHex()
		elseif optArgs.sharedMasksInSpace then
			assetDocValue2._spaceId = spaceId
		end

		rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue2 ) )

	end

	-- add preview and thumbnail2xData into dataCache
	
	local previewData = KSData.memoryMappedContentsOfFile( expectedData.previewFilePath )
	local thumbnail2xData = KSData.memoryMappedContentsOfFile( expectedData.thumbnailFilePath )

	local previewMd5 = previewData:digest( 'MD5' )
	local thumbMd5 = thumbnail2xData:digest( 'MD5' )
	
	rxTest:expectSingleValue( catalogService:getDataCache()
		:flatMap( function( dataCache )
			catalogDataCache = dataCache
			return dataCache:put( previewMd5, previewData )
		end )
		:map( tostring ),
		tostring( previewData ) )
		
	rxTest:expectSingleValue( catalogService:getDataCache()
		:flatMap( function( dataCache )
			return dataCache:put( thumbMd5, thumbnail2xData )
		end )
		:map( tostring ),
		tostring( thumbnail2xData ) )
		
	-- add asset into docStore
	
	if withRedactedOzLink then
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/master', 'href' )
		KSTableUtils.setNested( assetDocValue, true, '_serverProvidedMetadata', 'links', '/rels/master', 'exists' )
		
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'href' )
		KSTableUtils.setNested( assetDocValue, true, '_serverProvidedMetadata', 'links', '/rels/proxy_type/2560', 'exists' )
	end
	
	if onlyHasProxyLink then
		KSTableUtils.setNested( assetDocValue, nil, '_serverProvidedMetadata', 'links', '/rels/master' )
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( assetDocValue ), ':ignore:' )
		
	-- check if all files exist
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpDevelopSettingsFilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask1FilePath ) )
	rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask2FilePath ) )
	
	rxTest:expectSingleValue( catalogService:getDataCache()
		:flatMap( function( dataCache )
			return dataCache:get( previewMd5 )
		end )
		:map( tostring ),
		tostring( previewData ) )
		
	rxTest:expectSingleValue( catalogService:getDataCache()
		:flatMap( function( dataCache )
			return dataCache:get( thumbMd5 )
		end )
		:map( tostring ),
		tostring( thumbnail2xData ) )

	-- create space and add asset into space
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {

		_id = albumId,
		_spaceId = spaceId,
		type = 'album',
		subtype = 'collection',
		name = 'foo',

	}

	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumDoc ), ':ignore:' )
	
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumAssetDoc = {

		_id = albumAssetId,
		_spaceId = spaceId,
		type = 'album_asset',
		asset = {
			id = assetId
		},
		album = {
			id = albumId
		}
	}
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumAssetDoc ), ':ignore:' )

	rxTest:observe( wfCatalog:indexStore():query{
			sql = string.format( [[SELECT docId FROM %s WHERE albumId = ?]], albumAssetTable ),
			albumId
		})
		:expectDataWithinTime( 2, {{ albumAssetId }} )
		:dispose()
	
	-- purge assets for space
	
	rxTest:waitFor( WFCatSpacePurgeUtils.DEBUG_purgeAssetsForSpace( wfCatalog, spaceId, true, keepRedactedBinaries, catalogDataCache ) )
	
	-- check if files are purged and doc is updated
	
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.originalFilePath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.proxyFilePath ) )
	rxTest:expectEqual( false, WFFileUtils.exists( expectedData.xmpDevelopSettingsFilePath ) )

	if not ( optArgs.sharedMasksOutsideOfSpace or optArgs.sharedMasksWithCatalog ) then
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.mask1FilePath ) )
		rxTest:expectEqual( false, WFFileUtils.exists( expectedData.mask2FilePath ) )
	else
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask1FilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.mask2FilePath ) )
	end
	
	if not keepRedactedBinaries then
	
		rxTest:expectSingleValue( catalogService:getDataCache()
			:flatMap( function( dataCache )
				return dataCache:get( previewMd5 )
			end ),
			nil )
			
		rxTest:expectSingleValue( catalogService:getDataCache()
			:flatMap( function( dataCache )
				return dataCache:get( thumbMd5 )
			end ),
			nil )
	
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( assetId )
		:map( function( assetDocValue )
			
			local check = derefUniversal( assetDocValue, 'files', 'original', 'master', 'relativePath' ) == nil
							and derefUniversal( assetDocValue, 'files', 'proxy', '2560', 'relativePath' ) == nil
							and derefUniversal( assetDocValue, 'files', 'xmp_develop', 'relativePath' ) == nil
							and WFCatAssetUtils.getLocalAuxObjectPath( assetDocValue, expectedData.mask1Fingerprint ) == nil
							and WFCatAssetUtils.getLocalAuxObjectPath( assetDocValue, expectedData.mask2Fingerprint ) == nil
							
			if keepRedactedBinaries then
				return check
			else
			
				return check
					and derefUniversal( assetDocValue, 'files', 'renditions', 'thumbnail2x', 'relativePath' ) == nil
					and derefUniversal( assetDocValue, 'files', 'renditions', '2048', 'relativePath' ) == nil
			
			end
			
		end ),
		true
	)

	previewData:close()
	thumbnail2xData:close()

end 

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace( rxTest )

	local keepRedactedBinaries = false
	local withRedactedOzLink = false
	local onlyHasProxyLink = false
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_SharedAuxInSpace( rxTest )

	local keepRedactedBinaries = false
	local withRedactedOzLink = false
	local onlyHasProxyLink = false

	local optArgs = {
		sharedMasksInSpace = true
	}

	if WFPlatformInfo.isDesktop then

		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	elseif WFPlatformInfo.isiOS then

		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	elseif WFPlatformInfo.isAndroid then

		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_SharedAuxOutsideOfSpace( rxTest )

	local keepRedactedBinaries = false
	local withRedactedOzLink = false
	local onlyHasProxyLink = false

	local optArgs = {
		sharedMasksOutsideOfSpace = true
	}

	if WFPlatformInfo.isDesktop then

		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	elseif WFPlatformInfo.isiOS then

		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	elseif WFPlatformInfo.isAndroid then

		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_SharedAuxWithCatalog( rxTest )

	local keepRedactedBinaries = false
	local withRedactedOzLink = false
	local onlyHasProxyLink = false

	local optArgs = {
		sharedMasksWithCatalog = true
	}

	if WFPlatformInfo.isDesktop then

		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	elseif WFPlatformInfo.isiOS then

		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	elseif WFPlatformInfo.isAndroid then

		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink, optArgs )

	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_WithRedactedMaterLink( rxTest )

	local keepRedactedBinaries = false
	local withRedactedOzLink = true
	local onlyHasProxyLink = false
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_KeepRedactedBinaries( rxTest )

	local keepRedactedBinaries = true
	local withRedactedOzLink = false
	local onlyHasProxyLink = false
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_KeepRedactedBinaries_WithRedactedMaterLink( rxTest )

	local keepRedactedBinaries = true
	local withRedactedOzLink = true
	local onlyHasProxyLink = false
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_KeepRedactedBinaries_onlyHasProxyLink( rxTest )

	local keepRedactedBinaries = true
	local withRedactedOzLink = false
	local onlyHasProxyLink = true
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_KeepRedactedBinaries_OnlyHasProxyRedactedLink( rxTest )

	local keepRedactedBinaries = true
	local withRedactedOzLink = true
	local onlyHasProxyLink = true
	
	if WFPlatformInfo.isDesktop then
	
		testPurgeAssetsForSpace_desktop( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isiOS then
	
		testPurgeAssetsForSpace_iOS( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	elseif WFPlatformInfo.isAndroid then
	
		testPurgeAssetsForSpace_android( rxTest, keepRedactedBinaries, withRedactedOzLink, onlyHasProxyLink )
		
	end

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeAssetsForSpace_EditorDowngradWithBinariesNotUploaded( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetDocValue, expectedData = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId )
	assetDocValue._spaceId = spaceId
	assetDocValue._serverProvidedMetadata = nil
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( assetDocValue ), ':ignore:' )
	
	-- check if all files exist
	
	if WFPlatformInfo.isDesktop then
	
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpSidecarFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
	
	else
	
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpDevelopSettingsFilePath ) )
		
	end

	-- create space and add asset into space
	
	local albumId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumDoc = {

		_id = albumId,
		_spaceId = spaceId,
		type = 'album',
		subtype = 'collection',
		name = 'foo',

	}

	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumDoc ), ':ignore:' )
	
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local albumAssetDoc = {

		_id = albumAssetId,
		_spaceId = spaceId,
		type = 'album_asset',
		asset = {
			id = assetId
		},
		album = {
			id = albumId
		}
	}
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( albumAssetDoc ), ':ignore:' )

	local expectedAlbumAssetDocId = albumAssetId
	if WFPlatformInfo.isDesktop then
		expectedAlbumAssetDocId = 3
	end
	
	rxTest:observe( wfCatalog:indexStore():query{
			sql = string.format( [[SELECT docId FROM %s WHERE albumId = ?]], albumAssetTable ),
			albumId
		})
		:expectDataWithinTime( 3, {{ expectedAlbumAssetDocId }} )
		:dispose()
	
	-- purge assets for space
	
	rxTest:waitFor( WFCatSpacePurgeUtils.DEBUG_purgeAssetsForSpace( wfCatalog, spaceId, true, true ) )
	
	-- check if original, proxy and xmp_develop files still exists
	
	if WFPlatformInfo.isDesktop then
	
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpSidecarFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
	
	else
	
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.originalFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.proxyFilePath ) )
		rxTest:expectEqual( 'file', WFFileUtils.exists( expectedData.xmpDevelopSettingsFilePath ) )
		
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( assetId )
		:map( function( assetDocValue )
			
			if WFPlatformInfo.isDesktop then
			
				return derefOpt( assetDocValue, '_localOnly', 'files', 'original', 'master', 'relativePath' ) ~= nil
					and derefOpt( assetDocValue, '_localOnly', 'files', 'proxy', '2560', 'relativePath' ) ~= nil
					and derefOpt( assetDocValue, '_localOnly', 'files', 'original', 'xmp', 'path' ) ~= nil
			
			else
			
				return derefUniversal( assetDocValue, 'files', 'original', 'master', 'relativePath' ) ~= nil
					and derefUniversal( assetDocValue, 'files', 'proxy', '2560', 'relativePath' ) ~= nil
					and derefUniversal( assetDocValue, 'files', 'xmp_develop', 'relativePath' ) ~= nil
			
			end
			
		end ),
		true
	)

end

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

function WFCatSpacePurgeUtilsTest.rxTestPurgeSyncedVersionsForSpace( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local spaceId = KSIdGenerator.uuidInLowercaseHex()
	local ownerId = KSIdGenerator.uuidInLowercaseHex()
	local spaceUserId = KSIdGenerator.uuidInLowercaseHex()
	
	local spaceDoc = {
		_id = spaceId,
		type = 'space',
		subtype = 'shared',
		download = false,
		private = false,
		location = false,
		metadata = false,
		_serverProvidedMetadata = {
			owner = {
				id = ownerId
			},
			this_space_user = {
				id = spaceUserId
			}
		}
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( spaceDoc ) )
	
	-- Add an space_user to the space
	
	local spaceUserDoc = {
		_id = spaceUserId,
		type = 'space_user',
		space = { id = spaceId },
		user = { id = KSIdGenerator.uuidInLowercaseHex() },
		role = 'editor'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( spaceUserDoc ) )
	
	-- Create asset
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetDocValue, _ = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId )
	assetDocValue._spaceId = spaceId
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue ) )
	
	-- Create a fully synced Version
	
	local versionName = "Foo"
	
	local versionId = rxTest:getFirstValue( WFCatVersions.createVersionForAsset( wfCatalog, assetId, false, versionName ) )
		
	local versionXmpDevelopSettingsFilePath = rxTest:getFirstValue( wfCatalog:docStore():docValue( versionId )
		
			:map( function( versionDocValue )
			
				local path = derefOpt( versionDocValue, '_localOnly', 'files', 'xmp_develop', 'path' )
				
				if WFPlatformInfo.isMobile() then
					path = LrmOzPurgeAgentUtils.absolutePath( wfCatalog:ozCatalogId(), path )
				end
				
				return path
			
			end ) )
	
	local overlay = {
		_id = versionId
	}
	
	local links = {
		['/rels/xmp/develop'] = {
			href = 'foo'
		}
	}
	
	KSTableUtils.setNested( overlay, links, '_serverProvidedMetadata', 'links' )
	
	rxTest:waitFor( wfCatalog:docStore():applyOverlay( overlay ) )
	
	rxTest:observe( wfCatalog:indexStore():query {
			sql = [[SELECT docId FROM versions WHERE spaceId = ?]],
			spaceId
		} )
		:expectDataWithinTime( 2, {{ versionId }} )
		:dispose()
	
	-- check if xmp_develop file exists
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( versionXmpDevelopSettingsFilePath ) )
	
	-- purge versions for space
	
	rxTest:waitFor( WFCatSpacePurgeUtils.DEBUG_purgeVersionsForSpace( wfCatalog, spaceId, true ) )
	
	-- check if xmp_develop file is purged and doc is updated
	-- xmp_develop file won't be purged on desktop, it's handled by PixelProviderFileCachePurgeWorker
	
	if not WFPlatformInfo.isDesktop then
		
		rxTest:expectEqual( false, WFFileUtils.exists( versionXmpDevelopSettingsFilePath ) )
		
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( versionId )
			:map( function( versionDocValue )
				
				return derefOpt( versionDocValue, '_localOnly', 'files', 'xmp_develop', 'path' )

			end ),
			nil )
	
end

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

function WFCatSpacePurgeUtilsTest.rxTestDontPurgeUnsyncedVersionsForSpace( rxTest )

	rxTest:setTimeLimit( 100 )

	local wfCatalog = createFakeWFCatalog( rxTest )
	
	local spaceId = KSIdGenerator.uuidInLowercaseHex()
	local ownerId = KSIdGenerator.uuidInLowercaseHex()
	local spaceUserId = KSIdGenerator.uuidInLowercaseHex()
	
	local spaceDoc = {
		_id = spaceId,
		type = 'space',
		subtype = 'shared',
		download = false,
		private = false,
		location = false,
		metadata = false,
		_serverProvidedMetadata = {
			owner = {
				id = ownerId
			},
			this_space_user = {
				id = spaceUserId
			}
		}
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( spaceDoc ) )
	
	-- Add an space_user to the space
	
	local spaceUserDoc = {
		_id = spaceUserId,
		type = 'space_user',
		space = { id = spaceId },
		user = { id = KSIdGenerator.uuidInLowercaseHex() },
		role = 'editor'
	}
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( spaceUserDoc ) )
	
	-- Create asset
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	local assetDocValue, _ = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, assetId )
	assetDocValue._spaceId = spaceId
	
	rxTest:waitFor( wfCatalog:docStore():setDocValue( assetDocValue ) )
	
	-- Create an unsynced Version document.
	
	local versionName = "Foo"
	
	local versionId = rxTest:getFirstValue( WFCatVersions.createVersionForAsset( wfCatalog, assetId, false, versionName ) )
		
	local versionXmpDevelopSettingsFilePath = rxTest:getFirstValue( wfCatalog:docStore():docValue( versionId )
		
			:map( function( versionDocValue )
			
				local path = derefOpt( versionDocValue, '_localOnly', 'files', 'xmp_develop', 'path' )
				
				if WFPlatformInfo.isMobile() then
					path = LrmOzPurgeAgentUtils.absolutePath( wfCatalog:ozCatalogId(), path )
				end
				
				return path
			
			end ) )
	
	rxTest:observe( wfCatalog:indexStore():query{
			sql = [[SELECT docId FROM versions WHERE spaceId = ?]],
			spaceId
		} )
		:expectDataWithinTime( 2, {{ versionId }} )
		:dispose()
	
	-- check if xmp_develop file exists
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( versionXmpDevelopSettingsFilePath ) )
	
	-- purge versions for space
	
	rxTest:waitFor( WFCatSpacePurgeUtils.DEBUG_purgeVersionsForSpace( wfCatalog, spaceId, true ) )
	
	-- Make sure the unsynced version was *not* purged
	
	rxTest:expectEqual( 'file', WFFileUtils.exists( versionXmpDevelopSettingsFilePath ) )

	rxTest:expectSingleValue( wfCatalog:docStore():docValue( versionId )
		:map( function( versionDocValue )
			
			local path = derefOpt( versionDocValue, '_localOnly', 'files', 'xmp_develop', 'path' )
				
			if WFPlatformInfo.isMobile() then
				path = LrmOzPurgeAgentUtils.absolutePath( wfCatalog:ozCatalogId(), path )
			end
			
			return path
			
		end ),
		versionXmpDevelopSettingsFilePath
	)
	
end 

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

return WFRxTestCase.wrapSuite( 'WFCatSpacePurgeUtilsTest', WFCatSpacePurgeUtilsTest )
