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

NmbVolumeAgentTest.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.

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

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

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

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

	-- WF.oz_client.managed_catalog
local WFCatMockCatalog = require 'WFCatMockCatalog'
local NmbVolumeAgent = require 'NmbVolumeAgent'
local WFCatDelete = require 'WFCatDelete'
local WFCatFileSpec = require 'WFCatFileSpec'
local NmbFileManagementSettings = require 'NmbFileManagementSettings'

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

local NmbVolumeAgentTest = {}

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

local hasSeen = {}

--------------------------------------------------------------------------------
			
local KSDate_timeNow = assert( KSDate.timeNow, "KSDate.timeNow does not exist" )

local basePath = KSPathUtils.getStandardFilePath( 'carouselDocuments' )
local relativePath = WFFileUtils.removeVolumeFromPath( basePath )

local originalVolumeGuid = WFFileUtils.getVolumeGuidForPath( basePath )
local proxyVolumeGuid = WFFileUtils.getVolumeGuidForPath( basePath )
local externalVolumeGuid = KSIdGenerator.uuidInLowercaseHex()

local defaultPurgeReason = 1 -- No Disk Space

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

local catalogByTest = {}
local volumeAgentByTest = {}

local function setupVolumeAgent( rxTest, overrides )

	overrides = overrides or {}

	local volumeGuid = overrides.volumeGuid or originalVolumeGuid
	local targetDiskSpaceUsage = overrides.targetDiskSpaceUsage or 0.30
	local keepAllOriginals = overrides.keepAllOriginals or false
	local keepAllProxies = overrides.keepAllProxies or false
	
	if not overrides.debugProactivePurge then
		overrides.debugReactivePurge = true
	end

	if overrides.debugDisableMaxSizePurgeableCheck ~= false then
		overrides.debugDisableMaxSizePurgeableCheck = true
	end

	if not hasSeen[ rxTest ] then
		rxTest:setTimeLimit( overrides.timeLimit or 10 )
	end
	
	hasSeen[ rxTest ] = true

	local wfCatalog = catalogByTest[ rxTest ] 
			or WFCatMockCatalog.createFakeWFCatalog( rxTest )
	
	catalogByTest[ rxTest ] = wfCatalog

	local keptLocalInfo = {
		keepAllOriginals = keepAllOriginals,
		keepAllProxies = keepAllProxies,
	}
	
	local nmbVolumeAgent = volumeAgentByTest[ rxTest ] 
			or NmbVolumeAgent( wfCatalog, nil, volumeGuid, relativePath, 
								targetDiskSpaceUsage, keptLocalInfo, overrides )

	volumeAgentByTest[ rxTest ] = nmbVolumeAgent

	rxTest:finally( function()
	
		nmbVolumeAgent:close()
		nmbVolumeAgent = nil
		
		wfCatalog:close()
		wfCatalog = nil
		
		hasSeen[ rxTest ] = nil
		catalogByTest[ rxTest ] = nil
		volumeAgentByTest[ rxTest ] = nil
	
	end )
	
	return wfCatalog, nmbVolumeAgent

end

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

local function basicDocValue( maybeOriginalVolumeGuid, maybeProxyVolumeGuid )

	return {

		type = 'asset',
		subtype = 'image',
		captureDate = '2012-08-15T15:22:29',
		
		importSource = {
			importTimestamp = "2015-05-26T17:34:23-07:00",
			fileName = "Image.jpg",
		},
		
		_localOnly = {
			isMarkedForOfflineUse = false,
			files = {
				original = {
					master = {
						relativePath = 'path/to/original.jpg',
						volumeGuid = maybeOriginalVolumeGuid,
						size = 100,
					}
				},
				proxy = {
					[ '2560' ] = {
						relativePath = 'path/to/proxy.jpg',
						volumeGuid = maybeProxyVolumeGuid,
						size = 50, 
					},
					[ '720p' ] = {
						relativePath = 'path/to/proxy.mp4',
						volumeGuid = maybeProxyVolumeGuid,
						size = 50, 
					}
				},
			}
		},

		_serverProvidedMetadata = {
			links = {
				[ '/rels/master' ] = {
					href = 'path/to/original.jpg',
				},
				[ '/rels/proxy_type/2560' ] = {
					href = 'path/to/proxy.jpg',
				},
				[ '/rels/rendition_type/720p' ] = {
					href = 'path/to/proxy.jpg',
				},
				[ '/rels/rendition_type/640' ] = {
					href = 'path/to/rendition.jpg'
				}
			}
		}

	}
	
end

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

local function createBasicDoc( rxTest, wfCatalog, optArgs )

	optArgs = optArgs or {}
	
	local docId = KSIdGenerator.uuidInLowercaseHex()
	local localId
	
	local volumeGuidForOriginal = optArgs.originalVolumeGuid or originalVolumeGuid
	
	local volumeGuidForProxy = optArgs.proxyVolumeGuid or proxyVolumeGuid
	
	local docValue = basicDocValue( volumeGuidForOriginal, volumeGuidForProxy )
	docValue._id = docId
	
	local size = optArgs.size or 1
	
	docValue.importSource.fileSize = size
	docValue._localOnly.files.original.master.size = size
	docValue._localOnly.files.proxy[ '2560' ].size = size
	docValue._localOnly.files.proxy[ '720p' ].size = size
	
	if optArgs.originalOnly then
		docValue._localOnly.files.proxy = nil
	end
	
	if optArgs.ozHasOriginal == false then
		docValue._serverProvidedMetadata.links[ '/rels/master' ] = nil
	end


	if optArgs.ozHasProxy == false then
		docValue._serverProvidedMetadata.links[ '/rels/proxy_type/2560' ] = nil
		docValue._serverProvidedMetadata.links[ '/rels/rendition_type/720p' ] = nil
	end
	
	if optArgs.isVideo then
		docValue.subtype = 'video'
		docValue._localOnly.files.proxy[ '2560' ] = nil
	end
	
	if optArgs.isMarkedForOfflineUse then
		docValue._localOnly.isMarkedForOfflineUse = true
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():setDocValue( docValue ), ':ignore:' )

	local lastAccessedOffsetInDays = optArgs.lastAccessedOffsetInDays or 1000
		-- default to an asset not being accessed for 1000 days
		
	local daysToSeconds = function( days )
		return days * 24 * 60 * 60
	end

	local nDaysAgoInSeconds
	
	if lastAccessedOffsetInDays > 0 then
		nDaysAgoInSeconds = KSDate_timeNow() - daysToSeconds( lastAccessedOffsetInDays )
	end
	
	rxTest:expectOnlyCompleted(
		wfCatalog:docStore():docValue( docId )
			:flatMap( function( docValue )
				
				localId = docValue._localId
				return wfCatalog:fileAccessDb():touch( localId, nDaysAgoInSeconds )
				
			end ) )

	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )

	return docId, localId

end

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

