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

WFCatIdleDownloaderTest.lua

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

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

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

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

	-- RxLua
local Rx = require 'Rx'
local Observable = Rx.Observable
local Subject = Rx.Subject
local WFRxScheduler = require 'WFRxScheduler'


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

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

	-- WF.core.utils
local KSPathUtils = require 'KSPathUtils'
local WFLogger = require 'WFLogger'
local KSDate = require 'KSDate'
local WFFileUtils = require 'WFFileUtils'
local KSIdGenerator = require 'KSIdGenerator'
local WFOzTestUtils = require 'WFOzTestUtils'
local KSTableUtils = require 'KSTableUtils'

	-- WF.oz_client.managed_catalog
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFCatIdleDownloader = require 'WFCatIdleDownloader'
local WFCatSyncStatus = require 'WFCatSyncStatus'
local WFCatVersions = require 'WFCatVersions'

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

local WFCatIdleDownloaderTest = {}

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

local child = KSPathUtils.child

local derefOpt = assert( KSTableUtils.derefOpt )

local testDataPath = child( KSPathUtils.getStandardFilePath( 'testdata' ), 'wffileutils' )

local logger = WFLogger 'WFCatIdleDownloaderTest'

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

local counter = 1

local originalPath = child( testDataPath, 'original.txt' )
local originalRelativePath = WFFileUtils.removeVolumeFromPath( originalPath )
local originalVolumeGuid = WFFileUtils.getVolumeGuidForPath( originalPath )

local proxyPath = child( testDataPath, 'proxy.txt' )
local proxyRelativePath = WFFileUtils.removeVolumeFromPath( proxyPath )
local proxyVolumeGuid = WFFileUtils.getVolumeGuidForPath( proxyPath )

local xmpDevelopPath = child( testDataPath, 'xmpDevelop.txt' )

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

local kRunWithSubtypes = { 'image', 'deleted_image', 'video', 'deleted_video' }

if WFPlatformInfo.isAndroid then
	-- Android doesn't support video.
	kRunWithSubtypes = { 'image', 'deleted_image' }
end

local function isVideoSubtype( runWithSubtype )
	return runWithSubtype == 'video' or runWithSubtype == 'deleted_video'
end


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

local function modifyIdleDownloadLevers( docValue, hasMasterLink, hasProxyLink, hasLocalMaster, hasLocalProxy, 
						isBlocked, isImportant, isSubtype, isMarkedForOffline, waitingForProxy, waitExpired,
						corruptMaser, noRenditionsOnOz, hasExternalXmpLink )
				
	local localOnly = {
			files = {
				original = {},
				proxy = {}
			},
			deniedBy = {}
		}

	local smp = {}

	if isMarkedForOffline then
		localOnly.isMarkedForOfflineUse = true
	end

	if waitingForProxy and hasProxyLink then
		
		local startingTime = KSDate.timeInIso8601Format()
		
		if waitExpired then
			startingTime = KSDate.shiftIso8601DateTime( startingTime, -100000 )
		end
		
		smp.startedWaitingForProxyTimestamp = startingTime

	end
	
	if hasLocalMaster then
		localOnly.files.original.master = {
			relativePath = originalRelativePath,
			volumeGuid = originalVolumeGuid
		}
	else
		localOnly.files.original = { _delete = true }
	end
	
	local isVideo = isSubtype == 'video' or isSubtype == 'deleted_video'
	if hasLocalProxy then
		if isVideo then
			localOnly.files.proxy[ '720p' ] = {
				relativePath = proxyRelativePath,
				volumeGuid = proxyVolumeGuid
			}
		else
			localOnly.files.proxy[ '2560' ] = {
				relativePath = proxyRelativePath,
				volumeGuid = proxyVolumeGuid
			}
		end
	else
		localOnly.files.proxy = { _delete = true }
	end
	
	local links = {} 
	
	local importSource = {
		originalWidth = 640, -- avoid generating error in WFCatSearchByAssetType.lua bad argument max
		originalHeight = 480,
		sha256 = KSIdGenerator.uuidInLowercaseHex()
	}
	
	if hasMasterLink then
		links[ '/rels/master' ] = { href = '/master/href/bogus/testing' }

		if corruptMaser then
			KSTableUtils.setNested( importSource, true, 'status', 'error', 'all', 'reason', 'sha256' )
		end

	end
	
	if hasProxyLink then

		if not waitingForProxy or waitExpired then

			if isVideo and not noRenditionsOnOz then
				links[ '/rels/rendition_type/720p' ] = { href = '/proxy/href/bogus/testing' } 
			elseif not isVideo then
				links[ '/rels/proxy_type/2560' ] = { href = '/proxy/href/bogus/testing' } 
			end

		end
		
	end

	if hasExternalXmpLink then

		links[ '/rels/xmp/develop' ] = { href = '/xmp_develop/href/bogus/testing' }

	end

	if not noRenditionsOnOz then
		links[ '/rels/rendition_type/thumbnail2x' ] = { href = '/proxy/href/bogus/testing' }
		links[ '/rels/rendition_type/640' ] = { href = '/rendition/hello/testing' }
	end

	if isBlocked then
		localOnly.deniedBy[ 'WFCatIdleDownloader' ] = true
	end

	local picked = {
		[ 'foo' ] = {
			flag = 'pick'
		},
	}
	
	smp.links = links
	
	docValue.importSource = importSource
	docValue._localOnly = localOnly
	docValue.subtype = isSubtype
	docValue._serverProvidedMetadata = smp
	docValue.reviews = isImportant and picked or {}
	docValue._id = string.format( '%032x', counter )
	
	docValue.develop = {
		processingModel = "lightroom",
		xmpCameraRaw = { sha256 = '0054ef228b1eaf3322c8caa31df6123e5851bfb3c851f81e0a09c270d51877dc' }
	}
	
	counter = counter + 1
	
	return docValue

end

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

