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

NmbPathRestorerTest.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 KSTableUtils = require 'KSTableUtils'
local WFFileUtils = require 'WFFileUtils'
local KSPathUtils = require 'KSPathUtils'

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

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

local KSTableUtils_derefOpt = assert( KSTableUtils.derefOpt, 
										"KSTableUtils.derefOpt undefined" )

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

local NmbPathRestorerTest = {}

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

local basePath = KSPathUtils.getStandardFilePath( 'carouselDocuments' )
local onlineVolumeGuid = WFFileUtils.getVolumeGuidForPath( basePath )

local offlineVolumeGuid = KSIdGenerator.uuidInLowercaseHex()

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

local function basicDocValue( binaryType, realSha256, isOffline )

	local maybeLocalOriginal = binaryType == 'original' and
	{
		master = {
			sha256 = realSha256,
			relativePath = 'path/to/original.jpg',
			volumeGuid = isOffline and offlineVolumeGuid or onlineVolumeGuid,
			size = 100,
		}
	}
			
	local maybeLocalProxy = binaryType == 'proxy' and 
	{
		[ '2560' ] = {
			sha256 = realSha256,
			relativePath = 'path/to/proxy.jpg',
			volumeGuid = isOffline and offlineVolumeGuid or onlineVolumeGuid,
			size = 50, 
		},
	}

	return {

		type = 'asset',
		subtype = 'image',
		
		importSource = {
			importTimestamp = "2015-05-26T17:34:23-07:00",
			fileName = "Image.jpg",
			sha256 = realSha256,
		},
		
		_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',
				}
			}
		}

	}
	
end

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

local function createAsset( rxTest, wfCatalog, binaryType, isOffline )

	local docId = KSIdGenerator.uuidInLowercaseHex()
	
	local realSha256 = KSIdGenerator.uuidInLowercaseHex()
	
	local docValue = basicDocValue( binaryType, realSha256, isOffline )
	docValue._id = docId
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( docValue ), ':ignore:' )
	
	local localId
	
	rxTest:expectSingleValue(
		wfCatalog:docStore():docValue( docId )
			:map( function( docValue )
			
				localId = docValue._localId
				return true
				
			end ), true )
			

	return localId

end

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

local function checkIfArchived( rxTest, docStore, localId, binaryType, binarySize, shouldBeArchived )

	rxTest:expectSingleValue(
		docStore:docValue( localId )
			:map( function( docValue )
			
				local localOnlyFiles = KSTableUtils_derefOpt( docValue, '_localOnly', 'files' )
				local archivedVolumeGuid = KSTableUtils_derefOpt( localOnlyFiles, binaryType, binarySize, 'archivedVolumeGuid' )
				local archivedRelativePath = KSTableUtils_derefOpt( localOnlyFiles, binaryType, binarySize, 'archivedRelativePath' )
				local archivedSha256 = KSTableUtils_derefOpt( localOnlyFiles, binaryType, binarySize, 'archivedSha256' )
			
				return {
					not not archivedVolumeGuid,
					not not archivedRelativePath,
					not not archivedSha256,
				}
				
			end ), { shouldBeArchived, shouldBeArchived, shouldBeArchived } )

end

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

local function checkStandardAnnotations( rxTest, docStore, localId, binaryType, binarySize, shouldExist, expectedSha )

	rxTest:expectSingleValue(
		docStore:docValue( localId )
			:map( function( docValue )
			
				local localOnlyFiles = KSTableUtils_derefOpt( docValue, '_localOnly', 'files' )
				local volumeGuid = KSTableUtils_derefOpt( localOnlyFiles, binaryType, binarySize, 'volumeGuid' )
				local relativePath = KSTableUtils_derefOpt( localOnlyFiles, binaryType, binarySize, 'relativePath' )
				local sha256 = KSTableUtils_derefOpt( localOnlyFiles, binaryType, binarySize, 'sha256' )
			
				return {
					not not volumeGuid,
					not not relativePath,
					expectedSha and sha256 or ( not not sha256 ),
				}
				
			end ), { shouldExist, shouldExist, expectedSha or shouldExist } )

end

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

local function removeNonArchivedAnnotations( rxTest, docStore, localId, binaryType, binarySize )

	local binarySizes = {}
			
	binarySizes[ binarySize ] = {
	
		relativePath = { _delete = true },
		sha256 = { _delete = true },
		volumeGuid = { _delete = true }
		
	}
	
	local files = {}
	files[ binaryType ] = binarySizes
	
	rxTest:expectSingleValue( docStore:applyOverlay(
			{	
				_id = localId,
				_localOnly = {  
					files = files
				}
			} ), ':ignore:' )

end

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

local function revSha( rxTest, docStore, localId, binaryType, binarySize )

	local newSha = KSIdGenerator.uuidInLowercaseHex()

	local binarySizes = {}
			
	binarySizes[ binarySize ] = {
	
		sha256 = newSha
		
	}
	
	local files = {}
	files[ binaryType ] = binarySizes
	
	rxTest:expectSingleValue( docStore:applyOverlay(
			{	
				_id = localId,
				_localOnly = {  
					files = files
				}
			} ), ':ignore:' )

	return newSha

end

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