local function createBasicDocsForPerformanceTest( rxTest, wfCatalog, numberOfDocs, optArgs )

	optArgs = optArgs or {}
	
	local docValues = {}
	local docIds = {}
	
	for i=1, numberOfDocs do
	
		local docId = KSIdGenerator.uuidInLowercaseHex()
		
		local volumeGuidForOriginal = optArgs.originalVolumeGuid or originalVolumeGuid
		
		local volumeGuidForProxy = optArgs.proxyVolumeGuid or proxyVolumeGuid
		
		local docValue = basicDocValue( volumeGuidForOriginal, volumeGuidForProxy )
		docValue._id = docId
		
		local size = optArgs.size or 1
		
		docValue.importSource.fileSize = size
		docValue._localOnly.files.original.master.size = size
		docValue._localOnly.files.proxy[ '2560' ].size = size
		docValue._localOnly.files.proxy[ '720p' ].size = size
		
		if optArgs.originalOnly then
			docValue._localOnly.files.proxy = nil
		end
		
		if optArgs.ozHasOriginal == false then
			docValue._serverProvidedMetadata.links[ '/rels/master' ] = nil
		end

		if optArgs.ozHasProxy == false then
			docValue._serverProvidedMetadata.links[ '/rels/proxy_type/2560' ] = nil
			docValue._serverProvidedMetadata.links[ '/rels/rendition_type/720p' ] = nil
		end
		
		if optArgs.isVideo then
			docValue.subtype = 'video'
			docValue._localOnly.files.proxy[ '2560' ] = nil
		end
		
		if optArgs.isMarkedForOfflineUse then
			docValue._localOnly.isMarkedForOfflineUse = true
		end
	
		docValues[ #docValues + 1 ] = docValue
		docIds[ #docIds + 1 ] = docId
	end
	
	rxTest:expectSingleValue( wfCatalog:docStore():bulkSetDocValue( docValues ), ':ignore:' )

	local lastAccessedOffsetInDays = optArgs.lastAccessedOffsetInDays or 1000
		-- default to an asset not being accessed for 1000 days
		
	local daysToSeconds = function( days )
		return days * 24 * 60 * 60
	end

	local nDaysAgoInSeconds
	
	if lastAccessedOffsetInDays > 0 then
		nDaysAgoInSeconds = KSDate_timeNow() - daysToSeconds( lastAccessedOffsetInDays )
	end
	
	wfCatalog:fileAccessDb():touchMultipleIfNew( docIds, nDaysAgoInSeconds )

	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )

	return docIds

end

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

local function gbToBytes( gb )

	return gb * 1024 * 1024 * 1024

end

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

local function bytesToGb( bytes )

	return bytes / 1024 / 1024 / 1024

end

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

-- On Android, this test fails because the path associated with the
-- nmbVolumeAgent might not exist due to the use of an in memory doc store.

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

local function testTargetFreeSpace( rxTest, targetDiskSpaceUsage, freeSpaceGb, nimbusSpaceGb, expectedTargetGb, keepAllOriginals, keepAllProxies, useGbs )

	local catalog, nmbVolumeAgent = setupVolumeAgent( rxTest )

	nmbVolumeAgent._debugMockDiskFreeSpace = gbToBytes( freeSpaceGb )
	nmbVolumeAgent._debugMockNimbusSize = gbToBytes( nimbusSpaceGb )
	nmbVolumeAgent._targetDiskSpaceUsage = targetDiskSpaceUsage
	nmbVolumeAgent._keepAllOriginals = keepAllOriginals
	nmbVolumeAgent._keepAllProxies = keepAllProxies
	nmbVolumeAgent._minimumFreeSpace = gbToBytes( 10 )

	local rootPath = catalog:fileSpec():rootPath()

	local getTargetFreeSpace = nmbVolumeAgent.private._calculateTargetFreeSpaceResultStream

	local targetSpaceInfo
	rxTest:expectSingleValue( getTargetFreeSpace( nmbVolumeAgent, rootPath, nmbVolumeAgent._debugMockDiskFreeSpace, targetDiskSpaceUsage )
		:map( function( info )
			targetSpaceInfo = info
			return type( info )
		end ), 'table' )

	local expected = math.ceil( gbToBytes( expectedTargetGb ) )
	local actual = math.ceil( targetSpaceInfo.targetFreeSpace )
	
	rxTest:expectEqual( expected, actual )
	
	nmbVolumeAgent:close()
	
end

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

function NmbVolumeAgentTest.rxTestTargetFreeSpace( rxTest )

	local targetDiskSpaceUsage = 0.25 

	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 1, 109, 85 )

	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 0, 110, 85 )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 110, 0, 85 )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 109, 1, 85 )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 60, 50, 85 )

	-- Keel All Originals
	
	-- For the following tests, orginals take up 60% of the disk space usage
	-- and proxies take up 40%.

	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 1, 109, 35.95, true )
		-- Min Free Space = 10
		-- Size of originals = 109 * 0.6 = 65.4
		-- Max size of proxies = 110 - 10 - 65.4 = 34.6 * 0.25 = 8.65
		-- Max size of Nimbus = 65.4 + 8.65 = 74.05
		-- TARGET FREE SPACE = 110 - 74.05 = 35.95
		
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 0, 110, 35.5, true )
		-- Min Free Space = 10
		-- Size of originals = 110 * 0.6 = 66
		-- Max size of proxies = 110 - 10 - 66 = 34 * 0.25 = 8.5
		-- TARGET FREE SPACE = 110 - 66 - 8.5 = 35.5
		
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 110, 0, 85, true )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 109, 1, 84.55, true )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 60, 50, 62.50, true )
	
	-- Keep All Proxies

	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 1, 109, 52.30, false, true )
		-- Min Free Space = 10
		-- Size of originals = 109 * 0.4 = 43.6
		-- Max size of proxies = 110 - 10 - 43.6 = 56.6 * 0.25 = 14.1
		-- TARGET FREE SPACE = 110 - 43.6 - 14.1 = 42.30
		
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 0, 110, 52.00, false, true )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 110, 0, 85, false, true )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 109, 1, 84.7, false, true )
	
	testTargetFreeSpace( rxTest, targetDiskSpaceUsage, 60, 50, 70.00, false, true )
	
	-- Keep Everything
	
	testTargetFreeSpace( rxTest, 1, 1, 109, 10, true, true )

	testTargetFreeSpace( rxTest, 1, 0, 110, 10, true, true )
	
	testTargetFreeSpace( rxTest, 1, 110, 0, 10, true, true )
	
	testTargetFreeSpace( rxTest, 1, 109, 1, 10, true, true )
	
	testTargetFreeSpace( rxTest, 1, 60, 50, 10, true, true )

end

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

local function testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, freeSpaceGb, nimbusSpaceGb, keepAllOriginals, keepAllProxies )

	local minimumFreeSpace = 10

	local catalog, nmbVolumeAgent = setupVolumeAgent( rxTest )

	nmbVolumeAgent._debugMockDiskFreeSpace = gbToBytes( freeSpaceGb )
	nmbVolumeAgent._debugMockNimbusSize = gbToBytes( nimbusSpaceGb )
	nmbVolumeAgent._targetDiskSpaceUsage = targetDiskSpaceUsage
	nmbVolumeAgent._keepAllOriginals = keepAllOriginals
	nmbVolumeAgent._keepAllProxies = keepAllProxies
	nmbVolumeAgent._minimumFreeSpace = gbToBytes( minimumFreeSpace )

	local rootPath = catalog:fileSpec():rootPath()

	local getTargetFreeSpace = nmbVolumeAgent.private._calculateTargetFreeSpaceResultStream

	local spaceInfo
	rxTest:expectSingleValue( getTargetFreeSpace( nmbVolumeAgent, rootPath, nmbVolumeAgent._debugMockDiskFreeSpace, targetDiskSpaceUsage )
		:map( function( info )
			spaceInfo = info
			return type( info )
		end ), 'table' )

	local spacedUsedByOriginals = nimbusSpaceGb * 0.6
	local spacedUsedByProxies = nimbusSpaceGb * 0.4
	
	local maxSpace = targetDiskSpaceUsage * ( nimbusSpaceGb + freeSpaceGb - minimumFreeSpace )
	
	local percentOfTargetSpaceUsed = math.ceil( nimbusSpaceGb / maxSpace )
	local percentOfTargetSpaceUsedByOriginals = math.ceil( ( spacedUsedByOriginals ) / maxSpace )
	local percentOfTargetSpaceUsedByProxies = math.ceil( ( spacedUsedByProxies ) / maxSpace )
	local maxSizeOfPurgeableOriginals = math.ceil( spacedUsedByOriginals )
	local maxSizeOfPurgeableProxies =  math.ceil( ( spacedUsedByProxies ) - ( .55 * maxSpace ) )
	
	if keepAllOriginals then
	
		maxSizeOfPurgeableOriginals = 0
		percentOfTargetSpaceUsedByOriginals = 0
		maxSpace = targetDiskSpaceUsage * ( nimbusSpaceGb + freeSpaceGb - minimumFreeSpace - spacedUsedByOriginals )
		percentOfTargetSpaceUsed = math.ceil( spacedUsedByProxies / maxSpace )
		percentOfTargetSpaceUsedByProxies = math.ceil( ( spacedUsedByProxies ) / maxSpace )
		maxSizeOfPurgeableProxies =  math.ceil( ( spacedUsedByProxies ) - ( .55 * maxSpace ) )
		
	end
	
	if keepAllProxies then
	
		maxSizeOfPurgeableProxies = 0
		percentOfTargetSpaceUsedByProxies = 0
		maxSpace = targetDiskSpaceUsage * ( nimbusSpaceGb + freeSpaceGb - minimumFreeSpace - spacedUsedByProxies )
		percentOfTargetSpaceUsed = math.ceil( spacedUsedByOriginals / maxSpace )
		percentOfTargetSpaceUsedByOriginals = math.ceil( ( spacedUsedByOriginals ) / maxSpace )
		maxSizeOfPurgeableOriginals = math.ceil( spacedUsedByOriginals )
		
	end
			
	local expected = { 
		percentOfTargetSpaceUsed,
		percentOfTargetSpaceUsedByOriginals,
		percentOfTargetSpaceUsedByProxies,
		maxSizeOfPurgeableOriginals,
		maxSizeOfPurgeableProxies
	}
	
	local actual = { 
		math.ceil( spaceInfo.percentOfTargetSpaceUsed ),
		math.ceil( spaceInfo.percentOfTargetSpaceUsedByOriginals ),
		math.ceil( spaceInfo.percentOfTargetSpaceUsedByProxies ),
		math.ceil( bytesToGb( spaceInfo.maxSizeOfPurgeableOriginals ) ),
		math.ceil( bytesToGb( spaceInfo.maxSizeOfPurgeableProxies ) )
	}
	
	rxTest:expectEqual( expected, actual )
	
	nmbVolumeAgent:close()
	
end

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

function NmbVolumeAgentTest.rxTestTargetSpaceInfo( rxTest )

	local targetDiskSpaceUsage = 0.25 

	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 1, 109 )

	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 0, 110 )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 110, 0 )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 109, 1 )

	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 60, 50 )

	-- Keel All Originals
	
	-- For the following tests, orginals take up 60% of the disk space usage
	-- and proxies take up 40%.

	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 1, 109, true )
		-- Min Free Space = 10
		-- Size of originals = 109 * 0.6 = 65.4
		-- Max size of proxies = 110 - 10 - 65.4 = 34.6 * 0.25 = 8.65
		-- Max size of Nimbus = 65.4 + 8.65 = 74.05
		-- TARGET FREE SPACE = 110 - 74.05 = 35.95
		
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 0, 110, true )
		-- Min Free Space = 10
		-- Size of originals = 110 * 0.6 = 66
		-- Max size of proxies = 110 - 10 - 66 = 34 * 0.25 = 8.5
		-- TARGET FREE SPACE = 110 - 66 - 8.5 = 35.5
		
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 110, 0, true )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 109, 1, true )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 60, 50, true )
	
	-- Keep All Proxies

	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 1, 109, false, true )
		-- Min Free Space = 10
		-- Size of originals = 109 * 0.4 = 43.6
		-- Max size of proxies = 110 - 10 - 43.6 = 56.6 * 0.25 = 14.1
		-- TARGET FREE SPACE = 110 - 43.6 - 14.1 = 42.30
		
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 0, 110, false, true )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 110, 0, false, true )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 109, 1, false, true )
	
	testTargetSpaceInfo( rxTest, targetDiskSpaceUsage, 60, 50, false, true )

end

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

