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

PixelProviderExternalXmpDevelopDownloadTaskTest.lua

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

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

	-- If ACR is not supported, disable test before we attempt to
	-- require WFAcr. (That will fail.)
if not require 'WFPlatformInfo'.hasACR then return {} end

local Rx = require 'Rx'

	-- wf.core
local WFFunctionUtils = require 'WFFunctionUtils'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFRxTestCase = require 'WFRxTestCase'
local KSIdGenerator = require 'KSIdGenerator'

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

local PixelPathProviderScheduler = require "PixelPathProviderScheduler"
local PixelPathProviderRequestTypes = require "PixelPathProviderRequestTypes"
local PixelPathProviderStateMachine = require "PixelPathProviderStateMachine"
local PixelProviderExternalXmpDevelopPathCheckTask = require "PixelProviderExternalXmpDevelopPathCheckTask"
local PixelProviderExternalXmpDevelopDownloadTask = require "PixelProviderExternalXmpDevelopDownloadTask"

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

local PixelPathProviderRequestTypeNames = PixelPathProviderRequestTypes.names

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

local function makeSchedulerForTest( rxTest )

	local catalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local scheduler = PixelPathProviderScheduler( catalog )

	rxTest:finally( function() scheduler:close() end )

	return scheduler, catalog

end

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