function NmbPathRestorerTest.rxTestRestoreBasic( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()
	local deletionBacklog = wfCatalog:getDeletionBacklog()
	
	-- Create Original
	
	local origLocalId = createAsset( rxTest, wfCatalog, 'original' )

	-- Create Proxy

	local proxyLocalId = createAsset( rxTest, wfCatalog, 'proxy' )

	-- Archive the files
	
	rxTest:expectSingleValue( NmbPathRestorer.archiveLocalFilePath( docStore, origLocalId, 'original', 'master' ), ':ignore:' )
	
	rxTest:expectSingleValue( NmbPathRestorer.archiveLocalFilePath( docStore, proxyLocalId, 'proxy', '2560' ), ':ignore:' )
	
	-- Remove the standard file path annotations.
	
	removeNonArchivedAnnotations( rxTest, docStore, origLocalId, 'original', 'master' )
	
	removeNonArchivedAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560' )
	
	checkStandardAnnotations( rxTest, docStore, origLocalId, 'original', 'master', false )

	checkStandardAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560', false )
	
	-- Verify files are archived
	
	checkIfArchived( rxTest, docStore, origLocalId, 'original', 'master', true )
	
	checkIfArchived( rxTest, docStore, proxyLocalId, 'proxy', '2560', true )
	
	-- Restore Files
	
	rxTest:expectSingleValue( NmbPathRestorer.restoreArchivedPaths( docStore, indexStore, deletionBacklog ), true )
	
	-- Verify files are restored
	
	checkIfArchived( rxTest, docStore, origLocalId, 'original', 'master', false )
	
	checkIfArchived( rxTest, docStore, proxyLocalId, 'proxy', '2560', false )

	checkStandardAnnotations( rxTest, docStore, origLocalId, 'original', 'master', true )

	checkStandardAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560', true )

end

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

function NmbPathRestorerTest.rxTestRestoreDisconnectedVolume_NoOp( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()
	local deletionBacklog = wfCatalog:getDeletionBacklog()
	
	-- Create Original
	
	local origLocalId = createAsset( rxTest, wfCatalog, 'original', true )

	-- Create Proxy

	local proxyLocalId = createAsset( rxTest, wfCatalog, 'proxy', true )

	-- Archive the files
	
	rxTest:expectSingleValue( NmbPathRestorer.archiveLocalFilePath( docStore, origLocalId, 'original', 'master' ), ':ignore:' )
	
	rxTest:expectSingleValue( NmbPathRestorer.archiveLocalFilePath( docStore, proxyLocalId, 'proxy', '2560' ), ':ignore:' )
	
	-- Remove the standard file path annotations.
	
	removeNonArchivedAnnotations( rxTest, docStore, origLocalId, 'original', 'master' )
	
	removeNonArchivedAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560' )
	
	checkStandardAnnotations( rxTest, docStore, origLocalId, 'original', 'master', false )

	checkStandardAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560', false )
	
	-- Verify files are archived
	
	checkIfArchived( rxTest, docStore, origLocalId, 'original', 'master', true )
	
	checkIfArchived( rxTest, docStore, proxyLocalId, 'proxy', '2560', true )
	
	-- Restore Files
	
	rxTest:expectSingleValue( NmbPathRestorer.restoreArchivedPaths( docStore, indexStore, deletionBacklog ), true )
	
	-- Verify files are NOT restored since they're on an offline volume.
	
	checkIfArchived( rxTest, docStore, origLocalId, 'original', 'master', true )
	
	checkIfArchived( rxTest, docStore, proxyLocalId, 'proxy', '2560', true )

	checkStandardAnnotations( rxTest, docStore, origLocalId, 'original', 'master', false )

	checkStandardAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560', false )

end

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

function NmbPathRestorerTest.rxTestArchivedFilesOutOfDate( rxTest )

	rxTest:setTimeLimit( 10 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()
	local deletionBacklog = wfCatalog:getDeletionBacklog()
	
	-- Create Original
	
	local origLocalId = createAsset( rxTest, wfCatalog, 'original' )

	-- Create Proxy

	local proxyLocalId = createAsset( rxTest, wfCatalog, 'proxy' )

	-- Archive the files
	
	rxTest:expectSingleValue( NmbPathRestorer.archiveLocalFilePath( docStore, origLocalId, 'original', 'master' ), ':ignore:' )
	
	rxTest:expectSingleValue( NmbPathRestorer.archiveLocalFilePath( docStore, proxyLocalId, 'proxy', '2560' ), ':ignore:' )
	
	-- Verify files are archived
	
	checkIfArchived( rxTest, docStore, origLocalId, 'original', 'master', true )
	
	checkIfArchived( rxTest, docStore, proxyLocalId, 'proxy', '2560', true )
	
	-- Change SHA of existing assets.
	
	local newOrigSha = revSha( rxTest, docStore, origLocalId, 'original', 'master' )
	
	local newProxySha = revSha( rxTest, docStore, proxyLocalId, 'proxy', '2560' )
	
	-- Attempt to Restore Files
	
	rxTest:expectSingleValue( NmbPathRestorer.restoreArchivedPaths( docStore, indexStore, deletionBacklog ), true )
	
	-- Verify that the files are NOT restored beacuse they're out of date, but archived paths are removed.
	
	checkIfArchived( rxTest, docStore, origLocalId, 'original', 'master', false )
	
	checkIfArchived( rxTest, docStore, proxyLocalId, 'proxy', '2560', false )

	checkStandardAnnotations( rxTest, docStore, origLocalId, 'original', 'master', true, newOrigSha )

	checkStandardAnnotations( rxTest, docStore, proxyLocalId, 'proxy', '2560', true, newProxySha )

end

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

return WFRxTestCase.wrapSuite( 'NmbPathRestorerTest', NmbPathRestorerTest )