local function testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, freeSpaceGb, 
		nimbusSpaceGb, expectedTargetGb, keepAllOriginals, keepAllProxies, proactivePurge )

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest )

	local calculatePurgeBuffer = nmbVolumeAgent.private._calculatePurgeBufferResultStream
	
	nmbVolumeAgent._debugMockDiskFreeSpace = gbToBytes( freeSpaceGb )
	nmbVolumeAgent._debugMockNimbusSize = gbToBytes( nimbusSpaceGb )
	nmbVolumeAgent._targetDiskSpaceUsage = targetDiskSpaceUsage
	nmbVolumeAgent._keepAllOriginals = keepAllOriginals
	nmbVolumeAgent._keepAllProxies = keepAllProxies
	nmbVolumeAgent._minimumFreeSpace = gbToBytes( 10 )
	
	local expected = math.ceil( gbToBytes( expectedTargetGb ) )
	rxTest:expectSingleValue( calculatePurgeBuffer( nmbVolumeAgent, proactivePurge ):map( math.ceil ), expected )
	
	nmbVolumeAgent:close()
	
end

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

local function testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, freeSpaceGb, nimbusSpaceGb, expectedTargetGb, keepAllOriginals, keepAllProxies )

	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, freeSpaceGb, nimbusSpaceGb, expectedTargetGb, keepAllOriginals, keepAllProxies, 4 )
	
end

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

local function testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, freeSpaceGb, nimbusSpaceGb, expectedTargetGb, keepAllOriginals, keepAllProxies )

	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, freeSpaceGb, nimbusSpaceGb, expectedTargetGb, keepAllOriginals, keepAllProxies, 5 )
	
end

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

function NmbVolumeAgentTest.rxTestCalculatePurgeBuffer( rxTest )

	local targetDiskSpaceUsage = 0.25 

	-- The purge buffer is 10% of the max space. 
	-- The max space is 100GB * 0.25 = 25GB
	-- 25GB * 10% = 2.5GB
	-- The minimum free space is 10GB
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 1, 109, 2.5 )
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 0, 110, 2.5 )
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 60, 50, 2.5 )
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 86, 24, 0 )
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 110, 0, 0 )
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 109, 1, 0 )
		-- No purge buffer is needed when below the target disk space usage.

	-- Keel All Originals
	
	-- For the following tests, orginals take up 60% of the disk space usage
	-- and proxies take up 40%.

	-- When keeping all originals, the purge buffer is 10% of the max space
	-- that proxies can take up.

	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 1, 109, 0.865, true )
		-- Current space of originals = 109GB * 60% = 65.4GB
		-- The max space of proxies = ( 100GB - 65.4GB ) * 0.25 = 8.65GB
		-- Purge buffer = 8.65GB * 10% = 0.865GB
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 0, 110, .85, true )
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 60, 50, 1.75, true )
		-- Current space of originals = 50GB * 60% = 30GB
		-- The max space of proxies = ( 100GB - 30GB ) * 0.25 = 17.5GB
		-- Purge buffer = 17.5GB * 10% = 1.75GB
		
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 86, 24, 0, true )
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 110, 0, 0, true )
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 109, 1, 0, true )
		-- Below target space threshold so no buffer is needed.
	
	-- Keep All Proxies

	-- When keeping all proxies, the purge buffer is 10% of the max space
	-- that originals can take up.

	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 1, 109, 1.41, false, true )
		-- Current space of proxies = 109GB * 40% = 43.6GB
		-- The max space of originals = ( 100GB - 43.6GB ) * 0.25 = 14.1GB
		-- Purge buffer = 14.1GB * 10% = 1.41GB
		
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 0, 110, 1.4, false, true )
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 60, 50, 2.00, false, true )
	
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 86, 24, 0, false, true )
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 110, 0, 0, false, true )
	testCalculatePurgeBuffer( rxTest, targetDiskSpaceUsage, 109, 1, 0, false, true )
		-- Below target space threshold so no buffer is needed.
	
	-- Keep Everything
	
	-- No Purge Buffer
	
	testCalculatePurgeBuffer( rxTest, 1, 1, 109, 0, true, true )

	testCalculatePurgeBuffer( rxTest, 1, 0, 110, 0, true, true )
	
	testCalculatePurgeBuffer( rxTest, 1, 110, 0, 0, true, true )
	
	testCalculatePurgeBuffer( rxTest, 1, 109, 1, 0, true, true )
	
	testCalculatePurgeBuffer( rxTest, 1, 60, 50, 0, true, true )

end
	
--------------------------------------------------------------------------------

function NmbVolumeAgentTest.rxTestCalculatePurgeBuffer_ProactiveProxies( rxTest )

	-- The minimum free space is 10GB

	local targetDiskSpaceUsage = 0.25 

	-- When purging proactively, the purge buffer is the total amount of space
	-- that can be attempted to be purged. This includes any space over the target
	-- threshold as well as 45% of the target space threshold.
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 1, 109, 29.85 )
		-- Total Proxies = 109 * 0.4 = 43.6GB
		-- Amount above target = 43.6GB - 25GB = 18.6GB
		-- Purgeable in target = 25GB * 0.45 = 11.25GB
		-- Amount to Purge = 18.6GB + 11.25GB = 29.85GB
		
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 0, 100, 27.625 )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 60, 50, 6.25 )
		-- Total Proxies = 50 * 0.4 = 20GB
		-- Amount above target = 20GB - 25GB = -5GB
		-- Purgeable in target = 25GB * 0.45 = 11.25GB
		-- Amount to Purge = -5GB + 11.25GB = 6.25GB
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 86, 24, 0 )
		-- Total Proxies = 24 * 0.4 = 9.6GB
		-- Amount above target = 9.6GB - 25GB = -15.4GB
		-- Purgeable in target = 25GB * 0.45 = 11.25GB
		-- Amount to Purge = -15.4GB + 11.25GB < 0 = 0GB
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 110, 0, 0 )
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 109, 1, 0 )

		
	-- Keel All Originals
	
	-- For the following tests, orginals take up 60% of the disk space usage
	-- and proxies take up 40%.

	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 1, 109, 38.8425, true )
		-- Current space of proxies = 109GB * 40% = 43.6GB
		-- The max space of proxies = ( 43.6GB - 9 ) * 0.25 = 8.65GB
		-- Proxy space above target = 43.6GB - 8.65GB = 34.95GB
		-- Purgeable proxies in target = 8.65GB * 0.45 = 3.8925GB
		-- Amount to Purge = 34.95GB + 3.8925GB = 38.8425GB
		
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 0, 110, 39.325, true )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 60, 50, 10.375, true )
		-- Current space of originals = 50GB * 40% = 20GB
		-- The max space of originals = ( 50GB + 20GB ) * 0.25 = 17.5GB
		-- originals space above target = 20GB - 17.5GB = 2.5GB
		-- Purgeable proxies in target = 17.5GB * 0.45 = 7.875GB
		-- Amount to Purge = 2.5GB + 7.875GB = 10.375GB
		
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 86, 24, 0, true )
		-- Current space of originals = 24GB * 40% = 9.6GB
		-- The max space of originals = ( 76GB + 9.6GB ) * 0.25 = 21.4GB
		-- originals space above target = 9.6GB - 21.4GB = -11.8GB
		-- Purgeable proxies in target = 21.4GB * 0.45 = 9.63GB
		-- Amount to Purge = -11.8 + 9.63 ~= 0
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 110, 0, 0, true )
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 109, 1, 0, true )
		-- Amount above target = 0GB
	
	-- Keep All Proxies

	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 1, 109, 0, false, true )

	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 0, 110, 0, false, true )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 60, 50, 0, false, true )

	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 86, 24, 0, false, true )

	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 110, 0, 0, false, true )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, targetDiskSpaceUsage, 109, 1, 0, false, true )

	-- Keep Everything
	
	testCalculatePurgeBufferProactiveProxies( rxTest, 1, 1, 109, 0, true, true )

	testCalculatePurgeBufferProactiveProxies( rxTest, 1, 0, 110, 0, true, true )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, 1, 110, 0, 0, true, true )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, 1, 109, 1, 0, true, true )
	
	testCalculatePurgeBufferProactiveProxies( rxTest, 1, 60, 50, 0, true, true )

end
	
--------------------------------------------------------------------------------

function NmbVolumeAgentTest.rxTestCalculatePurgeBuffer_ProactiveOriginals( rxTest )

	local targetDiskSpaceUsage = 0.25 

	-- When purging originals proactively, we try to purge them all unless we're
	-- keeping them all local.
	
	local percentageOfOriginals = 0.6

	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 1, 109, 109*percentageOfOriginals )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 0, 110, 110*percentageOfOriginals )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 60, 50, 50*percentageOfOriginals )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 86, 24, 24*percentageOfOriginals)

	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 110, 0, 0 )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 109, 1, 1*percentageOfOriginals )

	-- Keel All Originals
	
	-- For the following tests, orginals take up 60% of the disk space usage
	-- and proxies take up 40%.

	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 1, 109, 0, true )

	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 0, 110, 0, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 60, 50, 0, true )
		
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 86, 24, 0, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 110, 0, 0, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 109, 1, 0, true )
	
	-- Keep All Proxies

	-- For the following tests, orginals take up 60% of the disk space usage
	-- and proxies take up 40%.

	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 1, 109, 65.4, false, true )
		-- Current space of originals = 109GB * 60% = 59.4GB
		
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 0, 110, 66, false, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 60, 50, 30, false, true )
		-- Current space of originals = 50GB * 60% = 30GB
		
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 86, 24, 14.4, false, true )
		-- Current space of originals = 24GB * 60% = 14.4GB
		
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 110, 0, 0, false, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, targetDiskSpaceUsage, 109, 1, 0.6, false, true )

	-- Keep Everything
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, 1, 1, 109, 0, true, true )

	testCalculatePurgeBufferProactiveOriginals( rxTest, 1, 0, 110, 0, true, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, 1, 110, 0, 0, true, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, 1, 109, 1, 0, true, true )
	
	testCalculatePurgeBufferProactiveOriginals( rxTest, 1, 60, 50, 0, true, true )

end
	
--------------------------------------------------------------------------------

