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

NmbLeakedFileDetectorTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2017 Adobe Systems Incorporated
All Rights Reserved.

NOTICE: All information contained herein is, and remain the property of
Adobe Systems Incorporated and its suppliers, if any. The intellectual and
technical concepts contained herein are proprietary to Adobe Systems
Incorporated and its suppliers and may be covered by U.S. and Foreign
Patents, patents in process, and are protected by trade secret or copyright
law.  Dissemination of this information or reproduction of this material is
strictly forbidden unless prior written permission is obtained from
Adobe Systems Incorporated.

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

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

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

	-- WF.oz_client.managed_catalog
local WFCatMockCatalog = require 'WFCatMockCatalog'
local NmbLeakedFileDetector = require 'NmbLeakedFileDetector'
local NmbPathRestorer = require 'NmbPathRestorer'


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

local NmbLeakedFileDetectorTest = {}

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

local pathToOriginals = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'testdata' ), KSIdGenerator.uuidInLowercaseHex() )
pathToOriginals = KSPathUtils.child( pathToOriginals, 'originals' )

local pathToProxies = KSPathUtils.child( KSPathUtils.getStandardFilePath( 'testdata' ), KSIdGenerator.uuidInLowercaseHex() )
pathToProxies = KSPathUtils.child( pathToProxies, 'proxies' )

local onlineVolumeGuid = WFFileUtils.getVolumeGuidForPath( pathToOriginals )

local mockImage = KSData.make( 'data' )

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

local function basicDocValue( binaryType, isTracked )

	local maybeLocalOriginal 
	
	local path 
	
	if binaryType == 'original' then
	
		path = KSPathUtils.child( pathToOriginals, KSIdGenerator.uuidInLowercaseHex() )
	
		if isTracked then
	
			maybeLocalOriginal = {
				master = {
					relativePath = WFFileUtils.removeVolumeFromPath( path ),
					volumeGuid = onlineVolumeGuid,
				}
			}

		end
			
	end
	
	local maybeLocalProxy 
	
	if binaryType == 'proxy' then
	
		path = KSPathUtils.child( pathToProxies, KSIdGenerator.uuidInLowercaseHex() )
	
		if isTracked then
	
			maybeLocalProxy = {
				[ '2560' ] = {
					relativePath = WFFileUtils.removeVolumeFromPath( path ),
					volumeGuid = onlineVolumeGuid,
				}
			}

		end
			
	end

	if path then
	
		KSData.saveToFile( mockImage, path )
	
	end

	return {

		type = 'asset',
		subtype = 'image',
		
		importSource = {
			importTimestamp = "2015-05-26T17:34:23-07:00",
			fileName = "Image.jpg",
		},
		
		_localOnly = {
			isMarkedForOfflineUse = false,
			files = {
				original = maybeLocalOriginal,
				proxy = maybeLocalProxy
			}
		},

		_serverProvidedMetadata = {
			revision_ids = {
				KSIdGenerator.uuidInLowercaseHex()
			},
			links = {
			
				[ '/rels/master' ] = {
					href = 'path/to/original.jpg',
				},
				[ '/rels/proxy_type/2560' ] = {
					href = 'path/to/proxy.jpg',
				}
			}
		}

	}, path
	
end

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

local function createAsset( rxTest, wfCatalog, binaryType, isTracked, isArchived )

	WFFileUtils.mkdir( pathToOriginals )
	WFFileUtils.mkdir( pathToProxies )

	local docId = KSIdGenerator.uuidInLowercaseHex()

	local docValue, path = basicDocValue( binaryType, isTracked, isArchived )
	docValue._id = docId
	
	local docStore = wfCatalog:docStore()
	
	rxTest:expectSingleValue( docStore:setDocValue( docValue ), ':ignore:' )

	if isArchived then
	
		-- Add the archived annotations
		
		local binarySize = binaryType == 'original' and 'master' or '2560'
		
		rxTest:expectSingleValue(
			docStore:docValue( docId )
				:flatMap( function( docValue )
				
					local localId = docValue._localId
					
					return NmbPathRestorer.archiveLocalFilePath( docStore, localId, binaryType, binarySize )
					
				end ), ':ignore:' )
			
		-- Remove the non-archived annotations
		
		local binarySizes = {}
				
		binarySizes[ binarySize ] = {
		
			relativePath = { _delete = true },
			volumeGuid = { _delete = true }
			
		}
		
		local files = {}
		files[ binaryType ] = binarySizes
		
		rxTest:expectSingleValue( docStore:applyOverlay(
			{	
				_id = docId,
				_localOnly = {  
					files = files
				}
			} ), ':ignore:' )
			
	end

	return path