local function addMixedAssets( rxTest, catalog, wfCatIdleDownloader, isForSubtype, waitingForProxy, skipBlocked, includeVersions )

	local docStore = catalog:docStore()

	local addAssetFn = WFOzTestUtils.v2.makeAdderOfAsset( rxTest, docStore, modifyIdleDownloadLevers )

	local proxyOverlays = {}

	-- TODO [jandrew 2020-03-11]: This code is almost inscrutable. 
	-- This test suite needs to be rewritten.
	
	-- The following code creates 13 asset documents.
	-- Each document has a unique permutation of settings that changes
	-- the download logic inside of the idle downloader.

	-- If includeVersions is true, 2 version documents are also created.
	
	local assetLocalIdsWithVersions = { 4, 5 }

	for i = 1, 13 do
	
		-- Assets 1-4, 7-8, 11-13 have masters on Oz
		-- Assets 2-6, 9-12 have proxies on Oz

		local hasMasterLink = i <= 4 or ( i > 6 and i <= 8 ) or i > 10
		local hasProxyLink = ( i > 2 and i <= 6 ) or i > 8 and i ~= 13
		
		-- Asset 3 has external xmp settings and a version.
		local hasExternalXmpLink = includeVersions and ( i == 4 or i == 5 )
		
		-- Local proxy/master
		
		local hasLocalMaster = i == 2 or i == 10
		local hasLocalProxy = i == 5
		
		-- Blocking from sync
		
		local isBlocked = false
		
		if not skipBlocked then
			isBlocked = i == 3
		end
		
		-- Importance. Shouldn't have an affect on what's downoaded: only download order.
		
		local isImportant = i % 2 == 0 or i == 1
		
		-- Offline Use.
		
		local isMarkedForOffline = i == 4
		
		-- Expired Wait for Proxy
		
		local waitExpired = i == 11
		
		-- Corrupt master on Oz
		
		local corruptMaser = i == 13
		
		-- No renditions on Oz
		
		local noRenditionsOnOz = i == 12
			-- Asset 12 has no renditions on Oz. For video files, this mean there's
			-- no 720p rendition( proxy ), so we expect an original to be downloaded.
			-- For images, the proxy should be downloaded.
		
		-- Proxies that may need download ( mnd = no master, no proxy, oz has proxy ): 3, 4, 6, 9
		-- Proxies that need download in managed ( mnd, not blocked, not marked for offline ): 6, 9, 11, 12
		-- Proxies that need download in keep-all-originals ( mnd, not blocked, oz has no original, not marked for offline ): 6, 9
		
		-- Originals that may need download ( mnd = no original, oz has original ): 1, 3, 4, 7, 8
		-- Originals that need download in managed ( mnd, not blocked, no proxy, oz has no proxy, maybe marked for offline ): 1, 4, 7, 8
		-- Originals that need download in keep-all-originals mode ( mnd, not blocked ): 1, 4, 7, 8, 11, 12
		
		local id = addAssetFn(
				hasMasterLink, 
				hasProxyLink, 
				hasLocalMaster, 
				hasLocalProxy, 
				isBlocked,
				isImportant,
				isForSubtype,
				isMarkedForOffline,
				waitingForProxy,
				waitExpired,
				corruptMaser,
				noRenditionsOnOz,
				hasExternalXmpLink )
					
		if waitingForProxy and hasProxyLink and not waitExpired then
		
			local overlay = {
				_id = id,
				_serverProvidedMetadata = {}
			}
		
			local links = {}

			local isForVideo = isForSubtype == 'video' or isForSubtype == 'deleted_video'
			if isForVideo and not noRenditionsOnOz then
				links[ '/rels/rendition_type/720p' ] = { href = '/proxy/href/bogus/testing' } 
			elseif not isForVideo then
				links[ '/rels/proxy_type/2560' ] = { href = '/proxy/href/bogus/testing' } 
			end
	
			overlay._serverProvidedMetadata.links = links
			
			table.insert( proxyOverlays, overlay )
			
		end
				
		if wfCatIdleDownloader and ( isBlocked ) then
			rxTest:expectSingleValue( docStore:docValue( id )
				:flatMapLatest( function( docValue )
					return wfCatIdleDownloader._failedDownloadDeniedListHelper:addToDeniedList( docValue._localId )
				end ),
				":ignore:" )
		end
		
	end
	
	if includeVersions then
	
		local versionOverlays = {}
		
		for _, localId in ipairs( assetLocalIdsWithVersions ) do
			
			-- Create the Version Document

			local versionId
			
			rxTest:waitFor( WFCatVersions.createVersionForAsset( catalog, localId, true, "foo" )
				:map( function( createdVersionId )
					versionId = createdVersionId
					return true
				end ) )
		
			-- Add an XMP download link
			
			local overlay = {
				_id = versionId,
				_serverProvidedMetadata = {}
			}
		
			local links = {}
			links[ '/rels/xmp/develop' ] = { href = '/xmp_develop/href/bogus/testing' }

			overlay._serverProvidedMetadata.links = links
			
			table.insert( versionOverlays, overlay )
		
		end
		
		rxTest:expectSingleValue( docStore:bulkApplyOverlay( versionOverlays ), ':ignore:' )
	
	end
	
	local addProxiesForWaitingAssetsFn = function()
		
		rxTest:expectSingleValue( docStore:bulkApplyOverlay( proxyOverlays ), ':ignore:' )

	end
	
	return addProxiesForWaitingAssetsFn

end

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

local downloadStream = Subject( 1 )

local ids
local subscriptions

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

local function disposeOfDownloadSubscriptions()

	if subscriptions then
	
		for key, disposable in pairs( subscriptions ) do
		
			disposable:dispose()
			subscriptions[ key ] = nil
		
		end

	end

	subscriptions = {}

end

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

local fileSize = 100