local function testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 
		freeSpaceGb, nimbusSpaceGb, spaceNeededToPreventNoDiskSpaceGb, 
		spaceNeededToReachTargetDiskSpaceGb )

	local nimbusSize = gbToBytes( nimbusSpaceGb )
	local freeSpaceSize = gbToBytes( freeSpaceGb )
	
	local overrides = {
		timeLimit = 30,
	}

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )

	nmbVolumeAgent._debugMockNimbusSize = nimbusSize
	nmbVolumeAgent._debugMockDiskFreeSpace = freeSpaceSize
	nmbVolumeAgent._targetDiskSpaceUsage = targetDiskSpaceUsage
	nmbVolumeAgent._minimumFreeSpace = gbToBytes( minimumFreeSpace )

	local getDiskSpaceNeeded = nmbVolumeAgent.private._getDiskSpaceNeededResultStream
	
	local percentOfTargetSpaceUsedExpected = nimbusSpaceGb / ( ( nimbusSpaceGb + freeSpaceGb - minimumFreeSpace ) * targetDiskSpaceUsage )
	
	rxTest:expectSingleValue( 
	
		getDiskSpaceNeeded( nmbVolumeAgent )
			:map( function( spaceNeededToPreventNoDiskSpace,
					spaceNeededToReachTargetDiskSpace,
					targetSpaceInfo,
					maybeFileSystemFreeSpace )
					
					return math.ceil( bytesToGb( spaceNeededToPreventNoDiskSpace ) ),
							math.ceil( bytesToGb( spaceNeededToReachTargetDiskSpace ) ),
							targetSpaceInfo.percentOfTargetSpaceUsed,
							maybeFileSystemFreeSpace
					
			end ),
			math.ceil( spaceNeededToPreventNoDiskSpaceGb ),
			math.ceil( spaceNeededToReachTargetDiskSpaceGb ),
			percentOfTargetSpaceUsedExpected,
			freeSpaceSize )
	
	nmbVolumeAgent:close()
	
end
	
--------------------------------------------------------------------------------

function NmbVolumeAgentTest.rxTestGetSpaceNeeded( rxTest )

	-- The following is based on the settings:
	
	local targetDiskSpaceUsage = 0.25 
	local minimumFreeSpace = 10
	
	-- Plenty of disk space

	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 110, 0, 0, 0 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 90, 20, 0, 0 )
	
	-- Target Limit Reached
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 85, 25, 0, 0 )
	
	-- Target Limit Exceeded
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 60, 50, 0, 25 )
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 50, 60, 0, 35 )
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 40, 70, 0, 45 )
	
	-- No disk space scenarios
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 0, 110, 10, 75 )

	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 1, 109, 9, 75 )

	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 2, 108, 8, 75 )

	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 9, 101, 1, 75 )

	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 10, 100, 0, 75 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 11, 99, 0, 74 )
	
end
	
--------------------------------------------------------------------------------

function NmbVolumeAgentTest.rxTestGetSpaceNeeded_ExternalDrive( rxTest )

	-- The following is based on the settings:
	
	local targetDiskSpaceUsage = 1
	local minimumFreeSpace = 10 --gb
	
	-- Plenty of disk space
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 110, 0, 0, 0 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 90, 20, 0, 0 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 60, 50, 0, 0 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 50, 60, 0, 0 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 40, 70, 0, 0 )
	
	-- No disk space scenarios
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 1, 109, 9, 0 )
	
	testGetDiskSpaceNeeded( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 0, 110, 10, 0 )
	
end
	
--------------------------------------------------------------------------------

local function testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 
		freeSpaceGb, nimbusSpaceGb, spaceNeededToPreventNoDiskSpaceGb, 
		spaceNeededToReachTargetDiskSpaceGb, expectedCount )

	local nimbusSize = gbToBytes( nimbusSpaceGb )
	local freeSpaceSize = gbToBytes( freeSpaceGb )
	
	local overrides = {
		timeLimit = 30
	}

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )

	nmbVolumeAgent._debugMockNimbusSize = nimbusSize
	nmbVolumeAgent._debugMockDiskFreeSpace = freeSpaceSize
	nmbVolumeAgent._targetDiskSpaceUsage = targetDiskSpaceUsage
	nmbVolumeAgent._minimumFreeSpace = gbToBytes( minimumFreeSpace )

	local spaceNeededStream = nmbVolumeAgent.private._spaceNeededStream
	local stream = spaceNeededStream( nmbVolumeAgent )
	local count = 0
	
	stream = stream
		:map( function( noSpaceGb, lowSpaceGb )
			return math.ceil( bytesToGb( noSpaceGb ) ),
				math.ceil( bytesToGb( lowSpaceGb ) )
		end )
		:tap( function()
			count = count + 1
		end )

	local o = rxTest:observe( stream )
	
	if expectedCount > 0 then
		o:expectDataWithinTime( 
			5, 
			math.ceil( spaceNeededToPreventNoDiskSpaceGb ), 
			math.ceil( spaceNeededToReachTargetDiskSpaceGb ) )
	end
	
	rxTest:expectEqual( count, expectedCount )
	
	o:dispose()
	nmbVolumeAgent:close()
	
end

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

function NmbVolumeAgentTest.rxTestSpaceNeededStream( rxTest )

	-- The following is based on the settings:
	
	local targetDiskSpaceUsage = 0.3
	local minimumFreeSpace = 10
	
	-- Plenty of disk space
	
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 110, 0, 0, 0, 0 )
	
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 90, 20, 0, 0, 0 )
	
	-- Target Limit Reached
	
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 80, 30, 0, 0, 0 )
	
	-- Target Limit Exceeded
	
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 60, 50, 0, 20, 1 )
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 50, 60, 0, 30, 1 )
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 40, 70, 0, 40, 1 )
	
	-- No disk space scenarios
	
	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 0, 110, 10, 70, 1 )

	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 1, 109, 9, 70, 1 )

	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 2, 108, 8, 70, 1 )

	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 10, 100, 0, 70, 1 )

	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 11, 99, 0, 69, 1 )

	testSpaceNeededStream( rxTest, targetDiskSpaceUsage, minimumFreeSpace, 12, 98, 0, 68, 1 )
	
end

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

local function mapAwayLastAccessDate( tbl )

	local mappedTbl = {}

	for k, v in pairs( tbl ) do 
		
		if type( v ) == 'table' then
			mappedTbl[ k ] = mapAwayLastAccessDate( v )
		elseif k ~= 'lastAccessed' then
			mappedTbl[ k ] = v
		end
		
	end
	
	return mappedTbl

end

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

function NmbVolumeAgentTest.rxTestPurgeOnDelete( rxTest )

	local wfCatalog = setupVolumeAgent( rxTest )
	local fileAccessDb = wfCatalog:fileAccessDb()
	
	local _docId, _localId = createBasicDoc( rxTest, wfCatalog )
	
	-- Wait until the file access db is up to date.
	
	rxTest:expectSingleValue( fileAccessDb:waitUntilUpToDate(), true )
	
	rxTest:expectSingleValue( fileAccessDb:DEBUG_dumpLastAccessContents()
		:map( mapAwayLastAccessDate ), 
		{ {
			localId = _localId,
			docId = _docId,
			isMarkedForOfflineUse = 0,
			isImportant = 0,
			originalFileSize = 1,
			ozHasOriginal = 1,
			ozHasProxy = 1,
			proxyFileSize = 1,
			sufficientRenditionFoundOnOz = 1,
			volumeGuidUsedByOriginal = originalVolumeGuid,
			volumeGuidUsedByProxy = proxyVolumeGuid,
			xmpSidecarSize = 0,
		} } )
	
	-- delete the doc
	
	rxTest:expectOnlyCompleted( 
		WFCatDelete.deleteAssets( wfCatalog, { _docId } )
	)


	-- Get the trash doc
	local trashDoc
	rxTest:expectSingleValue( wfCatalog:docStore():docValue( _docId )
	:flatMap( function( deletedDocValue )
		return wfCatalog:docStore():docValue( deletedDocValue._newId )
	end )
	:map( function( docValue )
		trashDoc = docValue
		return type( docValue )
	end ), 'table' )

	-- Make sure there is an entry for the trash asset in _fileAccessDb.
	rxTest:expectSingleValue( fileAccessDb:waitUntilUpToDate(), true )

	rxTest:expectSingleValue( fileAccessDb:DEBUG_dumpLastAccessContents()
		:map( mapAwayLastAccessDate ),
		{ {
			localId = trashDoc._localId,
			docId = trashDoc._id,
			isImportant = 0,
			originalFileSize = 1,
			ozHasOriginal = 1,
			ozHasProxy = 1,
			proxyFileSize = 1,
			sufficientRenditionFoundOnOz = 0,
			volumeGuidUsedByOriginal = originalVolumeGuid,
			volumeGuidUsedByProxy = proxyVolumeGuid,
			xmpSidecarSize = 0,
		} } )

	-- permanently delete the doc

	rxTest:expectOnlyCompleted(
		WFCatDelete.deleteTrashAssets( wfCatalog, { trashDoc._id } )
	)

	-- Make sure it's no longer in the _fileAccessDb
	rxTest:expectSingleValue( fileAccessDb:waitUntilUpToDate(), true )
	
	rxTest:expectSingleValue( fileAccessDb:DEBUG_dumpLastAccessContents()
		:map( mapAwayLastAccessDate ), {} )
	
end

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