end

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

function NmbLeakedFileDetectorTest.rxTestCleanupLeakedProxies( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local indexStore = wfCatalog:indexStore()
	
	-- Create Original
	
	local origLocalPath1 = createAsset( rxTest, wfCatalog, 'original', true ) -- Tracked
	local origLocalPath2 = createAsset( rxTest, wfCatalog, 'original', true ) -- Tracked
	local origLocalPath3 = createAsset( rxTest, wfCatalog, 'original', true, true ) -- Archived
	local origLocalPath4 = createAsset( rxTest, wfCatalog, 'original', true, true ) -- Archived
	local origLocalPath5 = createAsset( rxTest, wfCatalog, 'original', false ) -- Not Tracked
	local origLocalPath6 = createAsset( rxTest, wfCatalog, 'original', false ) -- Not Tracked
	
	-- Create Proxy

	local proxyLocalPath1 = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
	local proxyLocalPath2 = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
	local proxyLocalPath3 = createAsset( rxTest, wfCatalog, 'proxy', true, true ) -- Archived
	local proxyLocalPath4 = createAsset( rxTest, wfCatalog, 'proxy', true, true ) -- Archived
	local proxyLocalPath5 = createAsset( rxTest, wfCatalog, 'proxy', false ) -- Not Tracked
	local proxyLocalPath6 = createAsset( rxTest, wfCatalog, 'proxy', false ) -- Not Tracked
	
	local paths = {
		pathToProxies
	}

	local optArgs = {
		deleteLeakedFiles = true,
	}

	rxTest:expectOnlyCompleted( NmbLeakedFileDetector.cleanUpLeakedFiles( indexStore, 'proxy', paths, optArgs ) )

	-- Check that the untracked files in the proxies directory are cleaned.
	
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath5 ), false )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath6 ), false )
	
	-- Tracked proxies, and all of the originals, should be untouched.

	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath1 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath2 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath3 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath4 ), 'file' )

	rxTest:expectEqual( WFFileUtils.exists( origLocalPath1 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath2 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath3 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath4 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath5 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath6 ), 'file' )
	
	rxTest:finally( function()
	
		WFFileUtils.delete( pathToOriginals )
		WFFileUtils.delete( pathToProxies )
	
	end )
	
end

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

function NmbLeakedFileDetectorTest.rxTestCleanupLeakedOriginals( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local indexStore = wfCatalog:indexStore()
	
	-- Create Original
	
	local origLocalPath1 = createAsset( rxTest, wfCatalog, 'original', true ) -- Tracked
	local origLocalPath2 = createAsset( rxTest, wfCatalog, 'original', true ) -- Tracked
	local origLocalPath3 = createAsset( rxTest, wfCatalog, 'original', true, true ) -- Archived
	local origLocalPath4 = createAsset( rxTest, wfCatalog, 'original', true, true ) -- Archived
	local origLocalPath5 = createAsset( rxTest, wfCatalog, 'original', false ) -- Not Tracked
	local origLocalPath6 = createAsset( rxTest, wfCatalog, 'original', false ) -- Not Tracked
	
	-- Create Proxy

	local proxyLocalPath1 = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
	local proxyLocalPath2 = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
	local proxyLocalPath3 = createAsset( rxTest, wfCatalog, 'proxy', true, true ) -- Archived
	local proxyLocalPath4 = createAsset( rxTest, wfCatalog, 'proxy', true, true ) -- Archived
	local proxyLocalPath5 = createAsset( rxTest, wfCatalog, 'proxy', false ) -- Not Tracked
	local proxyLocalPath6 = createAsset( rxTest, wfCatalog, 'proxy', false ) -- Not Tracked
	
	local paths = {
		pathToOriginals
	}

	local optArgs = {
		deleteLeakedFiles = true,
	}

	rxTest:expectOnlyCompleted( NmbLeakedFileDetector.cleanUpLeakedFiles( indexStore, 'original', paths, optArgs ) )

	-- Check that the untracked files in the originals dir are cleaned.
	
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath5 ), false )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath6 ), false )
	
	-- Tracked originals, and all of the proxies, should be untouched.

	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath1 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath2 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath3 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath4 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath5 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath6 ), 'file' )
	
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath1 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath2 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath3 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath4 ), 'file' )
	
	rxTest:finally( function()
	
		WFFileUtils.delete( pathToOriginals )
		WFFileUtils.delete( pathToProxies )
	
	end )
	