local function createDownloader( rxTest, docStore, downloadCallback, reportRemainingSpace, slowDownload )

	ids = {}
	
	disposeOfDownloadSubscriptions()
	
	return function( localId, binaryType )

		local key = localId .. ':' .. binaryType

		if ids[ key ] then
			logger:warnf( "Already have downloaded %s for %d", key, ids[ key ] )
			rxTest:expectEqual( ids[ key ], nil )
		end

		ids[ key ] = localId

		local delay = slowDownload and 0.5 or 0.001

		logger:infof( "Downloading %s for %d", binaryType, localId )

		subscriptions[ key ] = Observable.timer( delay, WFRxScheduler.sharedScheduler() )
		
			:take( 1 )
		
			:flatMapLatest( function()

				local localOnly = {
					files = {
						original = {},
						proxy = {}
					}
				}

				if binaryType == 'original' then
					localOnly.files.original.master = {
					
						relativePath = originalRelativePath,
						volumeGuid = originalVolumeGuid,
						size = fileSize

					}
				end
				
				if binaryType == 'proxy' then
					localOnly.files.proxy[ '2560' ] = {
					
						relativePath = proxyRelativePath,
						volumeGuid = proxyVolumeGuid,
						size = fileSize
						
					}
					
					localOnly.files.proxy[ '720p' ] = {
					
						relativePath = proxyRelativePath,
						volumeGuid = proxyVolumeGuid,
						size = fileSize
						
					}
				end
		
				if binaryType == 'xmp_develop' then
					localOnly.files.xmp_develop = {
					
						path = xmpDevelopPath,
						sha256 = KSIdGenerator.uuidInLowercaseHex(),
						size = fileSize

					}
				end
				 
		
				downloadCallback()
		
				return docStore:applyOverlay {
					_id = localId,
					_localOnly = localOnly,
				}
				:tap( function()
				
					logger:infof( "DONE downloading %s for %d", binaryType, localId )
				
				end )

			end )
			
			:subscribe( function()
			
				if reportRemainingSpace then
					downloadStream:onNext( true, localId, true, binaryType, nil, fileSize )
				else
					downloadStream:onNext( true, localId, true, binaryType )
				end
				
				subscriptions[ key ] = nil
				
			end )

	end

end

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

local function createBadDownloader( downloadCallback )

	return function( localId, binaryType )

		local delay = 0.1

		local disposable 
	
		local disposeFn = function()
			
			disposable:dispose()
			disposable = nil
			
		end
		
		disposable = Observable.timer( delay, WFRxScheduler.sharedScheduler() )
			
				:take( 1 )
			
				:flatMapLatest( function()
				
					return Observable.just( true )
					
				end )
				
				:subscribe( function()
				
					downloadStream:onNext( true, localId, false, binaryType )
				
				end,
				disposeFn, 
				disposeFn )

	end

end

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

function WFCatIdleDownloaderTest.rxTestWhatToDownloadBasic( rxTest )

	-- XMP Develop Settings should be downloaded first.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		true, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'xmp_develop' )


	-- Proxy should be downloaded second.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )
	
	-- If we can't download the proxy because the drive is offline, we're done.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		true, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), nil )

	-- If we can't download a proxy because it's not on Oz,
	-- download the original...
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- hasLocalOriginal,
		false, -- needsProxyDownload, 
		false, -- hasLocalProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'original' )
	
	-- ...unless the original volume is offline. Then we're done.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- hasLocalOriginal,
		false, -- needsProxyDownload, 
		false, -- hasLocalProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		true, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), nil )	

	-- After we have a proxy, we're done.

	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		false, -- needsProxyDownload, 
		true, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), nil )
	
	-- Import case: have local original, but no proxy.

	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		false, -- keepAllProxies
		false, -- needsOriginalDownload, 
		true, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )

end

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

function WFCatIdleDownloaderTest.rxTestWhatToDownloadKeepAllOriginals( rxTest )

	-- XMP Develop Settings should be downloaded first.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		true, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		true, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'xmp_develop' )


	-- Original should be downloaded second...
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		true, -- keepAllOriginals
		false, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'original' )

	-- ...Unless it's not on Oz...
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		true, -- keepAllOriginals
		false, -- keepAllProxies
		false, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )
	
	-- ...OR the original volume is offline.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		true, -- keepAllOriginals
		false, -- keepAllProxies
		false, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )
	
	-- But if we do download the original, we should download the
	-- proxy next...
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		true, -- keepAllOriginals
		false, -- keepAllProxies
		false, -- needsOriginalDownload, 
		true, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )
	
	-- Once we have the original and proxy, we're done.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		true, -- keepAllOriginals
		false, -- keepAllProxies
		false, -- needsOriginalDownload, 
		true, -- haveLocalPathForOriginal,
		false, -- needsProxyDownload, 
		true, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), nil )

end

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

function WFCatIdleDownloaderTest.rxTestWhatToDownloadKeepAllProxies( rxTest )

	-- XMP Develop Settings should be downloaded first.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		true, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		true, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'xmp_develop' )


	-- Proxy should be downloaded second...
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		true, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )

	-- ...Unless it's not on Oz...
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		true, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		false, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'original' )
	
	-- ... if the proxy olume isn't online, download nothing.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		true, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		true, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), nil )
	
	-- Even if we have the original, download the proxy.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		true, -- keepAllProxies
		false, -- needsOriginalDownload, 
		true, -- haveLocalPathForOriginal,
		true, -- needsProxyDownload, 
		false, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), 'proxy' )
	
	-- Once we have the proxy, we're done.
	
	rxTest:expectEqual( WFCatSyncStatus.whatToDownload( 
		false, -- keepAllOriginals
		true, -- keepAllProxies
		true, -- needsOriginalDownload, 
		false, -- haveLocalPathForOriginal,
		false, -- needsProxyDownload, 
		true, -- haveLocalPathForProxy, 
		false, -- needsDevelopXmpDownload,
		false, -- isMarkedForOffline,
		false, -- originalVolumeOfflineOrFull,
		false, -- proxyVolumeOfflineOrFull,
		true -- sufficientRenditionFoundOnOz 
	), nil )

end

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