function NmbVolumeAgentTest.rxTestReactivelyPurgeSomeBinaries( rxTest )

	local overrides = {
		skipPurgeOfNMostRecentAssets = 0,
	}

	local purgeList = {
		proxies = {},
		originals = {}
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local reactivelyPurgeSomeBinaries = nmbVolumeAgent.private._reactivelyPurgeSomeBinaries

	local spaceToReclaim = 100
	
	-- Create one asset that can be purged.

	local optArgs = {
		originalOnly = true,
		size = spaceToReclaim,
	}

	createBasicDoc( rxTest, wfCatalog, optArgs )

	-- Wait until the file access DB is up to date.
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )

	-- Try to reclaim space using assets that have't been accessed in the given purge window.
	
	local purgeWindow = {
		beforeNDaysAgo = 10,
	}
	
	local reactivePurge = reactivelyPurgeSomeBinaries( 
			nmbVolumeAgent, 'original', defaultPurgeReason, true, spaceToReclaim, purgeWindow, purgeList )

	rxTest:expectSingleValue( reactivePurge, ':ignore:', 0 )
	
	-- Should not be able to purge this asset again.
	
	reactivePurge = reactivelyPurgeSomeBinaries( 
			nmbVolumeAgent, 'original', defaultPurgeReason, true, spaceToReclaim, purgeWindow, purgeList )

	rxTest:expectSingleValue( reactivePurge, ':ignore:', spaceToReclaim )

end

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

function NmbVolumeAgentTest.rxTestNothingToPurge( rxTest )

	local overrides = {
		skipPurgeOfNMostRecentAssets = 0,
	}

	local purgeList = {
		proxies = {},
		originals = {}
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local reactivelyPurgeSomeBinaries = nmbVolumeAgent.private._reactivelyPurgeSomeBinaries

	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.
		
	local ammountOfSpace = 100
	
	local purgeWindow = {
		beforeNDaysAgo = 10,
	}
	
	local reactivePurge = reactivelyPurgeSomeBinaries( 
			nmbVolumeAgent, 'original', defaultPurgeReason, true, ammountOfSpace, purgeWindow, purgeList )

	rxTest:expectSingleValue( reactivePurge, ':ignore:', 100 )

end

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

function NmbVolumeAgentTest.rxTestPurgeWindows( rxTest )

	local overrides = {
		skipPurgeOfNMostRecentAssets = 0,
	}

	local purgeList = {
		proxies = {},
		originals = {}
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local reactivelyPurgeSomeBinaries = nmbVolumeAgent.private._reactivelyPurgeSomeBinaries

	local spaceToReclaim = 300
	
	-- Create assets
	
	createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = spaceToReclaim / 3,
			lastAccessedOffsetInDays = 2,
		} )
		
	createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = spaceToReclaim / 3,
			lastAccessedOffsetInDays = 5,
		} )
	
	createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = spaceToReclaim / 3,
			lastAccessedOffsetInDays = 10,
		} )

	-- Wait until the file access DB is up to date.
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )

	local purgeWindow = {
		beforeNDaysAgo = 30,
	}

	local reactivePurge = reactivelyPurgeSomeBinaries( 
			nmbVolumeAgent, 'original', defaultPurgeReason, true, spaceToReclaim, purgeWindow, purgeList )

	-- Nothing should purge

	rxTest:expectSingleValue( reactivePurge, ':ignore:', spaceToReclaim )

	-- Increase purge window and try again.

	purgeWindow = {
		beforeNDaysAgo = 3,
	}

	reactivePurge = reactivelyPurgeSomeBinaries( 
			nmbVolumeAgent, 'original', defaultPurgeReason, true, spaceToReclaim, purgeWindow, purgeList )

	-- Should have purged 2 of the 3 binaries.

	rxTest:expectSingleValue( reactivePurge, ':ignore:', spaceToReclaim / 3 )

	-- Increase purge window and try again.

	purgeWindow = {
		beforeNDaysAgo = 1,
	}

	reactivePurge = reactivelyPurgeSomeBinaries( 
			nmbVolumeAgent, 'original', defaultPurgeReason, true, spaceToReclaim / 3, purgeWindow, purgeList )

	rxTest:expectSingleValue( reactivePurge, ':ignore:', 0 )

end

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

local function hasLocalOriginal( docStore, docId )

	return docStore:docValue( docId ):map( function( docValue )
			return WFCatFileSpec.getOriginalVolumeGuidFromDocValue( docValue ) and true or false
		end )

end

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

local function hasLocalProxy( docStore, docId )

	return docStore:docValue( docId ):map( function( docValue )
			return WFCatFileSpec.getProxyVolumeGuidFromDocValue( docValue ) and true or false
		end )

end

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

function NmbVolumeAgentTest.rxTestPurgeToReclaimSpace( rxTest )

	local overrides = {
		skipPurgeOfNMostRecentAssets = 0,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local purgeToReclaimSpace = nmbVolumeAgent.private._purgeToReclaimSpace

	local spaceToReclaim = 300
	local originalSize = spaceToReclaim / 3
	
	-- Create assets

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = originalSize,
			lastAccessedOffsetInDays = 2,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )
	
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.
		
	local purgeOriginals = true
	local purgeProxies = true

	local purgeObserver = rxTest:observe( purgeToReclaimSpace( nmbVolumeAgent, 1, purgeOriginals, purgeProxies, spaceToReclaim ) )

	-- Nothing should purge on the first pass ( 30 days )
	-- Nothing should purge on the next pass ( 15 days )
	-- 1 original should be purged on the next pass ( 7 days )
	-- Nothing should be purged on the next pass ( 5 days )
	-- 1 original should be purged on the next pass ( 3 days )
	-- 1 original should be purged on the next pass ( 2 days )
	
	local expectedSpaceStillNeeded = spaceToReclaim - 3 * originalSize

	purgeObserver:expectData( expectedSpaceStillNeeded ) 
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestPurgeToReclaimSpace_AllOrNothing( rxTest )

	local overrides = {
		skipPurgeOfNMostRecentAssets = 0,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local purgeToReclaimSpace = nmbVolumeAgent.private._purgeToReclaimSpace

	local spaceToReclaim = 500
	local originalSize = 100
	
	-- Create assets

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = originalSize,
			lastAccessedOffsetInDays = 2,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = true,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )

	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.

	local purgeOriginals = true
	local purgeProxies = true

	local purgeObserver = rxTest:observe( purgeToReclaimSpace( nmbVolumeAgent, 3, purgeOriginals, purgeProxies, spaceToReclaim ) )
	
	local expectedSpaceStillNeeded = spaceToReclaim - 3 * originalSize

	purgeObserver:expectData( expectedSpaceStillNeeded ) 
	
	-- Since the purge wasn't able to reclaim the space needed, nothing should have been removed
	-- from disk.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestDontPurgeAssetsFromOtherVolume( rxTest )

	local spaceToReclaim = 600
	local originalSize = spaceToReclaim / 6

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 1,
		timeLimit = 30
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	-- Create a bunch of assets that have both proxies and originals on disk

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = -1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
			originalVolumeGuid = externalVolumeGuid
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
			originalVolumeGuid = externalVolumeGuid
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 60,
			proxyVolumeGuid = externalVolumeGuid
		} )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
		
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) -- Most recently accessed asset should not be purged.
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true ) -- Don't purge, external volume.
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true ) -- Don't purge, external volume. 
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), false )
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), true ) -- Don't purge, external volume.
	
end

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

function NmbVolumeAgentTest.rxTestPurgeBuffer( rxTest )

	local spaceToReclaim = 30
	local originalSize = spaceToReclaim / 3

	local overrides = {
		debugSpaceNeededToReachTargetDiskSpace = spaceToReclaim,
		debugSpaceNeededToPreventNoDiskSpace = 0,
		minimumFreeSpace = 0,
		debugMockDiskFreeSpace = 670,
		debugMockNimbusSize = 330,
		skipPurgeOfNMostRecentAssets = 1,
	}

	-- The purge buffer is 10% of the max Nimbus size.
	
	-- Total space = 670 + 330 = 1000
	-- Max Nimbus Size = 1000 * 0.3 = 300
	-- Buffer size = 300 * 0.1 = 30
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	-- Create a bunch of assets that have both proxies and originals on disk

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = -1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 60,
		} )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
		
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	-- Most recently accessed asset should not be purged.
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	
	-- Should be purged because of no disk space.
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), false )
	
	-- Should be purged because of purge buffer.
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), false )
	
	-- Not purged!
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	
end

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

function NmbVolumeAgentTest.rxTest720pPurging( rxTest )

	local spaceToReclaim = 200
	local size = 100

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 1,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = size,
			lastAccessedOffsetInDays = -1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = size,
			lastAccessedOffsetInDays = 600,
			isVideo = true
		} )
	
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	-- Most recently accessed asset should not be purged.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	
	-- Original and SP should be purged for asset id2
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestDontPurgeMostRecent( rxTest )

	local spaceToReclaim = 100
	local originalSize = spaceToReclaim

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 1,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = -1,
		} )

	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
		
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	-- Most recenlty accessed asset should not be purged.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )

end

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

function NmbVolumeAgentTest.rxTestDontPurgeProtectedAssets_testNightly( rxTest )

	local spaceToReclaim = 600
	local originalSize = spaceToReclaim / 6

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 1,
		timeLimit = 30
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	-- Create a bunch of assets that have both proxies and originals on disk

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = -1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 60,
		} )
		
	-- Protect assets 4 and 5 from purging
	
	nmbVolumeAgent:protectFromPurge( { id4, id5 } )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
		
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	-- Most recently accessed asset should not be purged.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	
	-- Check Originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true ) -- Protected
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), true ) -- Protected
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true ) -- Protected
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), true ) -- Protected

	-- Release 4 and 5 from purging
	
	nmbVolumeAgent:releaseProtectionFromPurge( { id4, id5 } )
	
	local obs2 = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs2:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	-- Most recently accessed asset should not be purged.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	
	-- Check Originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), false )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), false )

end

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

local function getPurgeAssets( rxTest, wfCatalog, assetSize )

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 70,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 75,
		} )
		
	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 80,
		} )

	return id1, id2, id3, id4

end

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

local function removeVolume( status )

	status.volume = 'string'
	status.remainingSpace = nil
	return status

end

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

