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

WFCatTrashMultipleDevicesOtherDeleteTrashTest.lua

--------------------------------------------------------------------------------
ADOBE CONFIDENTIAL
------------------
Copyright 2023 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'
local WFTestFileUtils = require 'WFTestFileUtils'

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

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local KSTableUtils = require 'KSTableUtils'
local WFCatAssetUtils = require 'WFCatAssetUtils'
local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'

	-- WF.oz_client.managed_catalog
local WFCatTrash = require 'WFCatTrash'
local WFCatTrashTestUtils = require 'WFCatTrashTestUtils'
local WFCatTrashUtils = require 'WFCatTrashUtils'

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

local coveragePath

local derefOpt = KSTableUtils.derefOpt

local kOzWaitMultiplier = 30
local kTimeoutForSendingUpdates = 5

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

local WFCatTrashMultipleDevicesOtherDeleteTrashTest = {}

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

local function setTimeoutAndRetryLimit( rxTest, options, timeoutValue )

	rxTest:setTimeLimit( timeoutValue )

	if not options.mock then
		rxTest:setRetryLimit( 3, 30 )
	end

end

--==============================================================================
-- @mark tests that involve other client actions
--==============================================================================

local function testAddSyncRestoreOtherDeleteTrashSync( rxTest, options )

-- NMB-9395
-- This tests the two client scenario where one client attempts to restore an
-- asset from the trash while another client has permanently deleted that asset
-- from the trash. In this case, the client attempting to restore the asset
-- should instead create the new asset from scratch instead of asking Oz to restore
-- the trash asset

	options = options or {}

	local waitMultiplier = options.mock and 1 or kOzWaitMultiplier

	setTimeoutAndRetryLimit( rxTest, options, 15 * waitMultiplier )

	local testSession, catalog, catalogSpec, pusher, puller, uploader, pc, errorHandler = WFCatTrashTestUtils.setupCloudTrashTestSession( rxTest, options )
	assert( testSession )

	local userCreated = '2018-04-15T18:18:18Z'
	local importTimestamp = '2018-04-15T19:19:19Z'
	local assetCreated = '2018-04-15T20:20:20Z'

	local subtype = 'image'
	local fileName = "IMG_7763.JPG"
	local sha256 = "3bd8b936cc646bf1296e5ba4a76c410a27beb80809f525a8f5072f0115c54ccc"
	local proxyFileName = "IMG_7763.DNG"

	fileName = options.fileName or fileName
	subtype = options.subtype or subtype
	local trashAssetSubtype = 'deleted_' .. subtype

	local catalogId = catalog:ozCatalogId()
	local userId = catalog:ozUserId()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local revisionId

	-- First pull gets the album prefetch, catalog prefetch, and an empty pull
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.prefetchReqResp( catalogId ) )

	if options.mock then
		catalogSpec:expectHttpRequest( WFCatTrashTestUtils.catalogPrefetchReqResp( catalogId ) )
	end

	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.emptyPullReqResp( catalogId ) )
	rxTest:expectOnlyCompleted( puller:getUpdatesOnce() )

	local importSource = WFCatTrashTestUtils.makeImportSource( catalog, fileName, importTimestamp, sha256 )