local function setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs, maybeDownloader )

	optArgs = optArgs or {}

	rxTest:setTimeLimit( optArgs.timeLimit or 30 )
	
	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	local downloader = maybeDownloader
	
	if not downloader then
	
		downloader = {}
	
		local downloadCount = 0
		
		local revDownloadCount = function()
			downloadCount = downloadCount + 1
		end
		
		local reportRemainingSpace = optArgs.reportRemainingSpace
		
		downloader.func = createDownloader( rxTest, wfCatalog:docStore(), revDownloadCount, reportRemainingSpace, optArgs.slowDownload )
		
		downloader.resetCount = function()
		
			downloadCount = 0
		
		end
		
		downloader.getCount = function()
			return downloadCount
		end
		
	end
	
	downloader.cancelFunc = function( binaryType, localIds ) 
		
		for _, localId in ipairs( localIds ) do
		
			local key = localId .. ':' .. binaryType
			
			local maybeSubscription = subscriptions[ key ]
			subscriptions[ key ] = nil
			
			if maybeSubscription then
				maybeSubscription:dispose()
				maybeSubscription = nil
			end		
		
		end
	
	end
	
	keepAllOriginals = not not keepAllOriginals
	keepAllProxies = not not keepAllProxies
	
	optArgs.debugQueryLimit = 1
	
	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, downloader.func, downloadStream, downloader.cancelFunc, keepAllOriginals, keepAllProxies, optArgs )

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

	return wfCatalog, wfCatIdleDownloader, downloader

end

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

function WFCatIdleDownloaderTest.rxTestProxyDelay_testNightly( rxTest )
	
	rxTest:setRetryLimit( 3 )
	
	rxTest:setTimeLimit( 30 )
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	downloader.resetCount()

	local addProxiesForWaitingAssetsFn = addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image', true )

	wfCatIdleDownloader:start()

	-- We should first download the assets that are required
	
	dls:expectData( true, 4, true, 'original' )
	
	dls:expectData( true, 12, true, 'original' )
	
	-- Then the assets without that have no proxies and are no waiting for proxies.
	
	dls:expectData( true, 1, true, 'original' )
	
	dls:expectData( true, 8, true, 'original' )
		
	dls:expectData( true, 7, true, 'original' )
	
	dls:expectData( true, 11, true, 'proxy' )
		-- This proxy should download right away since the delay timestamp is
		-- already expired.
		
	rxTest:expectEqual( 6, downloader.getCount() )
		
	wfCatIdleDownloader:stop()

	if addProxiesForWaitingAssetsFn then
		addProxiesForWaitingAssetsFn() -- Add in proxies.
	end
				
	wfCatIdleDownloader:start()
		
	-- Afterwhich, proxy downloads should process normally:
	
	dls:expectData( true, 4, true, 'proxy' )
		
	dls:expectData( true, 6, true, 'proxy' )
	
	dls:expectData( true, 9, true, 'proxy' )
		
	dls:expectData( true, 12, true, 'proxy' )
		
	dls:expectData( true, 10, true, 'proxy' )

	rxTest:expectEqual( 11, downloader.getCount() )

	wfCatIdleDownloader:stop()

end

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

function WFCatIdleDownloaderTest.rxTestRemainingSpace_testNightly( rxTest )
	
	local optArgs = {
		reportRemainingSpace = true,
		timeLimit = 60,
		downloadBlackoutWindowInSeconds = 0.1
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {
			[ volumeGuid ] = fileSize,
		}
	} )
	
	-- There's a limited amount of free space left, so the downloader should eventually
	-- run out of space and stop downloading without an outOfSpace trigger
	-- via reportStatusOfVolumes.
	
	downloader.resetCount()

	addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image' )

	wfCatIdleDownloader:start()

	rxTest:sleep( 3 )
		
	rxTest:expectEqual( downloader.getCount() < 10, true )

	wfCatIdleDownloader:stop()

end

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