function NmbVolumeAgentTest.rxTestManaged_ReactivePurging_AboveTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Nimbus Size = 2000 * 0.3 = 600
	-- Purge Target = 600 * 0.90 = 540
	
	-- Expected Purge Amount = 1800 - 540 = 1260

	local assetSize = 1260 / 4 -- 4 assets should be purged

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestManaged_ReactivePurging_BelowTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 500 + 1500 = 2000
	-- Size of Proxies = 500 * 0.4 = 200
	-- Size of Originals = 500 * 0.6 = 300
	-- Max Nimbus Size = 2000 * 0.3 = 600
	-- Purge Target = 600 * 0.90 = 540
	
	-- Expected Purge Amount = 500 - 540 ~= 0

	local assetSize = 1

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestManaged_ReactivePurging_NoDiskSpace( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 1600,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 500 + 1500 = 2000
	-- Size of Proxies = 500 * 0.4 = 200
	-- Size of Originals = 500 * 0.6 = 300
	-- Max Nimbus Size = ( 2000 - 1600 ) * 0.3 = 120
	-- Purge Target = 120 * 0.90 = 108
	
	local assetSize = 200
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllOriginals_ReactivePurging_AboveTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllOriginals = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Proxy Size = ( 2000 - 1080 ) * 0.3 = 276
	-- Purge Target = 276 * 0.90 = 248.4
	
	-- Expected Purge Amount = 720 - 248.4 = 471.6

	local assetSize = 471.6 / 2 -- 2 assets should be purged

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllOriginals_ReactivePurging_BelowTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllOriginals = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 500 + 1500 = 2000
	-- Size of Proxies = 500 * 0.4 = 200
	-- Size of Originals = 500 * 0.6 = 300
	-- Max Proxy Size = ( 2000 - 300 ) * 0.3 = 510
	-- Purge Target = 510 * 0.90 = 459
	
	-- Expected Purge Amount = 200 - 459 ~= 0

	local assetSize = 1

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllOriginals_ReactivePurging_NoDiskSpace( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 1600,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllOriginals = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 500 + 1500 = 2000
	-- Size of Proxies = 500 * 0.4 = 200
	-- Size of Originals = 500 * 0.6 = 300
	-- Max Proxy Size = ( 400 - 300 ) * 0.3 = 30
	-- Purge Target = 30 * 0.90 = 27
	
	local assetSize = 173
		-- Just enough that purging asset will reach target disk space.
		-- 500 - 300 = 200 - 27 = 173
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllProxies_ReactivePurging_AboveTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllProxies = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Originals Size = ( 2000 - 720 ) * 0.3 = 384
	-- Purge Target = 384 * 0.90 = 345.6
	
	-- Expected Purge Amount = 1080 - 345.6 = 734.4

	local assetSize = 734.4 / 2 -- 2 assets should be purged

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllProxies_ReactivePurging_BelowTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllProxies = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 500 + 1500 = 2000
	-- Size of Proxies = 500 * 0.4 = 200
	-- Size of Originals = 500 * 0.6 = 300
	-- Max Originals Size = ( 2000 - 200 ) * 0.3 = 540
	-- Purge Target = 540 * 0.90 = 486
	
	-- Expected Purge Amount = 300 - 486 ~= 0

	local assetSize = 1

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllProxies_ReactivePurging_NoDiskSpace( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 1600,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllProxies = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 500 + 1500 = 2000
	-- Size of Proxies = 500 * 0.4 = 200
	-- Size of Originals = 500 * 0.6 = 300
	-- Max Originals Size = ( 400 - 200 ) * 0.3 = 60
	-- Purge Target = 60 * 0.90 = 54
	
	local assetSize = 246
		-- Just enough that purging asset will reach target disk space.
		-- 500 - 200 = 300 - 54 = 246
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestKeepEverything_ReactivePurging_AboveTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllProxies = true,
		keepAllOriginals = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	local assetSize = 100

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepEverything_ReactivePurging_BelowTargetThreshold( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllProxies = true,
		keepAllOriginals = true,
		debugDisableMaxSizePurgeableCheck = false,
	}

	local assetSize = 1

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepEverything_ReactivePurging_NoDiskSpace( rxTest )

	local overrides = {
		debugMockDiskFreeSpace = 1500,
		debugMockNimbusSize = 500,
		minimumFreeSpace = 1600,
		skipPurgeOfNMostRecentAssets = 1,
		debugReactivePurge = true,
		keepAllProxies = true,
		keepAllOriginals = true,
		debugDisableMaxSizePurgeableCheck = false,
	}
	
	local assetSize = 1
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local observer = rxTest:observe( nmbVolumeAgent:getVolumeStatusStream():map( removeVolume ) )
		
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = true,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = true,
	} )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Most recently accessed asset should not be purged.
		
	-- Check Originals
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check Proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestStopPurging_testNightly( rxTest )

	local spaceToReclaim = 100
	local originalSize = spaceToReclaim

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 1,
		timeLimit = 30
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	
	-- Create a bunch of assets that have both proxies and originals on disk

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 60,
		} )
		
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
		
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )

	-- Sleep again and expect the same results
	rxTest:sleep( 3 )

	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )

end

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

-- For the Proactive Purge Tests:

-- Originals make up 60% of size
-- Proxies make up 40% of size.
-- Target space value is 30% of free space.

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