end

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

function NmbLeakedFileDetectorTest.rxTestCleanupNoop( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local indexStore = wfCatalog:indexStore()
	
	-- Create Original
	
	local origLocalPath1 = createAsset( rxTest, wfCatalog, 'original', true ) -- Tracked
	local origLocalPath2 = createAsset( rxTest, wfCatalog, 'original', true ) -- Tracked
	local origLocalPath3 = createAsset( rxTest, wfCatalog, 'original', true, true ) -- Archived
	local origLocalPath4 = createAsset( rxTest, wfCatalog, 'original', true, true ) -- Archived
	
	-- Create Proxy

	local proxyLocalPath1 = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
	local proxyLocalPath2 = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
	local proxyLocalPath3 = createAsset( rxTest, wfCatalog, 'proxy', true, true ) -- Archived
	local proxyLocalPath4 = createAsset( rxTest, wfCatalog, 'proxy', true, true ) -- Archived

	local paths = {
		pathToProxies
	}

	local optArgs = {
		deleteLeakedFiles = true,
	}

	rxTest:expectOnlyCompleted( NmbLeakedFileDetector.cleanUpLeakedFiles( indexStore, 'proxy', paths, optArgs ) )

	-- All files should be untouched.

	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath1 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath2 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath3 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( proxyLocalPath4 ), 'file' )

	rxTest:expectEqual( WFFileUtils.exists( origLocalPath1 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath2 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath3 ), 'file' )
	rxTest:expectEqual( WFFileUtils.exists( origLocalPath4 ), 'file' )

	rxTest:finally( function()
	
		WFFileUtils.delete( pathToOriginals )
		WFFileUtils.delete( pathToProxies )
	
	end )

end

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

local WFLogger = require 'WFLogger'
local logger = WFLogger 'WFCatIdleDownloaderTest'
logger:enable( 'print' )

function NmbLeakedFileDetectorTest.DISABLED_rxTestCleanupLeakedProxies_testPerformance( rxTest )

	rxTest:setTimeLimit( 100 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local indexStore = wfCatalog:indexStore()
	
	local numberOfLeakedAssets = 500
	local leakedFiles = {}
	
	for i=1, numberOfLeakedAssets do 

		leakedFiles[ i ] = createAsset( rxTest, wfCatalog, 'proxy', false ) -- Not Tracked
		
	end
	
	local assetPaths = {}
	local numberOfAssets = 10000
	
	for i=1, numberOfAssets do 

		assetPaths[ i ] = createAsset( rxTest, wfCatalog, 'proxy', true ) -- Tracked
		
	end
	
	local paths = {
		pathToProxies
	}

	local startTime = KSDate.timeNow()
		
	logger:infof( "Starting File Leak Detection" )

	rxTest:expectOnlyCompleted( NmbLeakedFileDetector.cleanUpLeakedFiles( indexStore, 'proxy', paths ) )

	local endTime = KSDate.timeNow()
	
	local duration = endTime - startTime
	
	logger:infof( "Leak Detection Complete in %.3f seconds", duration )

	-- Check that the untracked files in the proxies directory are cleaned.

	for i=1, numberOfLeakedAssets do 
		rxTest:expectEqual( WFFileUtils.exists( leakedFiles[ i ] ), false )
	end

	for i=1, numberOfAssets do 
		rxTest:expectEqual( WFFileUtils.exists( assetPaths[ i ] ), 'file' )
	end
	
	rxTest:finally( function()
	
		WFFileUtils.delete( pathToOriginals )
		WFFileUtils.delete( pathToProxies )
	
	end )
	
end

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

return WFRxTestCase.wrapSuite( 'NmbLeakedFileDetectorTest', NmbLeakedFileDetectorTest )