function WFCatIdleDownloaderTest.rxTestAbandonDownloads( rxTest )

	local optArgs = {
		slowDownload = true
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	downloader.resetCount()

	addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image' )

	wfCatIdleDownloader:start()

	rxTest:sleep( 0.1 )
	
	wfCatIdleDownloader:stop()

	rxTest:sleep( 1 )
	
	rxTest:expectEqual( 0, downloader.getCount() )
	
end

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

function WFCatIdleDownloaderTest.rxTestAbandonDownloads_OutOfSpace( rxTest )

	local optArgs = {
		slowDownload = true
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	downloader.resetCount()

	addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image' )

	wfCatIdleDownloader:start()

	rxTest:sleep( 0.1 )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )

	rxTest:sleep( 1 )
	
	rxTest:expectEqual( 0, downloader.getCount() )
	
end

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

function WFCatIdleDownloaderTest.rxTestAbandonDownloads_Offline( rxTest )

	local optArgs = {
		slowDownload = true
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	downloader.resetCount()

	addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image' )

	wfCatIdleDownloader:start()

	rxTest:sleep( 0.1 )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	rxTest:sleep( 1 )
	
	rxTest:expectEqual( 0, downloader.getCount() )
	
end

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

function WFCatIdleDownloaderTest.rxTestAbandonDownloads_OverIdleSpaceThreshold( rxTest )

	local optArgs = {
		slowDownload = true
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	downloader.resetCount()

	addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image' )

	local dls = rxTest:observe( downloadStream )

	wfCatIdleDownloader:start()

	rxTest:sleep( 0.1 )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	dls:expectData( true, 4, true, 'original' ) 
	dls:expectData( true, 4, true, 'proxy' ) 
	dls:expectData( true, 12, true, 'proxy' )

	rxTest:expectEqual( 3, downloader.getCount() )
	
end

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

function WFCatIdleDownloaderTest.rxTestManaged( rxTest )

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local syncDiagnosticsObserver = rxTest:observe( wfCatIdleDownloader:syncDiagnostics( 0.1 )
		:map( function( diagnostics )
			return diagnostics
		end ) )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype, nil, nil, true )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 15

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )

		local runWithVideos = isVideoSubtype( runWithSubtype )
		
		if runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.
	
		dls:expectData( true, 5 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithSubtype == 'image' then
		
			-- The the external XMP from the version documents whose associated
			-- assets are marked for offline use.
			
			dls:expectData( true, 14 + localIdOffset, true, 'xmp_develop' )
		
			rxTest:expectEqual( 13, downloader.getCount() )
		
		else
		
			rxTest:expectEqual( 12, downloader.getCount() )
		
		end
		
		wfCatIdleDownloader:stop()
		
	end
	
	if WFPlatformInfo.isAndroid then
	
		-- Android doesn't support video, so counts are different.
	
		syncDiagnosticsObserver:expectDataWithinTime( 5,
		{
			downloadsByType = {
				original = 8,
				proxy = 12,
				xmp_develop = 5,
			},
			isCurrentlySyncing = false,
			numberOfRequiredBinariesRemainingToDownload = 0,
			numberOfScheduledDownloads = 0,
			recentAndScheduledDownloads = {
				"6::proxy",
				"4::proxy",
				"7::original",
				"9::proxy",
				"25::proxy",
				"26::proxy",
				"20::xmp_develop",
				"19::xmp_develop",
				"8::original",
				"12::proxy",
				"24::proxy",
				"4::xmp_develop",
				"1::original",
				"14::xmp_develop",
				"21::proxy",
				"4::original",
				"27::proxy",
				"5::xmp_develop",
				"19::original",
				"11::proxy",
				"10::proxy",
				"16::original",
				"19::proxy",
				"22::original",
				"23::original",
			},
			scheduledDownloads = {},
			summaryStr = "Downloaded 8 originals, 12 proxies, 5 xmp develop settings from Oz.",
		} )
	
	else
	
		syncDiagnosticsObserver:expectDataWithinTime( 5,
		{
			downloadsByType = {
				original = 18,
				proxy = 22,
				xmp_develop = 9,
			},
			isCurrentlySyncing = false,
			numberOfRequiredBinariesRemainingToDownload = 0,
			numberOfScheduledDownloads = 0,
			recentAndScheduledDownloads = {
				"6::proxy",
				"4::proxy",
				"7::original",
				"8::original",
				"35::xmp_develop",
				"31::original",
				"19::xmp_develop",
				"25::proxy",
				"39::proxy",
				"49::proxy",
				"19::proxy",
				"51::proxy",
				"27::proxy",
				"5::xmp_develop",
				"19::original",
				"11::proxy",
				"21::proxy",
				"53::original",
				"23::original",
				"55::proxy",
				"56::proxy",
				"54::proxy",
				"50::xmp_develop",
				"52::original",
				"9::proxy",
				"57::original",
				"49::original",
				"34::xmp_develop",
				"49::xmp_develop",
				"40::proxy",
				"41::proxy",
				"37::original",
				"38::original",
				"12::proxy",
				"24::proxy",
				"36::proxy",
				"1::original",
				"14::xmp_develop",
				"34::proxy",
				"4::original",
				"26::proxy",
				"20::xmp_develop",
				"46::original",
				"16::original",
				"10::proxy",
				"42::original",
				"34::original",
				"22::original",
				"4::xmp_develop",
			},
			scheduledDownloads = {},
			summaryStr = "Downloaded 18 originals, 22 proxies, 9 xmp develop settings from Oz.",
		} )
		
	end
	
	syncDiagnosticsObserver:dispose()
	
end

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

local function expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		rxTest:sleep( 0.1 )

		rxTest:expectEqual( 0, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end
	
end

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

function WFCatIdleDownloaderTest.rxTestManaged_NoDiskSpace( rxTest )

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_OverIdleSpaceThreshold( rxTest )

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	-- We should only download "required" assets.
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		rxTest:expectEqual( 3, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_Offline( rxTest )

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		rxTest:expectEqual( 10, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end

		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_NoDiskSpace_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}

	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )

		-- Then the standard priority downloads.
		
		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		
		rxTest:expectEqual( 5, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_NoDiskSpace_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {},
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_NoDiskSpace_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_Offline_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		
		rxTest:expectEqual( 5, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_Offline_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_Offline_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_OverIdleSpaceThreshold_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Marked for Offline Use
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		
		rxTest:expectEqual( 6, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_OverIdleSpaceThreshold_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		rxTest:expectEqual( runWithVideos and 1 or 2, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestManaged_OverIdleSpaceThreshold_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, nil, nil, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		rxTest:expectEqual( runWithVideos and 1 or 2, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do

		downloader.resetCount()
		
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype, nil, nil, true )
		
		wfCatIdleDownloader:start()
		
		local localIdOffset = ( i - 1 ) * 15
		
		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 5 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		-- Then the proxies when we already have the originals
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' ) 
		
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
		
		if runWithSubtype == 'image' then
		
			-- The the external XMP from the version documents whose associated
			-- assets are marked for offline use.
			
			dls:expectData( true, 15 + localIdOffset, true, 'xmp_develop' )
			
			dls:expectData( true, 14 + localIdOffset, true, 'xmp_develop' )
		
			rxTest:expectEqual( runWithVideos and 15 or 16, downloader.getCount() )
		
		else
		
			rxTest:expectEqual( runWithVideos and 13 or 14, downloader.getCount() )
		
		end

		wfCatIdleDownloader:stop()

	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_NoDiskSpace( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_OverIdleSpaceThreshold( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	-- We should only download "required" assets.
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' ) -- no master on Oz
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' ) -- no master on Oz
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		rxTest:expectEqual( 9, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_Offline( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		
		-- Then downloads the important assets

		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		-- Then the proxies when we already have the originals
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' ) 
		
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
		
		rxTest:expectEqual( runWithVideos and 11 or 12, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end

		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
	
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_NoDiskSpace_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 

		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		rxTest:expectEqual( 6, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_NoDiskSpace_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {},
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_NoDiskSpace_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_Offline_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 

		-- Then downloads the important assets

		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		rxTest:expectEqual( 6, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_Offline_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_Offline_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_OverIdleSpaceThreshold_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' ) -- no master on Oz
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' ) -- no master on Oz
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		rxTest:expectEqual( 9, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_OverIdleSpaceThreshold_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Then the proxies when we already have the originals
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- Downloaded because there's no suitable rendiition on Oz.
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end

		-- Then downloads the important assets
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' ) -- no master on Oz	

		-- Then the standard downloads
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' ) -- no master on Oz
		
		rxTest:expectEqual( runWithVideos and 3 or 4, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_OverIdleSpaceThreshold_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Then the proxies when we already have the originals
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- Downloaded because there's no suitable rendiition on Oz.
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end

		-- Then downloads the important assets
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' ) -- no master on Oz	
		
		-- Then the standard downloads
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' ) -- no master on Oz
		
		rxTest:expectEqual( runWithVideos and 3 or 4, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies( rxTest )

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do

		downloader.resetCount()
		
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype, nil, nil, true )
		
		wfCatIdleDownloader:start()
		
		local localIdOffset = ( i - 1 ) * 15

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 5 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithSubtype == 'image' then
		
			-- The the external XMP from the version documents whose associated
			-- assets are marked for offline use.
			
			dls:expectData( true, 15 + localIdOffset, true, 'xmp_develop' )
			
			dls:expectData( true, 14 + localIdOffset, true, 'xmp_develop' )
		
			rxTest:expectEqual( 14, downloader.getCount() )
		
		else
		
			rxTest:expectEqual( 12, downloader.getCount() )
		
		end

		wfCatIdleDownloader:stop()

	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_NoDiskSpace( rxTest )

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_OverIdleSpaceThreshold( rxTest )

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	-- We should only download "required" assets.
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )

		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		rxTest:expectEqual( 10, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_Offline( rxTest )

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		rxTest:expectEqual( 10, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_NoDiskSpace_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}

	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		
		rxTest:expectEqual( 5, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_NoDiskSpace_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {},
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_NoDiskSpace_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_Offline_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		
		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		
		rxTest:expectEqual( 5, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_Offline_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_Offline_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_OverIdleSpaceThreshold_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'original' )
		else
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 7 + localIdOffset, true, 'original' )
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		rxTest:expectEqual( 10, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_OverIdleSpaceThreshold_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_OverIdleSpaceThreshold_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do

		downloader.resetCount()
		
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype, nil, nil, true )
		
		wfCatIdleDownloader:start()
		
		local localIdOffset = ( i - 1 ) * 15

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		
		-- Then downloads the important assets

		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 5 + localIdOffset, true, 'xmp_develop' )
		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		-- Then the proxies when we already have the originals
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' ) 
		
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
		
		if runWithSubtype == 'image' then
		
			-- The the external XMP from the version documents whose associated
			-- assets are marked for offline use.
			
			dls:expectData( true, 15 + localIdOffset, true, 'xmp_develop' )
			
			dls:expectData( true, 14 + localIdOffset, true, 'xmp_develop' )
		
			rxTest:expectEqual( runWithVideos and 15 or 16, downloader.getCount() )
		
		else
		
			rxTest:expectEqual( runWithVideos and 13 or 14, downloader.getCount() )
		
		end

		wfCatIdleDownloader:stop()

	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_NoDiskSpace( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_OverIdleSpaceThreshold( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	-- We should only download "required" assets.
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		
		-- Then downloads the important assets

		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		-- Then the proxies when we already have the originals
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' ) 
		
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
		
		rxTest:expectEqual( runWithVideos and 11 or 12, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_Offline( rxTest )

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies )
	
	local volumeGuid = WFFileUtils.getVolumeGuidForPath( wfCatalog:fileSpec():catalogPath() )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		
		-- Then downloads the important assets

		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		-- Then the proxies when we already have the originals
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' ) 
		
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
		
		rxTest:expectEqual( runWithVideos and 11 or 12, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 

		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end

		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()

	local optArgs = {
		originalsVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_NoDiskSpace_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}

	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true
		},
		remainingSpace = {},
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 

		-- Then downloads the important assets
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		rxTest:expectEqual( 6, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_NoDiskSpace_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {},
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_NoDiskSpace_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ volumeGuid ] = true,
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_Offline_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 

		-- Then downloads the important assets

		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		rxTest:expectEqual( 6, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_Offline_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_Offline_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ volumeGuid ] = true,
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	expectToDownloadNothing( rxTest, wfCatalog, wfCatIdleDownloader, downloader )

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_OverIdleSpaceThreshold_ExternalOriginals( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- Downloads marked for offline assets first
	
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' )
		
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
		
		-- Then downloads the important assets

		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
		
		-- Then the standard downloads

		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
		
		-- Then the proxies when we already have the originals
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
		
		rxTest:expectEqual( runWithVideos and 11 or 12, downloader.getCount() )
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_OverIdleSpaceThreshold_ExternalOriginals_NoDiskSpace( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {
			[ externalVolumeGuid ] = true
		},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

function WFCatIdleDownloaderTest.rxTestKeepBothProxiesAndOriginals_OverIdleSpaceThreshold_ExternalOriginals_Offline( rxTest )

	local volumeGuid = KSIdGenerator.uuidInLowercaseHex()
	local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()
	
	local optArgs = {
		catalogVolumeGuid = volumeGuid,
		originalsVolumeGuid = externalVolumeGuid,
		proxiesVolumeGuid = volumeGuid
	}
	
	local keepAllOriginals = true
	local keepAllProxies = true
	
	local wfCatalog, wfCatIdleDownloader, downloader = setupDownloader( rxTest, keepAllOriginals, keepAllProxies, optArgs )

	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {
			[ externalVolumeGuid ] = true
		},
		volumesOverIdleSpaceThreshold = {
			[ volumeGuid ] = true,
		},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )

	local dls = rxTest:observe( downloadStream )
	
	for i, runWithSubtype in pairs( kRunWithSubtypes ) do
	
		downloader.resetCount()
	
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, runWithSubtype )

		wfCatIdleDownloader:start()

		local localIdOffset = ( i - 1 ) * 13

		-- downloads marked for offline assets first
		
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
		
		local runWithVideos = isVideoSubtype( runWithSubtype )
		if not runWithVideos then
			-- For more info, search this file for `noRenditionsOnOz`
			dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
		end
		
		-- Then downloads the important assets
		
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		
		-- Then the standard priority downloads.

		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' )
		
		-- Then the proxies when we already have the originals
		
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' )
		
		if runWithVideos then
			rxTest:expectEqual( 5, downloader.getCount() )
		else
			rxTest:expectEqual( 6, downloader.getCount() )
		end
		
		wfCatIdleDownloader:stop()
		
	end

end

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

local function checkDownload( rxTest, docStore, localId, binaryType )

	local hasExpectedDownload = docStore:docValue( localId )
	
		:pluck( '_localOnly', 'files' )
	
		:map( function( files )
		
			if binaryType == 'original' then
				return derefOpt( files, 'original', 'master' ) and true or false	
			elseif binaryType == 'proxy' then
				return derefOpt( files, 'proxy', '2560' ) and true or false
			end
		
			return false
		
		end )

	rxTest:expectSingleValue( hasExpectedDownload, true )

end

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

function WFCatIdleDownloaderTest.rxTestManaged_Large_testNightly( rxTest )

	rxTest:setTimeLimit( 120 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	local docStore = wfCatalog:docStore()
	
	local downloadCount = 0
	
	local revDownloadCount = function()
		downloadCount = downloadCount + 1
	end
	
	local downloader = createDownloader( rxTest, wfCatalog:docStore(), revDownloadCount )
	
	local cancelFunc = function() --[[noop]] end
	
	local keepAllOriginals = false
	local keepAllProxies = false

	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, downloader, downloadStream, cancelFunc, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	for i = 1, 100 do
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image', false, true )
	end
	
	downloadCount = 0
	
	local dls = rxTest:observe( downloadStream )
	
	wfCatIdleDownloader:start()

	-- Wait for everything to download
	
	for i = 1, 1100 do
		dls:expectData( true, ':ignore:', true, ':ignore:' )
	end

	rxTest:sleep( 0.1 )
	rxTest:expectEqual( 1100, downloadCount )
		-- Sleep to make sure there are no additional, unexpected downloads.

	-- Verify we downloaded the proper things

	for i = 1, 100 do
	
		local offset = ( ( i - 1 ) * 13 )
		
		checkDownload( rxTest, docStore, 4 + offset, 'original' )
		checkDownload( rxTest, docStore, 1 + offset, 'original' )
		checkDownload( rxTest, docStore, 6 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 8 + offset, 'original' )
		checkDownload( rxTest, docStore, 12 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 3 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 7 + offset, 'original' )
		checkDownload( rxTest, docStore, 9 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 11 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 10 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 4 + offset, 'proxy' )
		
	end
	
	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()
		
	end )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllOriginals_Large_testNightly( rxTest )

	rxTest:setTimeLimit( 120 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	local docStore = wfCatalog:docStore()
	
	local downloadCount = 0
	
	local revDownloadCount = function()
		downloadCount = downloadCount + 1
	end
	
	local downloader = createDownloader( rxTest, wfCatalog:docStore(), revDownloadCount )
	
	local cancelFunc = function() --[[noop]] end
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, downloader, downloadStream, cancelFunc, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	for i = 1, 100 do
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image', false, true )
	end
	
	downloadCount = 0
	
	local dls = rxTest:observe( downloadStream )
	
	wfCatIdleDownloader:start()

	-- Wait for everything to download
	
	for i = 1, 1400 do
		dls:expectData( true, ':ignore:', true, ':ignore:' )
	end

	rxTest:sleep( 0.1 )
	rxTest:expectEqual( 1400, downloadCount )
		-- Sleep to make sure there are no additional, unexpected downloads.
		
	-- Verify we downloaded the proper things
	
	for i = 1, 100 do
		local offset = ( ( i - 1 ) * 13 )
		
		checkDownload( rxTest, docStore, 4 + offset, 'original' ) 
		checkDownload( rxTest, docStore, 1 + offset, 'original' )
		checkDownload( rxTest, docStore, 6 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 12 + offset, 'original' )
		checkDownload( rxTest, docStore, 3 + offset, 'original' ) 
		checkDownload( rxTest, docStore, 7 + offset, 'original' ) 
		checkDownload( rxTest, docStore, 8 + offset, 'original' )
		checkDownload( rxTest, docStore, 9 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 11 + offset, 'original' )
		checkDownload( rxTest, docStore, 3 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 10 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 4 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 12 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 11 + offset, 'proxy' )
	end

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.rxTestKeepAllProxies_Large_testNightly( rxTest )

	rxTest:setTimeLimit( 120 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	local docStore = wfCatalog:docStore()
	
	local downloadCount = 0
	
	local revDownloadCount = function()
		downloadCount = downloadCount + 1
	end
	
	local downloader = createDownloader( rxTest, wfCatalog:docStore(), revDownloadCount )
	
	local cancelFunc = function() --[[noop]] end
	
	local keepAllOriginals = false
	local keepAllProxies = true
	
	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, downloader, downloadStream, cancelFunc, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	for i = 1, 100 do
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, 'image', false, true )
	end
	
	downloadCount = 0
	
	local dls = rxTest:observe( downloadStream )
	
	wfCatIdleDownloader:start()

	-- Wait for everything to download
	
	for i = 1, 1100 do
		dls:expectData( true, ':ignore:', true, ':ignore:' )
	end

	rxTest:sleep( 0.1 )
	rxTest:expectEqual( 1100, downloadCount )
		-- Sleep to make sure there are no additional, unexpected downloads.

	-- Verify we downloaded the proper things
	
	for i = 1, 100 do
	
		local offset = ( ( i - 1 ) * 13 )
		
		checkDownload( rxTest, docStore, 4 + offset, 'original' )
		checkDownload( rxTest, docStore, 4 + offset, 'proxy' )
		
		checkDownload( rxTest, docStore, 12 + offset, 'proxy' )
		
		checkDownload( rxTest, docStore, 1 + offset, 'original' )
		checkDownload( rxTest, docStore, 6 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 8 + offset, 'original' )
		checkDownload( rxTest, docStore, 3 + offset, 'proxy' )
		
		checkDownload( rxTest, docStore, 7 + offset, 'original' ) 
		checkDownload( rxTest, docStore, 9 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 11 + offset, 'proxy' )
		checkDownload( rxTest, docStore, 10 + offset, 'proxy' )

	end

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.rxTestDenyAssetFromSync_testNightly( rxTest )

	rxTest:setTimeLimit( 30 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	local downloadCount = 0
	
	local badDownloader = createBadDownloader( downloadCount )
	
	local cancelFunc = function() --[[noop]] end
	
	local keepAllOriginals = false
	local keepAllProxies = false
	
	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, badDownloader, downloadStream, cancelFunc, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader )
	
	downloadCount = 0
	
	wfCatIdleDownloader:start()

	rxTest:sleep( 10 )
	
	-- Nothing should have downloaded.
	
	rxTest:expectEqual( 0, downloadCount )

	rxTest:finally( function()
	
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.DISABLED_rxTestManaged_testPerformance( rxTest )

	rxTest:setTimeLimit( 1000 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )

	local downloadCount = 0
	
	local revDownloadCount = function()
		downloadCount = downloadCount + 1
	end
	
	local downloader = createDownloader( rxTest, wfCatalog:docStore(), revDownloadCount )
	
	local cancelFunc = function() --[[noop]] end
	
	local keepAllOriginals = false
	local keepAllProxies = false
	
	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, downloader, downloadStream, cancelFunc, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	for i = 1, 1000 do
		logger:infof( "Adding assets..." )
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, false, false, true )
	end
	
	local dls = rxTest:observe( downloadStream )
	
	wfCatIdleDownloader:start()

	-- Verify we downloaded the proper things

	for i = 1, 1000 do
		local offset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 4 + offset, true, 'original' ) 
	end
	
	for i = 1, 1000 do
		local offset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 4 + offset, true, 'proxy' ) 
	end
	
	for i = 1, 1000 do
		local offset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 12 + offset, true, 'proxy' )
	end
	
	for i = 1, 1000 do
		local offset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 1 + offset, true, 'original' )
		dls:expectData( true, 6 + offset, true, 'proxy' )
		dls:expectData( true, 8 + offset, true, 'original' )
	end
	
	for i = 1, 1000 do
		local offset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 3 + offset, true, 'proxy' )
		dls:expectData( true, 7 + offset, true, 'original' )
		dls:expectData( true, 9 + offset, true, 'proxy' )
		dls:expectData( true, 11 + offset, true, 'proxy' )
	end
	
	for i = 1, 1000 do
		local offset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 10 + offset, true, 'proxy' )
	end
	
	rxTest:sleep( 0.1 )
	rxTest:expectEqual( 11000, downloadCount )
		-- Sleep to make sure there are no additional, unexpected downloads.
	
	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

function WFCatIdleDownloaderTest.DISABLED_rxTestKeepAllOriginals_testPerformance( rxTest )

	rxTest:setTimeLimit( 1000 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	local downloadCount = 0
	
	local revDownloadCount = function()
		downloadCount = downloadCount + 1
	end
	
	local downloader = createDownloader( rxTest, wfCatalog:docStore(), revDownloadCount )
	
	local cancelFunc = function() --[[noop]] end
	
	local keepAllOriginals = true
	local keepAllProxies = false
	
	local wfCatIdleDownloader = WFCatIdleDownloader( wfCatalog, downloader, downloadStream, cancelFunc, keepAllOriginals, keepAllProxies )
	
	wfCatIdleDownloader:reportStatusOfVolumes( {
		offlineVolumes = {},
		volumesOverIdleSpaceThreshold = {},
		volumesOutOfSpace = {},
		remainingSpace = {}
	} )
	
	for i = 1, 1000 do
		logger:infof( "Adding assets..." )
		addMixedAssets( rxTest, wfCatalog, wfCatIdleDownloader, false, false, true )
	end
	
	local dls = rxTest:observe( downloadStream )
	
	wfCatIdleDownloader:start()

	-- Wait for everything to download
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 4 + localIdOffset, true, 'original' ) 
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 4 + localIdOffset, true, 'proxy' ) 
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 12 + localIdOffset, true, 'original' )
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 1 + localIdOffset, true, 'original' )
		dls:expectData( true, 6 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 8 + localIdOffset, true, 'original' )
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 3 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 7 + localIdOffset, true, 'original' ) 
		dls:expectData( true, 9 + localIdOffset, true, 'proxy' )
		dls:expectData( true, 11 + localIdOffset, true, 'original' ) 
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 12 + localIdOffset, true, 'proxy' )
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 10 + localIdOffset, true, 'proxy' ) 
	end
	
	for i = 1, 1000 do
		local localIdOffset = ( ( i - 1 ) * 13 )
		dls:expectData( true, 3 + localIdOffset, true, 'proxy' ) 
		dls:expectData( true, 11 + localIdOffset, true, 'proxy' ) 
	end

	rxTest:sleep( 0.1 )
	rxTest:expectEqual( 14000, downloadCount )
		-- Sleep to make sure there are no additional, unexpected downloads.

	rxTest:finally( function()
	
		disposeOfDownloadSubscriptions()
		wfCatIdleDownloader:stop()
		wfCatIdleDownloader:close()

	end )

end

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

return WFRxTestCase.wrapSuite( WFCatIdleDownloaderTest )