function NmbVolumeAgentTest.rxTestProactivePurgeIgnoresImportantAssets( rxTest )

	local assetSize = 200

	local overrides = {
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Nimbus Size = 2000 * 0.3 = 600
	-- Purge Cutoff = 600 * 0.55 = 330
	
	-- Expected Purge Size For Originals = 100% = 1080
	
	-- Expected Purge Size For Proxies = 720 - 330 = 390

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	-- Create a bunch of assets that have both proxies and originals on disk
	
	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 70,
		} )

	rxTest:expectSingleValue(

		docStore:applyOverlay {
				_id = id2,
				reviews = {
					[ 'foo' ] = {
						flag = 'pick'
					},
				},
			},

		':ignore:' )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 10,
		} )
		
	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 70,
		} )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 10, true )
	
	nmbVolumeAgent:stop()
	
	-- Asset id2 is important and therefore should not be purged.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	
	-- Asset Id1 and Id3 should not be purged because they're too recently accessed.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	
	-- Asset Id4 should be purged
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestManaged_ProactivePurging_BelowIdleThreshold( rxTest )

	local assetSize = 100

	local overrides = {
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 1200,
		debugMockNimbusSize = 800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 1200 + 800 = 2000
	-- Size of Proxies = 800 * 0.4 = 320
	-- Size of Originals = 800 * 0.6 = 480
	-- Max Nimbus Size = 2000 * 0.3 = 600
	-- Purge Cutoff = 600 * 0.55 = 330
	
	-- Expected Purge Size For Originals = 100% = 480
	
	-- Expected Purge Size For Proxies = 320 < 330 = 0% = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestManaged_ProactivePurging_AboveTargetThreshold( rxTest )

	local assetSize = 200

	local overrides = {
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Nimbus Size = 2000 * 0.3 = 600
	-- Purge Cutoff = 600 * 0.55 = 330
	
	-- Expected Purge Size For Originals = 100% = 1080
	
	-- Expected Purge Size For Proxies = 720 - 330 = 390

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestManaged_ProactivePurging_BelowTargetThreshold( rxTest )

	local assetSize = 170

	local overrides = {
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 600,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 600 + 1800 = 2400
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Nimbus Size = 2400 * 0.3 = 720
	-- Purge Cutoff = 720 * 0.55 = 396
	
	-- Expected Purge Size For Originals = 100% = 1080
	
	-- Expected Purge Size For Proxies = 720 - 396 = 324

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllOriginals_ProactivePurging_BelowIdleThreshold( rxTest )

	local assetSize = 100

	local overrides = {
		keepAllOriginals = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 2200,
		debugMockNimbusSize = 800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 2200 + 800 = 3000
	-- Size of Proxies = 800 * 0.4 = 320
	-- Size of Originals = 800 * 0.6 = 480
	-- Max Proxy Size = ( 3000 - 480 ) * 0.3 = 756
	-- Purge Cutoff = 756 * 0.45 = 415.8
	
	-- Expected Purge Size For Originals = 0% = 0
	
	-- Expected Purge Size For Proxies = 320 < 415.8 = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllOriginals_ProactivePurging_AboveTargetThreshold( rxTest )

	local assetSize = 300

	local overrides = {
		keepAllOriginals = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Proxy Size = ( 2000 - 1080 ) * 0.3 = 276
	-- Purge Cutoff = 276 * 0.55 = 151.8
	
	-- Expected Purge Size For Originals = 0% = 0
	
	-- Expected Purge Size For Proxies = 720 - 151.8 = 568.2

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllOriginals_ProactivePurging_BelowTargetThreshold( rxTest )

	local assetSize = 155

	local overrides = {
		keepAllOriginals = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 1800,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 1800 + 1800 = 3600
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Max Proxy Size = ( 3600 - 1080 ) * 0.3 = 756
	-- Purge Cutoff = 756 * 0.55 = 415.8
	
	-- Expected Purge Size For Originals = 0% = 0
	
	-- Expected Purge Size For Proxies = 720 - 415.8 = 304.2

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), false )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllProxies_ProactivePurging_BelowIdleThreshold( rxTest )

	local assetSize = 100

	local overrides = {
		keepAllProxies = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 2200,
		debugMockNimbusSize = 800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 2200 + 800 = 3000
	-- Size of Proxies = 800 * 0.4 = 320
	-- Size of Originals = 800 * 0.6 = 480
	-- Purge Cutoff = 756 * 0.45 = 415.8
	
	-- Expected Purge Size For Originals = 100% = 480
	
	-- Expected Purge Size For Proxies = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllProxies_ProactivePurging_AboveTargetThreshold( rxTest )

	local assetSize = 300

	local overrides = {
		keepAllProxies = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Purge Cutoff = 276 * 0.55 = 151.8
	
	-- Expected Purge Size For Originals = 100% = 0
	
	-- Expected Purge Size For Proxies = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepAllProxies_ProactivePurging_BelowTargetThreshold( rxTest )

	local assetSize = 155

	local overrides = {
		keepAllProxies = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 1800,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 1800 + 1800 = 3600
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Purge Cutoff = 756 * 0.55 = 415.8
	
	-- Expected Purge Size For Originals = 100% = 1080
	
	-- Expected Purge Size For Proxies = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepEverything_ProactivePurging_BelowIdleThreshold( rxTest )

	local assetSize = 100

	local overrides = {
		keepAllProxies = true,
		keepAllOriginals = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 2200,
		debugMockNimbusSize = 800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 2200 + 800 = 3000
	-- Size of Proxies = 800 * 0.4 = 320
	-- Size of Originals = 800 * 0.6 = 480
	-- Purge Cutoff = 756 * 0.45 = 415.8
	
	-- Expected Purge Size For Originals = 0
	
	-- Expected Purge Size For Proxies = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()

	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepEverything_ProactivePurging_AboveTargetThreshold( rxTest )

	local assetSize = 300

	local overrides = {
		keepAllProxies = true,
		keepAllOriginals = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 200,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 200 + 1800 = 2000
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Purge Cutoff = 276 * 0.55 = 151.8
	
	-- Expected Purge Size For Originals = 0
	
	-- Expected Purge Size For Proxies = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestKeepEverything_ProactivePurging_BelowTargetThreshold( rxTest )

	local assetSize = 155

	local overrides = {
		keepAllProxies = true,
		keepAllOriginals = true,
		debugProactivePurge = true,
		debugMockDiskFreeSpace = 1800,
		debugMockNimbusSize = 1800,
		skipPurgeOfNMostRecentAssets = 0,
		minimumFreeSpace = 0,
		debugDisableMaxSizePurgeableCheck = false,
	}

	-- Total Space = 1800 + 1800 = 3600
	-- Size of Proxies = 1800 * 0.4 = 720
	-- Size of Originals = 1800 * 0.6 = 1080
	-- Purge Cutoff = 756 * 0.55 = 415.8
	
	-- Expected Purge Size For Originals = 0
	
	-- Expected Purge Size For Proxies = 0

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	local id1, id2, id3, id4 = getPurgeAssets( rxTest, wfCatalog, assetSize )
		
	local obs = rxTest:observe( nmbVolumeAgent:proactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
		-- Asset id1 is too recently accessed to be purged by proactive purge.
		
	-- Check originals
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	
	-- Check proxies
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestTargetDiskSpacePurging( rxTest )

	local spaceToReclaim = 500
	local assetSize = spaceToReclaim / 5

	local overrides = {
		debugSpaceNeededToReachTargetDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 1,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()
	
	-- Create a bunch of assets that have both proxies and originals on disk

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			assetSize = 0,
			lastAccessedOffsetInDays = 0,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 1,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 1,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 5,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 50,
		} )
	
	local obs = rxTest:observe( nmbVolumeAgent:reactivePurgeRunCompleteStream() )
	
	nmbVolumeAgent:start()
	
	obs:expectDataWithinTime( 5, true )
	
	nmbVolumeAgent:stop()
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
		-- Not purged because most recently accessed.
		
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), false )
		-- Purged!
		
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), false )
		-- Purged! ( least recently accessed of the proxies )
		
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true)
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
		-- Not purged because no need to purge!
		
end

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

function NmbVolumeAgentTest.rxTestVolumeStatusStream_NoSpace( rxTest )

	-- Create a no disk space scenario using the overrides.
	
	local totalDiskSize = gbToBytes( 50 )
	local nimbusSize = totalDiskSize
	
	local overrides = {
		debugMockNimbusSize = nimbusSize,
		debugMockDiskFreeSpace = totalDiskSize - nimbusSize,
	}

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	
	local statusStream = nmbVolumeAgent:getVolumeStatusStream()
	local observer = rxTest:observe( statusStream:map( removeVolume ) )
	
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = true,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = true,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestVolumeStatusStream_BelowTarget( rxTest )

	local totalDiskSize = gbToBytes( 50 )
	local nimbusSize = gbToBytes( 1 )
	
	local overrides = {
		debugMockNimbusSize = nimbusSize,
		debugMockDiskFreeSpace = totalDiskSize - nimbusSize,
		targetDiskSpaceUsage = NmbFileManagementSettings.targetNimbusDiskSpacePercentage(),
	}

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	
	local statusStream = nmbVolumeAgent:getVolumeStatusStream()
	local observer = rxTest:observe( statusStream:map( removeVolume ) )
	
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestVolumeStatusStream_BelowIdleTarget( rxTest )

	local totalDiskSize = gbToBytes( 50 )
	local targetNimbusSize = totalDiskSize * NmbFileManagementSettings.targetNimbusDiskSpacePercentage()
	local nimbusSize = targetNimbusSize - gbToBytes( 1 )
	
	local overrides = {
		debugMockNimbusSize = nimbusSize,
		debugMockDiskFreeSpace = totalDiskSize - nimbusSize,
		targetDiskSpaceUsage = NmbFileManagementSettings.targetNimbusDiskSpacePercentage(),
	}

	-- Proxies make up 40% of disk space.
	-- Target nimbus size = 50 * 0.25 = 12.5GB
	-- Size of Proxies: 12.5 * 0.4 = 5GB
	-- Max Idle Space For Proxies = 12.5 * 0.5 = 6.25

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	
	local statusStream = nmbVolumeAgent:getVolumeStatusStream()
	local observer = rxTest:observe( statusStream:map( removeVolume ) )
	
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestVolumeStatusStream_AboveIdleTarget( rxTest )

	local totalDiskSize = gbToBytes( 50 )
	local targetNimbusSize = totalDiskSize * ( NmbFileManagementSettings.targetNimbusDiskSpacePercentage() + 0.10 )
	local nimbusSize = targetNimbusSize - gbToBytes( 1 )
	
	local overrides = {
		debugMockNimbusSize = nimbusSize,
		debugMockDiskFreeSpace = totalDiskSize - nimbusSize,
		targetDiskSpaceUsage = NmbFileManagementSettings.targetNimbusDiskSpacePercentage(),
	}

	-- Proxies make up 40% of disk space.
	-- Target nimbus size = 50 * 0.35 = 17.5GB
	-- Size of Proxies: 17.5 * 0.4 = 7GB
	-- Max Idle Space For Proxies = 12.5 * 0.5 = 6.25

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	
	local statusStream = nmbVolumeAgent:getVolumeStatusStream()
	local observer = rxTest:observe( statusStream:map( removeVolume ) )
	
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = true,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestVolumeStatusStream_AboveTarget( rxTest )

	local totalDiskSize = gbToBytes( 50 )
	local targetNimbusSize = totalDiskSize * NmbFileManagementSettings.targetNimbusDiskSpacePercentage()
	local nimbusSize = targetNimbusSize + gbToBytes( 15 )
	
	local overrides = {
		debugMockNimbusSize = nimbusSize,
		debugMockDiskFreeSpace = totalDiskSize - nimbusSize,
		targetDiskSpaceUsage = NmbFileManagementSettings.targetNimbusDiskSpacePercentage()
	}

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	
	local statusStream = nmbVolumeAgent:getVolumeStatusStream()
	local observer = rxTest:observe( statusStream:map( removeVolume ) )
	
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = originalVolumeGuid,
		isOnline = true, 
		isOverIdleSpaceThreshold = true, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = true,
	} )
	
end

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

function NmbVolumeAgentTest.rxTestVolumeStatusStream_OfflineVolume( rxTest )

	local totalDiskSize = gbToBytes( 50 )
	local targetNimbusSize = totalDiskSize * NmbFileManagementSettings.targetNimbusDiskSpacePercentage()
	local nimbusSize = targetNimbusSize + gbToBytes( 1 )
	
	local overrides = {
		debugMockNimbusSize = nimbusSize,
		debugMockDiskFreeSpace = totalDiskSize - nimbusSize,
		volumeGuid = KSIdGenerator.uuidInLowercaseHex(),
		targetDiskSpaceUsage = NmbFileManagementSettings.targetNimbusDiskSpacePercentage()
	}

	local originalSize = 100

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	
	local statusStream = nmbVolumeAgent:getVolumeStatusStream()
	local observer = rxTest:observe( statusStream:map( removeVolume ) )
	
	createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 1,
		} )

	createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )

	createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )
	
	nmbVolumeAgent:start()

	observer:expectDataWithinTime( 5, {
		volume = 'string',
		volumeGuid = overrides.volumeGuid,
		isOnline = false, 
		isOverIdleSpaceThreshold = false, 
		isOutOfSpace = false,
		isReadOnly = false,
		isOverTargetDiskSpaceUsage = false,
	})
	
end

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