local function rxTestMissingNeedsDownloadInfo( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	for _, initialState in pairs( PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates ) do
		for _, hasNeedsXmpDowloadInfo in pairs( { false, true } ) do

			needDevelopAuxFileDownloadCache:popCacheItem( localAssetId )

			if hasNeedsXmpDowloadInfo then

				-- add an entry that is missing what we need
				needDevelopAuxFileDownloadCache:pushCacheItem( localAssetId, {} )

			end

			SchedulerTestAPI.setState( 
				scheduler, pixStreamId, localAssetId, initialState )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			local expectedStateAfterMissing = 
					PixelPathProviderStateMachine.SendDataStates.SendPermanentError

			if not expectedStateAfterMissing then

				-- run a failing test
				rxTest
					:expectEqual(
						string.format( "Must provide a %s entry for initial state: %s", 
										not hasNeedsXmpDowloadInfo and
											"expectedMissingNeedsDownloadInfoStates" or
											"expectedAllRequireMissingDownloadInfoStates",
										initialState ),
						"" )

			end

			local localAssetIdRequests = 
					SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
					
			rxTest:expectEqual( #localAssetIdRequests, 1 )

			local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
					unpack( localAssetIdRequests[ 1 ] or {} )

			rxTest:expectEqual( pixStreamId, actualPixStreamId )

			rxTest:expectEqual( localAssetId, actualLocalAssetId )

			rxTest:logf( "Checking if actual state %s is same as expected: %s",
							actualState, expectedStateAfterMissing )

			rxTest:expectEqual( expectedStateAfterMissing, actualState )

		end

	end

end

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

local function makeMockWFCatalog() -- rxTest

	local applyOverlayResultStreams = {}

	local mockDocStore = {

		applyOverlay = 
			function() 

				applyOverlayResultStreams[ #applyOverlayResultStreams + 1 ] =
					Rx.Subject()

				return applyOverlayResultStreams[ #applyOverlayResultStreams ]

			end

	}

	local httpRequestResultStreams = {}

	local mockOzCatalogSpec = {

			getBinary = 
				function( _, uri )

					httpRequestResultStreams[ uri ] = Rx.Subject()

					return httpRequestResultStreams[ uri ]

				end

	}

	local mockWFCatalog = {

		ozCatalogSpec = function() return mockOzCatalogSpec end,
		docStore = function() return mockDocStore end,

	}

	return mockWFCatalog, applyOverlayResultStreams, httpRequestResultStreams

end

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

local function makeMockSaveFileFunc()-- rxTest )

	local saveFileResultStreams = {}

	local function mockSaveFileFunc( blob )

		saveFileResultStreams[ blob ] = Rx.Subject()

		return saveFileResultStreams[ blob ]

	end

	return mockSaveFileFunc, saveFileResultStreams

end

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

local function sendDataAndComplete( stream, data )

	stream:onNext( data )

	stream:onCompleted()

end

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

local function sendError( stream, maybErrStr )

	local errStr = maybErrStr or "faked error"

	stream:onError( errStr )

end

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

local function rxTestWithMissingURI( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog, applyOverlayResultStreams, httpRequestResultStreams =
		makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc, saveFileResultStreams =
			makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"makeParentFolderFunc", function() return true end )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	for _, initialState in pairs( PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates ) do

		for _, uriStatus in pairs( { "all_missing", "one_missing", "none_missing" } ) do

			for _, applyOverlayFails in pairs( { true, false } ) do

				local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

				local mask1URI = uriStatus ~= "all_missing" and "mask1URI" or nil

				local mask1AbsPath = "mask1AbsPath"

				local mask1RelPath = "mask1RelPath"

				local mask1Blob = {}

				local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

				local mask2URI = uriStatus == "none_missing" and "mask2URI" or nil

				local mask2AbsPath = "mask2AbsPath"

				local mask2RelPath = "mask2RelPath"

				local mask2Blob = {}

				local externalDevelopFiles = {
					{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
					{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
				}

				local missingDevelopAuxFiles = {
					{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
					{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
				}
					
				-- set up the caches
				needDevelopAuxFileDownloadCache
					:pushCacheItem( localAssetId, 
						{
							externalDevelopFiles = externalDevelopFiles,
							missingDevelopAuxFiles = missingDevelopAuxFiles
						} )
					
				baseRenderInfoCache	
					:pushCacheItem( localAssetId, 
						{
							externalDevelopFiles = externalDevelopFiles,
						} )

				SchedulerTestAPI.setState( 
					scheduler, pixStreamId, localAssetId, initialState )

				SchedulerTestAPI.runScheduledRequests( scheduler )

				rxTest:log( "fulfilling http" )

				if uriStatus ~= "all_missing" then
					
					sendDataAndComplete( 
						httpRequestResultStreams[ mask1URI ], mask1Blob )

				end

				if uriStatus == "none_missing" then

					sendDataAndComplete( 
						httpRequestResultStreams[ mask2URI ], mask2Blob )

				end

				SchedulerTestAPI.runScheduledRequests( scheduler )

				rxTest:log( "fulfilling save" )

				if uriStatus ~= "all_missing" then
					
					sendDataAndComplete( 
						saveFileResultStreams[ mask1Blob ], true )

				end

				if uriStatus == "none_missing" then
					
					sendDataAndComplete( 
						saveFileResultStreams[ mask2Blob ], true )

				end

				SchedulerTestAPI.runScheduledRequests( scheduler )

				rxTest:log( "applying overlay" )

				local applyOverlayResultFunc =
						not applyOverlayFails and
							sendDataAndComplete or sendError

				WFFunctionUtils.map( 
					applyOverlayResultFunc, 
						applyOverlayResultStreams, "ignored" )

				SchedulerTestAPI.runScheduledRequests( scheduler )

				local expectedState = 
						( initialState == 
							PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload and
							( uriStatus ~= "none_missing" and
								PixelPathProviderStateMachine.SendDataStates.SendNoDownloadableXmpDevelop or
								PixelPathProviderStateMachine.SendDataStates.HaveLocalXmpDevelopPath ) ) or
						( initialState == 
							PixelPathProviderStateMachine.DownloadStates.RenderNeedExternalDevelopAuxFilesDownload and
							( uriStatus ~= "none_missing" and
								PixelPathProviderStateMachine.DocstoreInfoStates.UseDefaultRenderSettingsForMissingXmpDevelopRender or
								PixelPathProviderStateMachine.LocalBinaryPathCheckStates.RenderFetchLocalExternalXmpDevelop ) ) or
						string.format( "%s %s failed overlay: %s", 
										initialState, uriStatus, applyOverlayFails )

				local localAssetIdRequests = 
						SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
						
				rxTest:expectEqual( #localAssetIdRequests, 1 )

				local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
						unpack( localAssetIdRequests[ 1 ] or {} )

				rxTest:expectEqual( pixStreamId, actualPixStreamId )

				rxTest:expectEqual( localAssetId, actualLocalAssetId )

				rxTest:logf( "Checking if actual state %s with uri status %s and applyOverlayFails %s same as expected state: %s",
								actualState, uriStatus, applyOverlayFails,
								expectedState )

				rxTest:expectEqual( expectedState, actualState )

			end

		end

	end

end

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

local function rxTestWithDownloadError( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog, applyOverlayResultStreams, httpRequestResultStreams =
		makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc, saveFileResultStreams =
			makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"makeParentFolderFunc", function() return true end )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	for _, initialState in pairs( PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates ) do

		for _, downloadStatus in pairs( { "throws", "returns nil", "early_complete", "ok" } ) do

			local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

			local mask1URI = "mask1URI"

			local mask1AbsPath = "mask1AbsPath"

			local mask1RelPath = "mask1RelPath"

			local mask1Blob = {}

			local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

			local mask2URI = "mask2URI"

			local mask2AbsPath = "mask2AbsPath"

			local mask2RelPath = "mask2RelPath"

			local mask2Blob = {}

			local externalDevelopFiles = {
				{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
				{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
			}

			local missingDevelopAuxFiles = {
				{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
				{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
			}
				
			-- set up the caches
			needDevelopAuxFileDownloadCache
				:pushCacheItem( localAssetId, 
					{
						externalDevelopFiles = externalDevelopFiles,
						missingDevelopAuxFiles = missingDevelopAuxFiles
					} )
				
			baseRenderInfoCache	
				:pushCacheItem( localAssetId, 
					{
						externalDevelopFiles = externalDevelopFiles,
					} )

			SchedulerTestAPI.setState( 
				scheduler, pixStreamId, localAssetId, initialState )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "fulfilling http" )

			if downloadStatus == "throws" then
				
				sendError( httpRequestResultStreams[ mask1URI ] )

			elseif downloadStatus == "early_complete" then

				httpRequestResultStreams[ mask1URI ]:onCompleted()

			else

				local data = downloadStatus == "ok" and mask1Blob or nil

				sendDataAndComplete( 
					httpRequestResultStreams[ mask1URI ], data )

			end

			sendDataAndComplete( 
				httpRequestResultStreams[ mask2URI ], mask2Blob )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "fulfilling save" )

			if downloadStatus == "ok" then
				
				sendDataAndComplete( 
					saveFileResultStreams[ mask1Blob ], true )

			end
				
			sendDataAndComplete( 
				saveFileResultStreams[ mask2Blob ], true )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "applying overlay" )

			WFFunctionUtils.map( 
				sendDataAndComplete, 
					applyOverlayResultStreams, "ignored" )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			local expectedState = 
					( initialState == 
						PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload and
						( downloadStatus ~= "ok" and
							PixelPathProviderStateMachine.SendDataStates.SendNoDownloadableXmpDevelop or
							PixelPathProviderStateMachine.SendDataStates.HaveLocalXmpDevelopPath ) ) or
					( initialState == 
						PixelPathProviderStateMachine.DownloadStates.RenderNeedExternalDevelopAuxFilesDownload and
						( downloadStatus ~= "ok" and
							PixelPathProviderStateMachine.DocstoreInfoStates.UseDefaultRenderSettingsForMissingXmpDevelopRender or
							PixelPathProviderStateMachine.LocalBinaryPathCheckStates.RenderFetchLocalExternalXmpDevelop ) ) or
					string.format( "%s downloadStatus %s",
									initialState, downloadStatus )

			local localAssetIdRequests = 
					SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
					
			rxTest:expectEqual( #localAssetIdRequests, 1 )

			local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
					unpack( localAssetIdRequests[ 1 ] or {} )

			rxTest:expectEqual( pixStreamId, actualPixStreamId )

			rxTest:expectEqual( localAssetId, actualLocalAssetId )

			rxTest:logf( "Checking if actual state %s with download status %s and same as expected state: %s",
							actualState, downloadStatus, 
							expectedState )

			rxTest:expectEqual( expectedState, actualState )

		end

	end

end

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

local function rxTestWithSaveFailure( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog, applyOverlayResultStreams, httpRequestResultStreams =
		makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc, saveFileResultStreams =
			makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	for _, initialState in pairs( PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates ) do

		for _, saveStatus in pairs( { "throws", "dir create fails", "ok", "early_complete" } ) do

			local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

			local mask1URI = "mask1URI"

			local mask1AbsPath = "mask1AbsPath"

			local mask1RelPath = "mask1RelPath"

			local mask1Blob = {}

			local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

			local mask2URI = "mask2URI"

			local mask2AbsPath = "mask2AbsPath"

			local mask2RelPath = "mask2RelPath"

			local mask2Blob = {}

			local externalDevelopFiles = {
				{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
				{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
			}

			local missingDevelopAuxFiles = {
				{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
				{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
			}

			SchedulerTestAPI.setTaskState( 
				scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
				"makeParentFolderFunc", 
				function( path ) 

					return path ~= mask1AbsPath or saveStatus ~= "dir create fails"

				end )

				
			-- set up the caches
			needDevelopAuxFileDownloadCache
				:pushCacheItem( localAssetId, 
					{
						externalDevelopFiles = externalDevelopFiles,
						missingDevelopAuxFiles = missingDevelopAuxFiles
					} )
				
			baseRenderInfoCache	
				:pushCacheItem( localAssetId, 
					{
						externalDevelopFiles = externalDevelopFiles,
					} )

			SchedulerTestAPI.setState( 
				scheduler, pixStreamId, localAssetId, initialState )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "fulfilling http" )

			sendDataAndComplete( 
				httpRequestResultStreams[ mask1URI ], mask1Blob )

			sendDataAndComplete( 
				httpRequestResultStreams[ mask2URI ], mask2Blob )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "fulfilling save" )

			if saveStatus == "throws" then

				sendError( saveFileResultStreams[ mask1Blob ] )

			elseif saveStatus == "ok" then

				sendDataAndComplete( 
					saveFileResultStreams[ mask1Blob ], true )

			elseif saveStatus == "early_complete" then

					saveFileResultStreams[ mask1Blob ]:onCompleted()
			end
				
			sendDataAndComplete( 
				saveFileResultStreams[ mask2Blob ], true )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "applying overlay" )

			WFFunctionUtils.map( 
				sendDataAndComplete, 
					applyOverlayResultStreams, "ignored" )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			local expectedState = 
					( initialState == 
						PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload and
						( saveStatus ~= "ok" and saveStatus ~= "early_complete" and
							PixelPathProviderStateMachine.SendDataStates.SendNoDownloadableXmpDevelop or
							PixelPathProviderStateMachine.SendDataStates.HaveLocalXmpDevelopPath ) ) or
					( initialState == 
						PixelPathProviderStateMachine.DownloadStates.RenderNeedExternalDevelopAuxFilesDownload and
						( saveStatus ~= "ok" and saveStatus ~= "early_complete" and
							PixelPathProviderStateMachine.DocstoreInfoStates.UseDefaultRenderSettingsForMissingXmpDevelopRender or
							PixelPathProviderStateMachine.LocalBinaryPathCheckStates.RenderFetchLocalExternalXmpDevelop ) ) or
					string.format( "%s downloadStatus %s",
									initialState, saveStatus )

			local localAssetIdRequests = 
					SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
					
			rxTest:expectEqual( #localAssetIdRequests, 1 )

			local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
					unpack( localAssetIdRequests[ 1 ] or {} )

			rxTest:expectEqual( pixStreamId, actualPixStreamId )

			rxTest:expectEqual( localAssetId, actualLocalAssetId )

			rxTest:logf( "Checking if actual state %s with save status %s and same as expected state: %s",
							actualState, saveStatus, 
							expectedState )

			rxTest:expectEqual( expectedState, actualState )

		end

	end

end

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

local function rxTestWithInvalidatingUpdate( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog, applyOverlayResultStreams, httpRequestResultStreams =
		makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc, saveFileResultStreams =
			makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	for _, initialState in pairs( PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates ) do

		for _, invalidationTime in pairs( { "download", "save", "overlay" } ) do

			local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

			local mask1URI = "mask1URI"

			local mask1AbsPath = "mask1AbsPath"

			local mask1RelPath = "mask1RelPath"

			local mask1Blob = {}

			local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

			local mask2URI = "mask2URI"

			local mask2AbsPath = "mask2AbsPath"

			local mask2RelPath = "mask2RelPath"

			local mask2Blob = {}

			local externalDevelopFiles = {
				{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
				{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
			}

			local missingDevelopAuxFiles = {
				{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
				{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
			}

			SchedulerTestAPI.setTaskState( 
				scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
				"makeParentFolderFunc", function() return true end )
				
			-- set up the caches
			needDevelopAuxFileDownloadCache
				:pushCacheItem( localAssetId, 
					{
						externalDevelopFiles = externalDevelopFiles,
						missingDevelopAuxFiles = missingDevelopAuxFiles
					} )
				
			baseRenderInfoCache	
				:pushCacheItem( localAssetId, 
					{
						externalDevelopFiles = externalDevelopFiles,
					} )

			SchedulerTestAPI.setState( 
				scheduler, pixStreamId, localAssetId, initialState )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			rxTest:log( "fulfilling http" )

			if invalidationTime == "download" then

				baseRenderInfoCache	
					:pushCacheItem( localAssetId, 
						{
							externalDevelopFiles = {
								{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask1URI", "otherMask1AbsPath", "otherMask1RelPath" },
								{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask2URI", "otherMask2AbsPath", "otherMask2RelPath" },
							}
						} )

			end

			sendDataAndComplete( 
				httpRequestResultStreams[ mask1URI ], mask1Blob )

			sendDataAndComplete( 
				httpRequestResultStreams[ mask2URI ], mask2Blob )

			SchedulerTestAPI.runScheduledRequests( scheduler )

			if invalidationTime ~= "download" then

				rxTest:log( "fulfilling digest" )

				if invalidationTime == "digest" then

					baseRenderInfoCache	
						:pushCacheItem( localAssetId, 
							{
								externalDevelopFiles = {
									{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask1URI", "otherMask1AbsPath", "otherMask1RelPath" },
									{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask2URI", "otherMask2AbsPath", "otherMask2RelPath" },
								}
							} )

				end

				SchedulerTestAPI.runScheduledRequests( scheduler )

				if invalidationTime ~= "digest" then

					rxTest:log( "fulfilling save" )

					if invalidationTime == "save" then

						baseRenderInfoCache	
							:pushCacheItem( localAssetId, 
								{
									externalDevelopFiles = {
										{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask1URI", "otherMask1AbsPath", "otherMask1RelPath" },
										{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask2URI", "otherMask2AbsPath", "otherMask2RelPath" },
									}
								} )

					end

					sendDataAndComplete( 
						saveFileResultStreams[ mask1Blob ], true )
						
					sendDataAndComplete( 
						saveFileResultStreams[ mask2Blob ], true )

					SchedulerTestAPI.runScheduledRequests( scheduler )

					if invalidationTime ~= "save" then

						rxTest:log( "applying overlay" )

						if invalidationTime == "overlay" then

							baseRenderInfoCache	
								:pushCacheItem( localAssetId, 
									{
										externalDevelopFiles = {
											{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask1URI", "otherMask1AbsPath", "otherMask1RelPath" },
											{ 'aux', KSIdGenerator.uuidInLowercaseHex(), "otherMask2URI", "otherMask2AbsPath", "otherMask2RelPath" },
										}
									} )

						end

						WFFunctionUtils.map( 
							sendDataAndComplete, 
								applyOverlayResultStreams, "ignored" )

						SchedulerTestAPI.runScheduledRequests( scheduler )

					end
				end

			end

			local expectedState = 
					( initialState == 
						PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload and 
							PixelPathProviderStateMachine.DocstoreInfoStates.NeedXmpDevelopInfo ) or
					( initialState == 
						PixelPathProviderStateMachine.DownloadStates.RenderNeedExternalDevelopAuxFilesDownload and 
							PixelPathProviderStateMachine.PixelCacheCheckStates.ChooseRenditionStrategy ) or
					string.format( "%s invalidationTime %s",
									initialState, invalidationTime )

			local localAssetIdRequests = 
					SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
					
			rxTest:expectEqual( #localAssetIdRequests, 1 )

			local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
					unpack( localAssetIdRequests[ 1 ] or {} )

			rxTest:expectEqual( pixStreamId, actualPixStreamId )

			rxTest:expectEqual( localAssetId, actualLocalAssetId )

			rxTest:logf( "Checking if actual state %s with invalidationTime %s and same as expected state: %s",
							actualState, invalidationTime,
							expectedState )

			rxTest:expectEqual( expectedState, actualState )

		end

	end

end

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

local function rxTestWithBackloggedDownloads( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog = makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc = makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"makeParentFolderFunc", function() return true end )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	local initialState = PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload

	for localAssetId = 1, PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.maxActiveExternalDevelopFileSyncTasks do

		local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

		local mask1URI = "mask1URI"

		local mask1AbsPath = "mask1AbsPath"

		local mask1RelPath = "mask1RelPath"

		local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

		local mask2URI = "mask2URI"

		local mask2AbsPath = "mask2AbsPath"

		local mask2RelPath = "mask2RelPath"

		local externalDevelopFiles = {
			{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
			{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
		}

		local missingDevelopAuxFiles = {
			{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
			{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
		}
			
		-- set up the caches
		needDevelopAuxFileDownloadCache
			:pushCacheItem( localAssetId, 
				{
					externalDevelopFiles = externalDevelopFiles,
					missingDevelopAuxFiles = missingDevelopAuxFiles
				} )
			
		baseRenderInfoCache	
			:pushCacheItem( localAssetId, 
				{
					externalDevelopFiles = externalDevelopFiles,
				} )

		scheduler
			:addRequest( 
				pixStreamId, localAssetId,
				PixelPathProviderRequestTypeNames.grid_visible, 1, initialState )

		SchedulerTestAPI.runScheduledRequests( scheduler )

		local expectedState = PixelPathProviderStateMachine.DownloadStates.DownloadingExternalAuxFiles

		local localAssetIdRequests = 
				SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
				
		rxTest:expectEqual( #localAssetIdRequests, 1 )

		local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
				unpack( localAssetIdRequests[ 1 ] or {} )

		rxTest:expectEqual( pixStreamId, actualPixStreamId )

		rxTest:expectEqual( localAssetId, actualLocalAssetId )

		rxTest:logf( "Checking if actual state %s for %s is same as expected state: %s",
						actualState, localAssetId, expectedState )

		rxTest:expectEqual( expectedState, actualState )

	end

	local backloggedAssetId =
			PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.maxActiveExternalDevelopFileSyncTasks + 1

	scheduler
		:addRequest( 
			pixStreamId, backloggedAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1, initialState )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	rxTest:log( "Checking that the most recent request is backlogged because the others are still busy" )

	local localAssetIdRequests = 
			SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, backloggedAssetId )
			
	rxTest:expectEqual( #localAssetIdRequests, 1 )

	local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
			unpack( localAssetIdRequests[ 1 ] or {} )

	rxTest:expectEqual( pixStreamId, actualPixStreamId )

	rxTest:expectEqual( backloggedAssetId, actualLocalAssetId )

	rxTest:logf( "Checking backlogged requests mean actual state %s for %s is same as initial state: %s",
					actualState, backloggedAssetId, initialState )

	rxTest:expectEqual( initialState, actualState )

end

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

local function rxTestJoinRunningMaskDownload( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog, _, httpRequestResultStreams =
		makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc = makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	local initialState = PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload

	local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

	local mask1URI = "mask1URI"

	local mask1AbsPath = "mask1AbsPath"

	local mask1RelPath = "mask1RelPath"

	local mask1Blob = {}

	local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

	local mask2URI = "mask2URI"

	local mask2AbsPath = "mask2AbsPath"

	local mask2RelPath = "mask2RelPath"

	local mask2Blob = {}

	local externalDevelopFiles = {
		{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
		{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
	}

	local missingDevelopAuxFiles = {
		{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
		{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
	}

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"makeParentFolderFunc", function() return true end )
		
	-- set up the caches
	needDevelopAuxFileDownloadCache
		:pushCacheItem( localAssetId, 
			{
				externalDevelopFiles = externalDevelopFiles,
				missingDevelopAuxFiles = missingDevelopAuxFiles
			} )
		
	baseRenderInfoCache	
		:pushCacheItem( localAssetId, 
			{
				externalDevelopFiles = externalDevelopFiles,
			} )

	SchedulerTestAPI.setState( 
		scheduler, pixStreamId, localAssetId, initialState )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	rxTest:log( "fulfilling http" )

	sendDataAndComplete( 
		httpRequestResultStreams[ mask1URI ], mask1Blob )

	sendDataAndComplete( 
		httpRequestResultStreams[ mask2URI ], mask2Blob )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local expectedState = PixelPathProviderStateMachine.DownloadStates.DownloadingExternalAuxFiles

	local localAssetIdRequests = 
			SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
			
	rxTest:expectEqual( #localAssetIdRequests, 1 )

	local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
			unpack( localAssetIdRequests[ 1 ] or {} )

	rxTest:expectEqual( pixStreamId, actualPixStreamId )

	rxTest:expectEqual( localAssetId, actualLocalAssetId )

	rxTest:logf( "Checking if actual state %s same as expected state: %s",
					actualState, expectedState )

	rxTest:expectEqual( expectedState, actualState )

	for _, extraRequestInitialState in pairs( PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates ) do

		rxTest:logf( "Adding another request for same localAssetId starting in state: %s", extraRequestInitialState )

		local otherPixStreamId = extraRequestInitialState

		scheduler
			:addRequest( 
				otherPixStreamId, localAssetId,
				PixelPathProviderRequestTypeNames.grid_visible, 1, extraRequestInitialState )

	end

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local allLocalAssetIdRequests = 
			SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
			
	rxTest:expectEqual( #allLocalAssetIdRequests, 3 )

	for _, request in pairs( allLocalAssetIdRequests ) do

		local streamId, locAssetId, _, _, streamState = 
				unpack( request )

		rxTest:expectEqual( localAssetId, locAssetId )

		local expectedStreamState = 
				streamId ~= PixelPathProviderStateMachine.DownloadStates.RenderNeedExternalDevelopAuxFilesDownload and
					PixelPathProviderStateMachine.DownloadStates.DownloadingExternalAuxFiles or
					PixelPathProviderStateMachine.DownloadStates.RenderDownloadingExternalAuxFiles 

		rxTest:logf( "Checking if request for pixStream %s has actual state %s same as expected state: %s",
						streamId, streamState, expectedStreamState )

		rxTest:expectEqual( expectedStreamState, streamState )

	end

end

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

local function appendT( ... )

	local appendedT = {}

	local ts = {}

	for i = 1, select( '#', ... ) do

		ts[ i ] = select( i, ... )

		assert( type( ts[ i ] ) == "table",
					string.format( "arg %s is not a table!", i ) )

	end

	local j = 0

	for _, t in ipairs( ts ) do

		for _, v in ipairs( t ) do
		
			j = j + 1

			appendedT[ j ] = v

		end

	end

	return appendedT

end

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

local function rxTestSendPathForPendingOnExternalMaskDownload( rxTest )

	local scheduler = makeSchedulerForTest( rxTest )

	local SchedulerTestAPI = scheduler:_expose_test_API()

	local pixStreamId = "pixStreamId"

	local localAssetId = 1

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local baseRenderInfoCache = 
			SchedulerTestAPI.getBaseRenderInfoCache( scheduler )

	local needDevelopAuxFileDownloadCache = 
			SchedulerTestAPI.getSharedCache( 
				scheduler, "needDevelopAuxFileDownloadCache" )

	local mockWFCatalog, applyOverlayResultStreams, httpRequestResultStreams =
		makeMockWFCatalog( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"wfCatalog", mockWFCatalog )

	local mockSaveFileFunc, saveFileResultStreams = makeMockSaveFileFunc( rxTest )

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"saveToFileFunc", mockSaveFileFunc )

	scheduler
		:addRequest( 
			pixStreamId, localAssetId,
			PixelPathProviderRequestTypeNames.grid_visible, 1 )

	SchedulerTestAPI.addRunLoopTaskToAllowlist( 
		scheduler, 
		"PixelProviderExternalXmpDevelopDownloadTask" )

	local initialState = PixelPathProviderStateMachine.DownloadStates.NeedExternalDevelopAuxFilesDownload

	local mask1Digest = KSIdGenerator.uuidInLowercaseHex()

	local mask1URI = "mask1URI"

	local mask1AbsPath = "mask1AbsPath"

	local mask1RelPath = "mask1RelPath"

	local mask1Blob = {}

	local mask2Digest = KSIdGenerator.uuidInLowercaseHex()

	local mask2URI = "mask2URI"

	local mask2AbsPath = "mask2AbsPath"

	local mask2RelPath = "mask2RelPath"

	local mask2Blob = {}

	local externalDevelopFiles = {
		{ 'aux', mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
		{ 'aux', mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
	}

	local missingDevelopAuxFiles = {
		{ mask1Digest, mask1URI, mask1AbsPath, mask1RelPath },
		{ mask2Digest, mask2URI, mask2AbsPath, mask2RelPath },
	}

	SchedulerTestAPI.setTaskState( 
		scheduler, "PixelProviderExternalXmpDevelopDownloadTask",
		"makeParentFolderFunc", function() return true end )
		
	-- set up the caches
	needDevelopAuxFileDownloadCache
		:pushCacheItem( localAssetId, 
			{
				externalDevelopFiles = externalDevelopFiles,
				missingDevelopAuxFiles = missingDevelopAuxFiles
			} )
		
	baseRenderInfoCache	
		:pushCacheItem( localAssetId, 
			{
				externalDevelopFiles = externalDevelopFiles,
			} )

	SchedulerTestAPI.setState( 
		scheduler, pixStreamId, localAssetId, initialState )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	rxTest:log( "fulfilling http" )

	sendDataAndComplete( 
		httpRequestResultStreams[ mask1URI ], mask1Blob )

	sendDataAndComplete( 
		httpRequestResultStreams[ mask2URI ], mask2Blob )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local expectedState = PixelPathProviderStateMachine.DownloadStates.DownloadingExternalAuxFiles

	local localAssetIdRequests = 
			SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
			
	rxTest:expectEqual( #localAssetIdRequests, 1 )

	local actualPixStreamId, actualLocalAssetId, _, _, actualState = 
			unpack( localAssetIdRequests[ 1 ] or {} )

	rxTest:expectEqual( pixStreamId, actualPixStreamId )

	rxTest:expectEqual( localAssetId, actualLocalAssetId )

	rxTest:logf( "Checking if actual state %s same as expected state: %s",
					actualState, expectedState )

	rxTest:expectEqual( expectedState, actualState )

	local extraRequestStates = 
			appendT(
				PixelProviderExternalXmpDevelopDownloadTask.privateUnitTestExport.needExternalDevelopAuxFileSyncStates,
				PixelProviderExternalXmpDevelopPathCheckTask.privateUnitTestExport.needCheckIfExternalAuxFilesLocalStates)

	for _, extraRequestInitialState in pairs( extraRequestStates ) do

		rxTest:logf( "Adding another request for same localAssetId starting in state: %s", extraRequestInitialState )

		local otherPixStreamId = extraRequestInitialState

		scheduler
			:addRequest( 
				otherPixStreamId, localAssetId,
				PixelPathProviderRequestTypeNames.grid_visible, 1 )

	end

	for _, extraRequestInitialState in pairs( extraRequestStates ) do

		rxTest:logf( "forcing localAssetId starting state to be: %s", extraRequestInitialState )

		local otherPixStreamId = extraRequestInitialState

		SchedulerTestAPI.setState( 
			scheduler, otherPixStreamId, localAssetId, extraRequestInitialState )

	end

	local allLocalAssetIdRequestsBefore = 
			SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
			
	rxTest:expectEqual( #allLocalAssetIdRequestsBefore, 5 )

	for _, request in pairs( allLocalAssetIdRequestsBefore ) do

		local streamId, locAssetId, _, _, streamState = 
				unpack( request )

		rxTest:expectEqual( localAssetId, locAssetId )

		local expectedStreamState = 
				streamId ~= pixStreamId and 
					streamId or 
					PixelPathProviderStateMachine.DownloadStates.DownloadingExternalAuxFiles

		rxTest:logf( "Checking if BEFORE state of request for pixStream %s has actual state %s same as expected state: %s",
						streamId, streamState, expectedStreamState )

		rxTest:expectEqual( expectedStreamState, streamState )

	end

	rxTest:log( "completing the successful save for orig request" )

	sendDataAndComplete( saveFileResultStreams[ mask1Blob ], true )

	sendDataAndComplete( saveFileResultStreams[ mask2Blob ], true )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	rxTest:log( "applying overlay" )

	WFFunctionUtils.map( 
		sendDataAndComplete, 
			applyOverlayResultStreams, "ignored" )

	SchedulerTestAPI.runScheduledRequests( scheduler )

	local allLocalAssetIdRequests = 
			SchedulerTestAPI.getAllLocalAssetIdRequests( scheduler, localAssetId )
			
	rxTest:expectEqual( #allLocalAssetIdRequests, 5 )

	for _, request in pairs( allLocalAssetIdRequests ) do

		local streamId, locAssetId, _, _, streamState = 
				unpack( request )

		rxTest:expectEqual( localAssetId, locAssetId )

		local expectedStreamState = 
				( streamId == PixelPathProviderStateMachine.DownloadStates.RenderNeedExternalDevelopAuxFilesDownload or
						streamId == PixelPathProviderStateMachine.LocalBinaryPathCheckStates.RenditionStrategyNeedCheckIfExternalDevelopAuxFilesAreLocal ) and
					PixelPathProviderStateMachine.LocalBinaryPathCheckStates.RenderFetchLocalExternalXmpDevelop or
					PixelPathProviderStateMachine.SendDataStates.HaveLocalXmpDevelopPath

		rxTest:logf( "Checking if request for pixStream %s has actual state %s same as expected state: %s",
						streamId, streamState, expectedStreamState )

		rxTest:expectEqual( expectedStreamState, streamState )

	end

end

	--[[
-- use this to debug tests
local function logRequest( request, rxTest, desc )

	local requestPlaceHolders = "%s" .. string.rep( ", %s", #request )

	rxTest:logf( "%s: { " .. requestPlaceHolders .. " } ",
					desc, unpack( request ) )

end
	scheduler
		:_mapAllRequestsWithPixStreamId( 
			pixStreamId, 
				logRequest, 
					rxTest, 
					string.format( "after runScheduledRequests with state %s", 
									initialState ) )
	--]]

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

return WFRxTestCase.wrapSuite( 'PixelProviderExternalXmpDevelopDownloadTaskTest', {

	rxTestMissingNeedsDownloadInfo = rxTestMissingNeedsDownloadInfo,

	rxTestWithMissingURI = rxTestWithMissingURI,

	rxTestWithDownloadError = rxTestWithDownloadError,
	
	rxTestWithSaveFailure = rxTestWithSaveFailure,

	rxTestWithInvalidatingUpdate = rxTestWithInvalidatingUpdate,

	rxTestWithBackloggedDownloads = rxTestWithBackloggedDownloads,

	rxTestJoinRunningMaskDownload = rxTestJoinRunningMaskDownload,

	rxTestSendPathForPendingOnExternalMaskDownload = 
		rxTestSendPathForPendingOnExternalMaskDownload,

} )