-- Step 1: Add an image asset
	local tempTestFolder = WFTestFileUtils.createTestFolder( rxTest )

	local filePath, proxyFilePath
	if options.proxyOnlyAsset then
		proxyFilePath = WFCatTrashTestUtils.getProxyFilePath( rxTest, tempTestFolder, proxyFileName )

		rxTest:expectSingleValue( WFCatTrashTestUtils.addDocumentWithProxyOnly( catalog, catalogId, assetId, proxyFilePath, subtype, userCreated, importSource )
			:tap( function( revId )
				revisionId = revId
			end ),
			':ignore:' )

	else
		filePath = WFCatTrashTestUtils.getOriginalFilePath( rxTest, tempTestFolder, fileName )
		proxyFilePath = WFCatTrashTestUtils.getProxyFilePath( rxTest, tempTestFolder, proxyFileName )

		rxTest:expectSingleValue( WFCatTrashTestUtils.addDocumentWithLocalMasterAndProxy( catalog, catalogId, assetId, filePath, proxyFilePath, subtype, userCreated, importSource )
			:tap( function( revId )
				revisionId = revId
			end ),
		':ignore:' )
	end


	-- Send the metadata for the newly added asset
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushCreateAssetReqResp( catalogId, fileName, subtype ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates ) )

	-- these are the /rels/* links we currently expect in the received document
	local linksExpectedInDoc = { master = false, proxy = false, renditions = false }

	-- Get the metadata for the newly added asset that includes the links for uploading binaries.
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.assetUpdateResponse( assetId, revisionId, fileName, subtype, assetCreated, userCreated, importSource, linksExpectedInDoc )
	}, WFCatTrashTestUtils.stripForAssetUpdate( false ) ), 'success' )

	revisionId = WFCatTrashTestUtils.getLatestRevisionId( rxTest, catalog, assetId )

	-- push and validate for the binary upload
	local expectedOriginalUploadCount = 0
	local expectedProxyUploadCount = 0
	if options.proxyOnlyAsset then
		expectedProxyUploadCount = expectedProxyUploadCount + 1

		-- Upload the proxy (and generate renditions)
		catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createProxyReqResp( catalogId, assetId, revisionId, KSIdGenerator.uuidInLowercaseHex(), proxyFilePath ) )
		uploader:startContinuousUploads()

		-- wait for the uploader to issue the create proxy request
		rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'proxy' ))
		:expectDataWithinTime( 5 * waitMultiplier, expectedProxyUploadCount )
		:dispose()
	else
		expectedOriginalUploadCount = expectedOriginalUploadCount + 1

		-- Upload the master
		catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createMasterReqResp( catalogId, assetId, revisionId, filePath ) )
		uploader:startContinuousUploads()

		-- Wait for the uploader to issue the create master request
		rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'master' ))
		:expectDataWithinTime( 5 * waitMultiplier, expectedOriginalUploadCount )
		:dispose()
	end
	uploader:stopContinuousUploads()

	-- Wait for oz to generate the renditions before requesting next update
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollUntilHasRequiredLinks( 10 * waitMultiplier, catalogSpec, catalogId, assetId, revisionId, subtype, { proxyOnlyAsset = true } ), true )

	-- Get the updated metadata with the binary link.
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.assetUpdateResponse( assetId, revisionId, fileName, subtype, assetCreated, userCreated, importSource, { master = not options.proxyOnlyAsset, proxy = options.proxyOnlyAsset, renditions = true }, nil, true )
	}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	-- Wait for the update to get applied to the assets docValue
	local binaryRelsKey = options.proxyOnlyAsset and '/rels/proxy_type/2560' or '/rels/master'
	rxTest:observe( catalog:docStore():ongoingDocValue( assetId )
		:pluck( '_serverProvidedMetadata', 'links', binaryRelsKey, 'href' )
		:map( type ))
	:expectDataWithinTime( 5 * waitMultiplier, 'string' )
	:dispose()

-- Step 1.5: Maybe remove some of the local binaries for the asset to test different restore scenarios
	if options.dropLocalMaster then
		rxTest:expectSingleValue( catalog:docStore():applyOverlay(
			WFCatAssetTestUtils.getOverlayToRemoveLocalOriginal( assetId ) ),
			':ignore:' )
	end

	if options.dropLocalProxy then
		rxTest:expectSingleValue( catalog:docStore():applyOverlay(
			WFCatAssetTestUtils.getOverlayToRemoveLocalProxy( assetId ) ),
			':ignore:' )
	end

-- Step 2: Move the asset to trash locally and send that to Oz

	-- Delete the asset which is on Oz
	rxTest:expectOnlyCompleted( WFCatTrash.moveAssetsToTrash( catalog, { assetId }, pc ) )

	-- Make sure the original asset was deleted, and get it's new revision id
	rxTest:expectSingleValue( catalog:docStore():docValue( assetId )
	:tap( function( docValue )
		revisionId = docValue._revId
	end )
	:pluck( '_deleted' )
	, true )

	-- Make sure a deleted_image was created
	local trashAssetId, trashRevId = WFCatTrashTestUtils.getTrashAssetForDeletedAsset( rxTest, catalog, waitMultiplier, assetId )
	rxTest:expectEqual( 'string', type( trashAssetId ) )
	rxTest:expectEqual( 'string', type( trashRevId ) )

	local trashUserCreated, trashPurgeDate
	rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId )
		:tap( function( docValue )
			trashUserCreated = docValue.userCreated
			trashPurgeDate = docValue.purgeDate
		end )
	, ':ignore:' )

	-- Verify we only send up the delete, the trash asset should not be sent if the original asset was already synced up to oz
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushDeleteAssetReqResp( catalogId, assetId, revisionId, trashAssetId, trashRevId ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates ) )

	local waitForRenditions = not options.noWaitForRenditions

	-- Get the trashed asset back in the sync feed with the links to necessary binaries
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 7 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.trashAssetUpdateResponse2( trashAssetId, trashRevId, fileName, trashAssetSubtype, trashUserCreated, trashPurgeDate, userCreated, importSource, assetId, { master = not options.proxyOnlyAsset, proxy = true, renditions = waitForRenditions, xmpDevelop = options.xmpDevelop } ),
		WFCatTrashTestUtils.assetDeletedResponse( assetId, trashAssetId, userId ),
    }, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )


-- Other Client ------------------------------------------------------------

-- Step 3: On a second client, remove the asset from the trash on that second client
-- so that it's totally gone on Oz

	WFCatTrashTestUtils.simulateOtherClientDeleteTrash {
		rxTest = rxTest,
		catalog = catalog,
		catalogSpec = catalogSpec,
		trashAssetId = trashAssetId,
		trashAssetRevId = trashRevId,
	}

	rxTest:expectSingleValue( WFCatTrashTestUtils.pollUntilDeleted( 10 * waitMultiplier, catalogSpec, catalogId, trashAssetId, trashRevId, options ), true )

-- Original Client ------------------------------------------------------------

-- Step 4: Attempt to restore the asset

	-- Restore the trash asset
	rxTest:expectOnlyCompleted( WFCatTrash.restoreTrashAssets( catalog, { trashAssetId }, pc ) )

	-- Make sure the trash asset was deleted
	rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId )
		:pluck( '_deleted' ),
	true )

	local restoredAssetId, restoredRevId, restoredDocValue = WFCatTrashTestUtils.getNewlyCreatedAsset( rxTest, catalog, waitMultiplier, { assetId, trashAssetId } )
	rxTest:expectEqual( 'asset', restoredDocValue.type )
	rxTest:expectEqual( subtype, restoredDocValue.subtype )
	rxTest:expectEqual( nil, derefOpt( restoredDocValue, 'original' ) )

	-- Make sure the last trash userCreated and purgeDate data is correctly stored in restored asset createFrom field
	rxTest:expectSingleValue( catalog:docStore():docValue( restoredAssetId )
		:map( function( docValue )
			local createFromInfo = WFCatTrashUtils.createFromInfo( docValue )
			return createFromInfo.lastTrashUserCreated == trashUserCreated and createFromInfo.lastTrashPurgeDate == trashPurgeDate
		end )
	, true )

	-- Send create restored asset from original asset
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushRestoreAsset2ReqResp( catalogId, restoredAssetId, restoredRevId, trashAssetId, trashRevId, restoredDocValue.userUpdated ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates ) )

	-- Make sure the trash asset was deleted
	rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId )
		:pluck( '_deleted' ),
	true )

	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 10 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.trashAssetDeletedResponse( trashAssetId, userId ),
		WFCatTrashTestUtils.resourceNotFoundErrorUpdateResponse( "create", restoredAssetId, restoredRevId, "asset", trashAssetId, "deleted_asset", nil, userId ),
	}, WFCatTrashTestUtils.transformOrderAndStripAssetUpdate( false )), 'success' )

-- Step 5: The error handler should process the RNFE and turn the restore into a proper asset create
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushCreateAssetReqResp( catalogId, fileName, subtype ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates * 3 ) )

	if options.dropLocalMaster and not options.dropLocalProxy then
		importSource.willNotUploadMaster = true
	end

	-- pull from Oz to get the asset create response
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
			WFCatTrashTestUtils.assetUpdateResponse( restoredAssetId, restoredRevId, fileName, subtype, assetCreated, userCreated, importSource,
								{ master = false, renditions = false, xmpDevelop = false },
								nil --[[developSettings]], true --[[alwaysHaveLocationData]] )
		}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	-- validate the restored asset is on oz
	local isRestoredDocOnOz = rxTest:observe( catalog:docStore():ongoingDocValue( restoredAssetId )
		:map( function( docValue )
			local receivedUpdateFromOz = docValue._serverProvidedMetadata ~= nil

			-- stash the latest oz revisionId so we can validate the upload
			local revisionIds = derefOpt( docValue, '_serverProvidedMetadata', 'revision_ids' )
			if revisionIds then
				restoredRevId = revisionIds[ #revisionIds ]
			end

			return receivedUpdateFromOz
		end ) )
	isRestoredDocOnOz:expectDataWithinTime( 5 * waitMultiplier, true )

-- Step 6: The restored asset gets its binaries uploaded (if applicable)

	if not ( options.dropLocalMaster and options.dropLocalProxy ) then
		-- we should have some binaries so validate that they're uploaded

		-- Make sure the restored asset has the expected set of local files
		rxTest:expectSingleValue( catalog:docStore():docValue( restoredAssetId )
			:map( function( docValue )
				local hasBinary = false
				if options.proxyOnlyAsset or options.dropLocalMaster then
					local proxyPath = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )
					hasBinary = proxyPath and WFFileUtils.exists( proxyPath ) == 'file'
				else
					local originalPath = WFCatAssetUtils.getFullOriginalPathFromDocValue( docValue )
					hasBinary = originalPath and WFFileUtils.exists( originalPath ) == 'file'
				end

				return hasBinary
			end ),
		true )

		restoredRevId = WFCatTrashTestUtils.getLatestRevisionId( rxTest, catalog, restoredAssetId )

		if options.proxyOnlyAsset or options.dropLocalMaster then
			expectedProxyUploadCount = expectedProxyUploadCount + 1

			-- Upload the proxy (and generate renditions)
			catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createProxyReqResp( catalogId, restoredAssetId, restoredRevId, KSIdGenerator.uuidInLowercaseHex(), proxyFilePath ) )
			uploader:startContinuousUploads()

			-- wait for the uploader to issue the create proxy request
			rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'proxy' ))
			:expectDataWithinTime( 5 * waitMultiplier, expectedProxyUploadCount )
			:dispose()
		else
			expectedOriginalUploadCount = expectedOriginalUploadCount + 1

			-- Upload the master
			catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createMasterReqResp( catalogId, restoredAssetId, restoredRevId, filePath ) )
			uploader:startContinuousUploads()

			-- Wait for the uploader to issue the create master request
			rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'master' ))
			:expectDataWithinTime( 5 * waitMultiplier, expectedOriginalUploadCount )
			:dispose()
		end

		uploader:stopContinuousUploads()

		-- Get the updated metadata with the binary link.
		local expectMasterLink = not ( options.dropLocalMaster or options.proxyOnlyAsset )
		local expectProxyAndRenditionLinks = not options.dropLocalProxy

		rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
				WFCatTrashTestUtils.assetUpdateResponse( restoredAssetId, restoredRevId, fileName, subtype, assetCreated, userCreated, importSource,
									{ master = expectMasterLink, proxy = expectProxyAndRenditionLinks, renditions = expectProxyAndRenditionLinks },
									nil --[[developSettings]], true --[[alwaysHaveLocationData]] )
			}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	end

	-- Check that there is nothing to send
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 0, kTimeoutForSendingUpdates ) )

	-- Check to see how the ResourceNotFoundErrors were resolved
	rxTest:expectEqual( {
		ResourceNotFoundError = {
			count = 1,
			resolution = {
				RemovedTrashInfoToCreateAssetDirectly_docThatIncurredErrorWasTrashAsset = {
					count = 1,
					sourceDocIds = {
						restoredAssetId,
					},
				},
			},
		},
	}, errorHandler:DEBUG_errorsResolved() )

end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestore_OtherDelTrash_Master( rxTest )
-- NMB-9395
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { mock = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestore_OtherDelTrash_Master_testNightly( rxTest )
-- NMB-9395
	testAddSyncRestoreOtherDeleteTrashSync( rxTest )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestore_OtherDelTrash_NoMaster( rxTest )
-- NMB-9395
-- Expected result: The asset was a Lightroom style asset and will be restored
-- as a Lightroom style asset

-- TODO [kcarlson 2018-10-17]: Should a warning be displayed in this case?
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { mock = true, proxyOnlyAsset = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestore_OtherDelTrash_NoMaster_testNightly( rxTest )
-- NMB-9395
-- Expected result: The asset will be restored as a Lightroom style asset

-- TODO [kcarlson 2018-10-17]: Should a warning be displayed in this case?
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { proxyOnlyAsset = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestore_OtherDelTrash_NoLocalMaster( rxTest )
-- NMB-9395
-- Expected result: The asset had a master, but not locally and it's no longer on Oz
-- so the asset will be restored as a Lightroom style asset

-- TODO [kcarlson 2018-10-17]: Should a warning be displayed in this case?
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { mock = true, dropLocalMaster = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestore_OtherDelTrash_NoLocalMaster_testNightly( rxTest )
-- NMB-9395
-- Expected result: The asset had a master, but not locally and it's no longer on Oz
-- so the asset will be restored as a Lightroom style asset

-- TODO [kcarlson 2018-10-17]: Should a warning be displayed in this case?
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { dropLocalMaster = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestore_OtherDelTrash_NoLocalBinaries( rxTest )
-- NMB-9395
-- In this case we fail, as we only had the thumbnail.
-- The asset won't show up on other clients but would show up on Lr Web as an incomplete
-- asset.

-- I am thinking it should show up as a bad asset in the LrCC client that issued the
-- restore - showing this will likely require a change as we currently don't show an asset that doesn't
-- have a master/proxy).

-- TODO [kcarlson 2018-10-17]: Should a warning be displayed in this case?

-- expect to encounter and handle ResourceNotFoundError
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { mock = true, dropLocalMaster = true, dropLocalProxy = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestore_OtherDelTrash_NoLocalBinaries_testNightly( rxTest )
-- NMB-9395
-- In this case we fail, as we only had the thumbnail.
-- The asset won't show up on other clients but I am thinking it should show
-- up as a bad asset in the LrCC client that issued the restore - showing this
-- will likely require a change as we currently don't show an asset that doesn't
-- have a master/proxy).

-- TODO [kcarlson 2018-10-17]: Should a warning be displayed in this case?

-- expect to encounter and handle ResourceNotFoundError
	testAddSyncRestoreOtherDeleteTrashSync( rxTest, { dropLocalMaster = true, dropLocalProxy = true } )
end

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

local function testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, options )

-- NMB-14710 / NMB-13896 #8
-- This tests the two client scenario where one client attempts to restore and
-- delete an asset from the trash while another client has permanently deleted
-- that asset from the trash. In this case, the client attempting to restore
-- the asset should instead create the new trash asset from scratch.

--Steps:
--	1) Add photo.
--	2) Delete the photo.
--	3) Sync, Pause
--	4) Other Client DelTrash
--	5) Restore the photo.
--	6) Delete the photo.
--	7) Resume Sync
--
--Expected: Photo in Trash with whatever local binaries it had.

	options = options or {}

	local waitMultiplier = options.mock and 1 or kOzWaitMultiplier

	setTimeoutAndRetryLimit( rxTest, options, 15 * waitMultiplier )

	local testSession, catalog, catalogSpec, pusher, puller, uploader, pc, errorHandler = WFCatTrashTestUtils.setupCloudTrashTestSession( rxTest, options )
	assert( testSession )

	local userCreated = '2018-04-15T18:18:18Z'
	local importTimestamp = '2018-04-15T19:19:19Z'
	local assetCreated = '2018-04-15T20:20:20Z'
	local trashAssetCreated = '2018-04-15T21:21:21Z'

	local subtype = 'image'
	local fileName = "IMG_7763.JPG"
	local sha256 = "3bd8b936cc646bf1296e5ba4a76c410a27beb80809f525a8f5072f0115c54ccc"
	local proxyFileName = "IMG_7763.DNG"

	fileName = options.fileName or fileName
	subtype = options.subtype or subtype
	local trashAssetSubtype = 'deleted_' .. subtype

	local catalogId = catalog:ozCatalogId()
	local userId = catalog:ozUserId()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local revisionId

	-- First pull gets the album prefetch, catalog prefetch, and an empty pull
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.prefetchReqResp( catalogId ) )

	if options.mock then
		catalogSpec:expectHttpRequest( WFCatTrashTestUtils.catalogPrefetchReqResp( catalogId ) )
	end

	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.emptyPullReqResp( catalogId ) )
	rxTest:expectOnlyCompleted( puller:getUpdatesOnce() )

	local importSource = WFCatTrashTestUtils.makeImportSource( catalog, fileName, importTimestamp, sha256 )

--	1) Add photo.
	local tempTestFolder = WFTestFileUtils.createTestFolder( rxTest )

	local filePath, proxyFilePath
	if options.proxyOnlyAsset then
		proxyFilePath = WFCatTrashTestUtils.getProxyFilePath( rxTest, tempTestFolder, proxyFileName )

		rxTest:expectSingleValue( WFCatTrashTestUtils.addDocumentWithProxyOnly( catalog, catalogId, assetId, proxyFilePath, subtype, userCreated, importSource )
			:tap( function( revId )
				revisionId = revId
			end ),
			':ignore:' )

	else
		filePath = WFCatTrashTestUtils.getOriginalFilePath( rxTest, tempTestFolder, fileName )
		proxyFilePath = WFCatTrashTestUtils.getProxyFilePath( rxTest, tempTestFolder, proxyFileName )

		rxTest:expectSingleValue( WFCatTrashTestUtils.addDocumentWithLocalMasterAndProxy( catalog, catalogId, assetId, filePath, proxyFilePath, subtype, userCreated, importSource )
			:tap( function( revId )
				revisionId = revId
			end ),
		':ignore:' )
	end

	-- Send the metadata for the newly added asset
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushCreateAssetReqResp( catalogId, fileName, subtype ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates ) )

	-- these are the /rels/* links we currently expect in the received document
	local linksExpectedInDoc = { master = false, proxy = false, renditions = false }

	-- Get the metadata for the newly added asset that includes the links for uploading binaries.
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.assetUpdateResponse( assetId, revisionId, fileName, subtype, assetCreated, userCreated, importSource, linksExpectedInDoc )
	}, WFCatTrashTestUtils.stripForAssetUpdate( false ) ), 'success' )

	revisionId = WFCatTrashTestUtils.getLatestRevisionId( rxTest, catalog, assetId )

	-- push and validate for the binary upload
	local expectedOriginalUploadCount = 0
	local expectedProxyUploadCount = 0
	if options.proxyOnlyAsset then
		expectedProxyUploadCount = expectedProxyUploadCount + 1

		-- Upload the proxy (and generate renditions)
		catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createProxyReqResp( catalogId, assetId, revisionId, KSIdGenerator.uuidInLowercaseHex(), proxyFilePath ) )
		uploader:startContinuousUploads()

		-- wait for the uploader to issue the create proxy request
		rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'proxy' ))
		:expectDataWithinTime( 5 * waitMultiplier, expectedProxyUploadCount )
		:dispose()
	else
		expectedOriginalUploadCount = expectedOriginalUploadCount + 1

		-- Upload the master
		catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createMasterReqResp( catalogId, assetId, revisionId, filePath ) )
		uploader:startContinuousUploads()

		-- Wait for the uploader to issue the create master request
		rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'master' ))
		:expectDataWithinTime( 5 * waitMultiplier, expectedOriginalUploadCount )
		:dispose()
	end
	uploader:stopContinuousUploads()

	-- Wait for oz to generate the renditions before requesting next update
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollUntilHasRequiredLinks( 10 * waitMultiplier, catalogSpec, catalogId, assetId, revisionId, subtype, { proxyOnlyAsset = true } ), true )

	-- Get the updated metadata with the binary link.
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.assetUpdateResponse( assetId, revisionId, fileName, subtype, assetCreated, userCreated, importSource, { master = not options.proxyOnlyAsset, proxy = options.proxyOnlyAsset, renditions = true }, nil, true )
	}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	-- Wait for the update to get applied to the assets docValue
	local binaryRelsKey = options.proxyOnlyAsset and '/rels/proxy_type/2560' or '/rels/master'
	rxTest:observe( catalog:docStore():ongoingDocValue( assetId )
		:pluck( '_serverProvidedMetadata', 'links', binaryRelsKey, 'href' )
		:map( type ))
	:expectDataWithinTime( 5 * waitMultiplier, 'string' )
	:dispose()

-- Step 1.5: Maybe remove some of the local binaries for the asset to test different restore scenarios
	if options.dropLocalMaster then
		rxTest:expectSingleValue( catalog:docStore():applyOverlay(
			WFCatAssetTestUtils.getOverlayToRemoveLocalOriginal( assetId ) ),
			':ignore:' )
	end

	if options.dropLocalProxy then
		rxTest:expectSingleValue( catalog:docStore():applyOverlay(
			WFCatAssetTestUtils.getOverlayToRemoveLocalProxy( assetId ) ),
			':ignore:' )
	end

--	2) Delete the photo.

	-- Delete the asset which is on Oz
	rxTest:expectOnlyCompleted( WFCatTrash.moveAssetsToTrash( catalog, { assetId }, pc ) )

	-- Make sure the original asset was deleted, and get it's new revision id
	rxTest:expectSingleValue( catalog:docStore():docValue( assetId )
	:tap( function( docValue )
		revisionId = docValue._revId
	end )
	:pluck( '_deleted' )
	, true )

	-- Make sure a deleted_image was created
	local trashAssetId, trashRevId = WFCatTrashTestUtils.getTrashAssetForDeletedAsset( rxTest, catalog, waitMultiplier, assetId )
	rxTest:expectEqual( 'string', type( trashAssetId ) )
	rxTest:expectEqual( 'string', type( trashRevId ) )

	local trashUserCreated, trashPurgeDate
	rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId )
		:tap( function( docValue )
			trashUserCreated = docValue.userCreated
			trashPurgeDate = docValue.purgeDate
		end )
	, ':ignore:' )

	-- Verify we only send up the delete, the trash asset should not be sent if the original asset was already synced up to oz
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushDeleteAssetReqResp( catalogId, assetId, revisionId, trashAssetId, trashRevId ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates ) )

	local waitForRenditions = not options.noWaitForRenditions

	-- Get the trashed asset back in the sync feed with the links to necessary binaries
	rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 7 * waitMultiplier, catalogSpec, catalogId, puller, {
		WFCatTrashTestUtils.trashAssetUpdateResponse2( trashAssetId, trashRevId, fileName, trashAssetSubtype, trashUserCreated, trashPurgeDate, userCreated, importSource, assetId, { master = not options.proxyOnlyAsset, proxy = true, renditions = waitForRenditions, xmpDevelop = options.xmpDevelop } ),
		WFCatTrashTestUtils.assetDeletedResponse( assetId, trashAssetId, userId ),
    }, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

--	3) Sync, Pause

-- Other Client ------------------------------------------------------------

--	4) Other Client DelTrash

	WFCatTrashTestUtils.simulateOtherClientDeleteTrash {
		rxTest = rxTest,
		catalog = catalog,
		catalogSpec = catalogSpec,
		trashAssetId = trashAssetId,
		trashAssetRevId = trashRevId,
	}

	rxTest:expectSingleValue( WFCatTrashTestUtils.pollUntilDeleted( 10 * waitMultiplier, catalogSpec, catalogId, trashAssetId, trashRevId, options ), true )

-- Original Client ------------------------------------------------------------

--	5) Restore the photo.

	-- Restore the trash asset
	rxTest:expectOnlyCompleted( WFCatTrash.restoreTrashAssets( catalog, { trashAssetId }, pc ) )

	-- Make sure the trash asset was deleted
	rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId )
		:pluck( '_deleted' ),
	true )

	local restoredAssetId, restoredRevId, restoredDocValue = WFCatTrashTestUtils.getNewlyCreatedAsset( rxTest, catalog, waitMultiplier, { assetId, trashAssetId } )
	rxTest:expectEqual( 'asset', restoredDocValue.type )
	rxTest:expectEqual( subtype, restoredDocValue.subtype )
	rxTest:expectEqual( nil, derefOpt( restoredDocValue, 'original' ) )

	-- Make sure the last trash userCreated and purgeDate data is correctly stored in restored asset createFrom field
	rxTest:expectSingleValue( catalog:docStore():docValue( restoredAssetId )
		:map( function( docValue )
			local createFromInfo = WFCatTrashUtils.createFromInfo( docValue )
			return createFromInfo.lastTrashUserCreated == trashUserCreated and createFromInfo.lastTrashPurgeDate == trashPurgeDate
		end )
	, true )

--	6) Delete the photo.

	rxTest:expectOnlyCompleted( WFCatTrash.moveAssetsToTrash( catalog, { restoredAssetId }, pc ) )

	-- Make sure a deleted_image was created
	local trashAssetId2, trashRevId2 = WFCatTrashTestUtils.getTrashAssetForDeletedAsset( rxTest, catalog, waitMultiplier, restoredAssetId )
	rxTest:expectEqual( 'string', type( trashAssetId2 ) )
	rxTest:expectEqual( 'string', type( trashRevId2 ) )

--	7) Resume Sync

	-- send up the restore delete
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushRestoreDeleteAssetReqResp( catalogId, trashAssetId, trashRevId, restoredAssetId, restoredRevId, trashAssetId2, trashRevId2 ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 2, kTimeoutForSendingUpdates ) )

	-- Make sure the trash asset was deleted
	rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId )
		:pluck( '_deleted' ),
	true )

	if options.splitErrors then

		rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 10 * waitMultiplier, catalogSpec, catalogId, puller, {
			WFCatTrashTestUtils.trashAssetDeletedResponse( trashAssetId, userId ),
			WFCatTrashTestUtils.resourceNotFoundErrorUpdateResponse( "create", restoredAssetId, restoredRevId, "asset", trashAssetId, "deleted_asset", nil, userId ),
		}, WFCatTrashTestUtils.transformOrderAndStripAssetUpdate( false )), 'success' )

		-- Wait for the errors to be processed.
		rxTest:observe( WFCatTrashTestUtils.pollErrorHandlerErrorsProcessed( errorHandler, 'ResourceNotFoundError' ))
		:expectDataWithinTime( 5 * waitMultiplier, 1, false )
		:dispose()

	else

		rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 10 * waitMultiplier, catalogSpec, catalogId, puller, {
			WFCatTrashTestUtils.trashAssetDeletedResponse( trashAssetId, userId ),
			WFCatTrashTestUtils.resourceNotFoundErrorUpdateResponse( "create", restoredAssetId, restoredRevId, "asset", trashAssetId, "deleted_asset", nil, userId ),
			WFCatTrashTestUtils.resourceNotFoundErrorUpdateResponse( "delete", restoredAssetId, restoredRevId, "asset", restoredAssetId, "asset", nil, userId ),
		}, WFCatTrashTestUtils.transformOrderAndStripAssetUpdate( false )), 'success' )

		-- Wait for the errors to be processed.
		rxTest:observe( WFCatTrashTestUtils.pollErrorHandlerErrorsProcessed( errorHandler, 'ResourceNotFoundError' ))
		:expectDataWithinTime( 5 * waitMultiplier, 2, false )
		:dispose()

	end

	-- The error handler should process the RNFE and turn the restore into a regular trash asset create
	catalogSpec:expectHttpRequest( WFCatTrashTestUtils.pushCreateAssetReqResp( catalogId, fileName, trashAssetSubtype ) )
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 1, kTimeoutForSendingUpdates * 3 ) )

	if options.dropLocalMaster and not options.dropLocalProxy then
		importSource.willNotUploadMaster = true
	end

	if options.splitErrors then

		-- pull from Oz to get the trash asset create response
		rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
			WFCatTrashTestUtils.trashAssetUpdateResponse( trashAssetId2, trashRevId2, fileName, trashAssetSubtype, trashAssetCreated, trashPurgeDate, userCreated, importSource, trashAssetId, false, false, options.xmpDevelop  ),
			WFCatTrashTestUtils.resourceNotFoundErrorUpdateResponse( "delete", restoredAssetId, restoredRevId, "asset", restoredAssetId, "asset", nil, userId ),
		}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	else

		-- pull from Oz to get the trash asset create response
		rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
			WFCatTrashTestUtils.trashAssetUpdateResponse( trashAssetId2, trashRevId2, fileName, trashAssetSubtype, trashAssetCreated, trashPurgeDate, userCreated, importSource, trashAssetId, false, false, options.xmpDevelop  ),
		}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	end

	-- validate the restored asset is on oz
	rxTest:observe( catalog:docStore():ongoingDocValue( trashAssetId2 )
	:map( function( docValue )
		local receivedUpdateFromOz = docValue._serverProvidedMetadata ~= nil

		-- stash the latest oz revisionId so we can validate the upload
		local revisionIds = derefOpt( docValue, '_serverProvidedMetadata', 'revision_ids' )
		if revisionIds then
			trashRevId2 = revisionIds[ #revisionIds ]
		end

		return receivedUpdateFromOz
	end ) )
	:expectDataWithinTime( 5 * waitMultiplier, true )
	:dispose()

	-- Make sure the newly re-created trash asset gets its binaries uploaded.

	if not ( options.dropLocalMaster and options.dropLocalProxy ) then
		-- we should have some binaries so validate that they're uploaded

		-- Make sure the restored asset has the expected set of local files
		rxTest:expectSingleValue( catalog:docStore():docValue( trashAssetId2 )
			:map( function( docValue )
				local hasBinary = false
				if options.proxyOnlyAsset or options.dropLocalMaster then
					local proxyPath = WFCatAssetUtils.getFullProxyPathFromDocValue( docValue )
					hasBinary = proxyPath and WFFileUtils.exists( proxyPath ) == 'file'
				else
					local originalPath = WFCatAssetUtils.getFullOriginalPathFromDocValue( docValue )
					hasBinary = originalPath and WFFileUtils.exists( originalPath ) == 'file'
				end

				return hasBinary
			end ),
		true )

		trashRevId2 = WFCatTrashTestUtils.getLatestRevisionId( rxTest, catalog, trashAssetId2 )

		if options.proxyOnlyAsset or options.dropLocalMaster then
			expectedProxyUploadCount = expectedProxyUploadCount + 1

			-- Upload the proxy (and generate renditions)
			catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createProxyReqResp( catalogId, trashAssetId2, trashRevId2, KSIdGenerator.uuidInLowercaseHex(), proxyFilePath ) )
			uploader:startContinuousUploads()

			-- wait for the uploader to issue the create proxy request
			rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'proxy' ))
			:expectDataWithinTime( 5 * waitMultiplier, expectedProxyUploadCount )
			:dispose()
		else
			expectedOriginalUploadCount = expectedOriginalUploadCount + 1

			-- Upload the master
			catalogSpec:expectHttpRequest( WFCatTrashTestUtils.createMasterReqResp( catalogId, trashAssetId2, trashRevId2, filePath ) )
			uploader:startContinuousUploads()

			-- Wait for the uploader to issue the create master request
			rxTest:observe( WFCatTrashTestUtils.pollUploadCount( uploader, 'master' ))
			:expectDataWithinTime( 5 * waitMultiplier, expectedOriginalUploadCount )
			:dispose()
		end
		uploader:stopContinuousUploads()

		-- Get the updated metadata with the binary link.
		local expectMasterLink = not ( options.dropLocalMaster or options.proxyOnlyAsset )
		local expectProxyAndRenditionLinks = not options.dropLocalProxy
		rxTest:expectSingleValue( WFCatTrashTestUtils.pollForUpdateWith( 5 * waitMultiplier, catalogSpec, catalogId, puller, {
			WFCatTrashTestUtils.trashAssetUpdateResponse2( trashAssetId2, trashRevId2, fileName, trashAssetSubtype, trashUserCreated, trashPurgeDate, userCreated, importSource, trashAssetId, { master = expectMasterLink, proxy = expectProxyAndRenditionLinks, renditions = expectProxyAndRenditionLinks } ),
		}, WFCatTrashTestUtils.stripAssetAndLocation ), 'success' )

	end

	-- Check that there is nothing to send
	rxTest:expectOnlyCompleted( pusher:_DEBUG_sendNUpdates( 0, kTimeoutForSendingUpdates ) )

	-- Check to see how the ResourceNotFoundErrors were resolved
	rxTest:expectEqual( {
		ResourceNotFoundError = {
			count = 2,
			resolution = {
				IgnoredRevisionDoesNotMatch = {
					count = 1,
					sourceDocIds = {
						restoredAssetId,
					},
				},
				RemovedTrashInfoToCreateAssetDirectly_deleteWasSentToOzBeforeAssetExisted = {
					count = 1,
					sourceDocIds = {
						restoredAssetId,
					},
				},
			},
		},
	}, errorHandler:DEBUG_errorsResolved() )

end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestoreDelete_OtherDelTrash_Master( rxTest )
-- NMB-14710 / NMB-13896 #8
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { mock = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestoreDelete_OtherDelTrash_Master_testNightly( rxTest )
-- NMB-14710 / NMB-13896 #8
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestoreDelete_OtherDelTrash_NoMaster( rxTest )
-- NMB-14710 / NMB-13896 #8
-- Expected result: The asset was a Lightroom style asset and will be restored
-- as a Lightroom style asset

	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { mock = true, proxyOnlyAsset = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestoreDelete_OtherDelTrash_NoMaster_testNightly( rxTest )
-- NMB-14710 / NMB-13896 #8
-- Expected result: The asset will be restored as a Lightroom style asset

	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { proxyOnlyAsset = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestoreDelete_OtherDelTrash_NoLocalMaster( rxTest )
-- NMB-14710 / NMB-13896 #8
-- Expected result: The asset had a master, but not locally and it's no longer on Oz
-- so the asset will be restored as a Lightroom style asset

	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { mock = true, dropLocalMaster = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestoreDelete_OtherDelTrash_NoLocalMaster_testNightly( rxTest )
-- NMB-14710 / NMB-13896 #8
-- Expected result: The asset had a master, but not locally and it's no longer on Oz
-- so the asset will be restored as a Lightroom style asset

	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { dropLocalMaster = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestoreDelete_OtherDelTrash_NoLocalBinaries( rxTest )
-- NMB-14710 / NMB-13896 #8
-- In this case we fail, as we only had the thumbnail.
-- The asset won't show up on other clients but would show up on Lr Web as an incomplete
-- asset.

-- This should show up as a bad asset in the LrCC client that issued the restore/Delete.

-- expect to encounter and handle ResourceNotFoundError
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { mock = true, dropLocalMaster = true, dropLocalProxy = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestoreDelete_OtherDelTrash_NoLocalBinaries_testNightly( rxTest )
-- NMB-14710 / NMB-13896 #8
-- In this case we fail, as we only had the thumbnail.
-- The asset won't show up on other clients but I am thinking it should show
-- up as a bad asset in the LrCC client that issued the restore - showing this
-- will likely require a change as we currently don't show an asset that doesn't
-- have a master/proxy).

-- expect to encounter and handle ResourceNotFoundError
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { dropLocalMaster = true, dropLocalProxy = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestoreDelete_OtherDelTrash_Master( rxTest )
-- NMB-14710 / NMB-13896 #8
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { mock = true, splitErrors = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestoreDelete_OtherDelTrash_Master_testNightly( rxTest )
-- NMB-14710 / NMB-13896 #8
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { splitErrors = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_MockRestoreDelete_OtherDelTrash_splitErrors( rxTest )
-- NMB-14710 / NMB-13896 #8
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { mock = true, splitErrors = true } )
end

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

function WFCatTrashMultipleDevicesOtherDeleteTrashTest.rxTest_CT_OzRestoreDelete_OtherDelTrash_splitErrors_testNightly( rxTest )
-- NMB-14710 / NMB-13896 #8
	testAddSyncRestoreDeleteOtherDeleteTrashSync( rxTest, { splitErrors = true } )
end

--==============================================================================
-- @mark setup
--==============================================================================


function WFCatTrashMultipleDevicesOtherDeleteTrashTest.setUp( inCoveragePath )

	coveragePath = inCoveragePath

end

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

return WFRxTestCase.wrapSuite( 'WFCatTrashMultipleDevicesOtherDeleteTrashTest', WFCatTrashMultipleDevicesOtherDeleteTrashTest )