function NmbVolumeAgentTest.rxTestTryToClaimSpace_AtCapacity( rxTest )

	local spaceToReclaim = 150
	local assetSize = spaceToReclaim / 3

	local overrides = {
		debugMockDiskFreeSpace = 500,
		debugMockNimbusSize = 500,
		targetNimbusDiskSpacePercentage = 0.5,
		minimumFreeSpace = 500,
		skipPurgeOfNMostRecentAssets = 1,
	}

	-- For reactive purge, the purge buffer is 10% of the max Nimbus size
	
	-- Total space = 1000 = 1000
	-- Max Nimbus Size = 1000 * 0.5 = 500
	-- Buffer size = 500 * 0.10 = 50
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 60,
		} )
		
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim )
	
	rxTest:expectSingleValue( availableSpace, spaceToReclaim )
	
	-- Not purged because most recently accessed.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	
	-- Purged to reclaim the needed space.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), false )

	-- Not Purged
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestTryToClaimSpace_OverLimit( rxTest )

	local spaceToReclaim = 180
	local assetSize = spaceToReclaim / 3

	local overrides = {
		debugMockDiskFreeSpace = 0,
		debugMockNimbusSize = 1000,
		targetNimbusDiskSpacePercentage = 0.5,
		minimumFreeSpace = 60,
		skipPurgeOfNMostRecentAssets = 1,
	}

	-- For reactive purge, the purge buffer is 10% of the max Nimbus size
	
	-- Total space = 1000 = 1000
	-- Max Nimbus Size = 1000 * 0.5 = 500
	-- Buffer size = 500 * 0.10 = 50
	
	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = assetSize,
			lastAccessedOffsetInDays = 60,
		} )
	
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim )
	
	rxTest:expectSingleValue( availableSpace, spaceToReclaim )
	
	-- Not purged because most recently accessed.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	
	-- Purged to reclaim the needed space.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), false )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), false )
	
	-- Purged to get out of the no disk space state
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), false )
	
	-- Not Purged
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestTryToClaimSpace_NoOp( rxTest )

	local spaceToReclaim = 100
	local originalSize = spaceToReclaim

	-- Make it so Nimbus is well under capacity.
	
	local overrides = {
		debugMockDiskFreeSpace = 1900,
		debugMockNimbusSize = 100,
		targetNimbusDiskSpacePercentage = 0.5,
		minimumFreeSpace = 0,
		skipPurgeOfNMostRecentAssets = 1,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = -1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 60,
		} )
		
	-- Since Nimbus is under it's storage limit, the following should
	-- be a no-op.
	
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim )
	
	rxTest:expectSingleValue( availableSpace, spaceToReclaim )
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) -- Most recently accessed asset should not be purged.
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), true )
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestTryToClaimSpace_Fail( rxTest )

	local spaceToReclaim = 300
	local originalSize = spaceToReclaim / 3

	-- Make it so Nimbus is at capacity, but most assets are not purgeable.
	
	local overrides = {
		debugMockDiskFreeSpace = 1000,
		debugMockNimbusSize = 1000,
		targetNimbusDiskSpacePercentage = 0.75,
		minimumFreeSpace = 1000,
		skipPurgeOfNMostRecentAssets = 4,
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	local id1 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = -1,
		} )

	local id2 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 4,
		} )

	local id3 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 10,
		} )

	local id4 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 50,
		} )
		
	local id5 = createBasicDoc( rxTest, wfCatalog, 
		{
			originalOnly = false,
			size = originalSize,
			lastAccessedOffsetInDays = 60,
		} )
		
	-- The following should only be able to purge 200 of the 300 needed bytes.
	
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim )
	
	rxTest:expectSingleValue( availableSpace, 200 )
	
	-- Since it wasn't able to reclaim ALL of the needed space, and the purge was triggered
	-- via tryToClaimSpace, nothing should be purged. tryToClaimSpace is all or nothing.
	
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id1 ), true ) 
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id4 ), true )
	rxTest:expectSingleValue( hasLocalOriginal( docStore, id5 ), true )
	
	rxTest:expectSingleValue( hasLocalProxy( docStore, id1 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id2 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id3 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id4 ), true )
	rxTest:expectSingleValue( hasLocalProxy( docStore, id5 ), true )
	
end

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

function NmbVolumeAgentTest.rxTestTryToClaimSpace_SimultaneousQuery( rxTest )

	local _, nmbVolumeAgent = setupVolumeAgent( rxTest )

	local availableSpace1 = nmbVolumeAgent:tryToClaimSpace( 1 )
	local availableSpace2 = nmbVolumeAgent:tryToClaimSpace( 1 )
	
	-- Two clients are asking to claim space at the same time.
	
	local availableSpace = require 'Rx'.Observable.zip( availableSpace1, availableSpace2 )
		:map( function( space1, space2 )
			return true
		end )
	
	rxTest:expectSingleValue( availableSpace, true )
	
end

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

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

local performanceTestSize = 50000

function NmbVolumeAgentTest.DISABLED_rxTestReactiveCheckAndPurge_testPerformance( rxTest )

	local numberOfAssets = performanceTestSize
	local spaceToReclaim = numberOfAssets
	local originalSize = 1

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 0,
		timeLimit = 1000
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	logger:infof( "Adding assets..." )

	local docIds = createBasicDocsForPerformanceTest( rxTest, wfCatalog, numberOfAssets,
		{
			originalOnly = true,
			size = originalSize,
			isMarkedForOfflineUse = false,
			lastAccessedOffsetInDays = math.floor( math.random ( 1, 100 ) )
		} )

		
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.
		
	local startTime = KSDate.timeNow()
		
	logger:infof( "Starting Purge" )
		
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim, true )
	
	rxTest:expectSingleValue( availableSpace, spaceToReclaim )
	
	local endTime = KSDate.timeNow()
	
	local purgeDuration = endTime - startTime
	
	logger:infof( "Purge Complete in %.3f seconds", purgeDuration )
	
	-- Since it wasn't able to reclaim ALL of the needed space, and the purge was triggered
	-- via tryToClaimSpace, nothing should be purged. tryToClaimSpace is all or nothing.
	
	for i=1, numberOfAssets do 
	
		rxTest:expectSingleValue( hasLocalOriginal( docStore, docIds[ i ] ), false ) 
	
	end
	
end

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

function NmbVolumeAgentTest.DISABLED_rxTestReactiveCheckNoPurge_testPerformance( rxTest )

	local numberOfAssets = performanceTestSize
	local spaceToReclaim = numberOfAssets
	local originalSize = 1

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 0,
		timeLimit = 1000
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	logger:infof( "Adding assets..." )

	local docIds = createBasicDocsForPerformanceTest( rxTest, wfCatalog, numberOfAssets,
		{
			originalOnly = true,
			size = originalSize,
			isMarkedForOfflineUse = true,
			lastAccessedOffsetInDays = math.floor( math.random ( 1, 100 ) )
		} )
		
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.
		
	local startTime = KSDate.timeNow()
		
	logger:infof( "Starting Purge" )
		
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim, true )
	
	rxTest:expectSingleValue( availableSpace, 0 )
	
	local endTime = KSDate.timeNow()
	
	local purgeDuration = endTime - startTime
	
	logger:infof( "Purge Complete in %.3f seconds", purgeDuration )
	
	-- Since it wasn't able to reclaim ALL of the needed space, and the purge was triggered
	-- via tryToClaimSpace, nothing should be purged. tryToClaimSpace is all or nothing.
	
	for i=1, numberOfAssets do 
	
		rxTest:expectSingleValue( hasLocalOriginal( docStore, docIds[ i ] ), true ) 
	
	end
	
end

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

function NmbVolumeAgentTest.DISABLED_rxTestReactiveCheckExternalOriginals_testPerformance( rxTest )

	-- This tests purge performance on the main volume when the external volume contains
	-- many originals.

	local numberOfAssets = performanceTestSize
	local spaceToReclaim = numberOfAssets
	local originalSize = 1

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 0,
		timeLimit = 1000
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	logger:infof( "Adding assets..." )

	local docIds = createBasicDocsForPerformanceTest( rxTest, wfCatalog, numberOfAssets,
		{
			originalOnly = true,
			size = originalSize,
			originalVolumeGuid = 'ABCD_fakeVolumeGuid_EFGH',
			lastAccessedOffsetInDays = math.floor( math.random ( 1, 100 ) )
		} )
		
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.
		
	local startTime = KSDate.timeNow()
		
	logger:infof( "Starting Purge" )
		
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim, true )
	
	rxTest:expectSingleValue( availableSpace, 0 )
	
	local endTime = KSDate.timeNow()
	
	local purgeDuration = endTime - startTime
	
	logger:infof( "Purge Complete in %.3f seconds", purgeDuration )
	
	-- Since it wasn't able to reclaim ALL of the needed space, and the purge was triggered
	-- via tryToClaimSpace, nothing should be purged. tryToClaimSpace is all or nothing.
	
	for i=1, numberOfAssets do 
	
		rxTest:expectSingleValue( hasLocalOriginal( docStore, docIds[ i ] ), true ) 
	
	end
	
end

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

function NmbVolumeAgentTest.DISABLED_rxTestReactiveCheckUnsynced_testPerformance( rxTest )

	-- This tests purge performance when assets are not synced.

	local numberOfAssets = performanceTestSize
	local spaceToReclaim = numberOfAssets
	local originalSize = 1

	local overrides = {
		debugSpaceNeededToPreventNoDiskSpace = spaceToReclaim,
		skipPurgeOfNMostRecentAssets = 0,
		timeLimit = 1000
	}

	local wfCatalog, nmbVolumeAgent = setupVolumeAgent( rxTest, overrides )
	local docStore = wfCatalog:docStore()

	logger:infof( "Adding assets..." )

	local docIds = createBasicDocsForPerformanceTest( rxTest, wfCatalog, numberOfAssets,
		{
			originalOnly = true,
			size = originalSize,
			ozHasOriginal = false,
			lastAccessedOffsetInDays = math.floor( math.random ( 1, 100 ) )
		} )
		
	rxTest:expectSingleValue( wfCatalog:fileAccessDb():waitUntilUpToDate(), true )
		-- Wait until the file access DB is up to date.
		
	local startTime = KSDate.timeNow()
		
	logger:infof( "Starting Purge" )
		
	local availableSpace = nmbVolumeAgent:tryToClaimSpace( spaceToReclaim, true )
	
	rxTest:expectSingleValue( availableSpace, 0 )
	
	local endTime = KSDate.timeNow()
	
	local purgeDuration = endTime - startTime
	
	logger:infof( "Purge Complete in %.3f seconds", purgeDuration )
	
	-- Since it wasn't able to reclaim ALL of the needed space, and the purge was triggered
	-- via tryToClaimSpace, nothing should be purged. tryToClaimSpace is all or nothing.
	
	for i=1, numberOfAssets do 
	
		rxTest:expectSingleValue( hasLocalOriginal( docStore, docIds[ i ] ), true ) 
	
	end
	
end

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

if WFPlatformInfo.isMac or WFPlatformInfo.isWindows then
	return WFRxTestCase.wrapSuite( NmbVolumeAgentTest )
else
	return {}
end

