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

ADOBE CONFIDENTIAL
------------------
Copyright 2015 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 WFPlatformInfo = require 'WFPlatformInfo'

if WFPlatformInfo.isiOS then
	return {}
end

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

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local WFTableMerge = require 'WFTableMerge'

	-- WF.oz_client.sync_engine
local WFOzSyncConstants = require 'WFOzSyncConstants'

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

local LrmCoreInfoIndexDefinitions = require 'LrmCoreInfoIndexDefinitions'

local WFCatAssetTestUtils = require 'WFCatAssetTestUtils'

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

local LrmCatalogIndexDefinitionsTest = {}

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

local TEST_TIMEOUT = 10

local catalogOptions = {
	indexDefinitions = 'LrmCatalogIndexDefinitions.lua'
}

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

local function makeAssetDoc()

	return { 
		_localOnly = {
			thumbnail2x = {
				md5 = 'md5_hash',
			},
			preview = {
				md5 = 'md5_hash',
			},
			proxy = {
				filePath = '/originals/foo.jpeg',
			},
		}
	}
	
end

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

-- @mark coreInfo table

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfo_ignorePhotoWithoutRenditionsAndProxy( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	-- Add one "photo" to the doc store.

	local assetId = KSIdGenerator.uuidInLowercaseHex()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			width = 30,
			height = 20,
			captureDate = '2012-08-15T15:22:29',
		},
		':ignore:' )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			width = 30,
			height = 20,
			captureDate = '2012-08-15T15:22:29',
			_localOnly = {
				thumbnail2x = {
					md5 = 'foo',
				}
			}
		},
		':ignore:' )

		-- Query result should be empty because this photo did not
		-- contain a thumbnail reference.

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId	FROM coreInfo]],
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData(	{} )
		
end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfo_ImportedAssetWithReferencedMaster( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()
	
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local localUrl = KSIdGenerator.uuid()
	
		-- Add one "photo" to the doc store.
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
			},
			captureDate = '2012-08-15T15:22:29',
			_localOnly = {
				thumbnail2x = {
					md5 = 'md5_hash',
				},
				preview = {
					md5 = 'md5_hash',
				},
				localUrl = localUrl,
			},
		},
		':ignore:' )
		
	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId FROM coreInfo]],
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData(
		{
			{ assetId }
		} )
		
end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfo_FullAssetSet( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )
	
	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			userCreated = '2012-01-15T11:12:15',
			userUpdated = '2012-09-14T15:22:29',
			captureDate = '2012-08-15T15:22:29',
			_serverProvidedMetadata = {
				updated = '2012-09-15T15:22:29',
				importedByUser = {
					id = 'imported by someone',
				},
			},
			_localOnly = {
				thumbnail2x = {
					md5 = 'hash',
				},
				preview = {
					md5 = 'hash',
				},
				proxy = {
					filePath = 'originals/foo_proxy.jpeg',
				},
				localUrl = 'asset-url://file.dng',
			},
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
				fileName = 'File01.dng',
				importedBy = 'iPhone 10S',
				importTimestamp = '2012-01-15T11:12:15',
				copyTimestamp = '2013-11-09',
				linkedLocation = {
			            id = 'linked-location-1',
			            source = 'apple.icloud'
				}
			},
			reviews = {
				[ KSIdGenerator.uuidInLowercaseHex() ] = {
					flag = 'pick',
				},
			},
			ratings = {
				[ KSIdGenerator.uuidInLowercaseHex() ] = {
					rating = 5,
				},
			},
			xmp = {
					dc = {
					rights = 'Copyright',
				},
				exif = {
					ExposureTime = { 100, 1 },
					FNumber = { 100, 1 },
					ApertureValue = { 100, 1 },
					FocalLength = { 100, 1 },
					ISOSpeedRatings = 100,
				},
				tiff = {
					Make = 'Make',
					Model = 'Model',
				},
				aux = {
					Lens = 'Lens',
				}
			},
			develop = {
				croppedWidth = 25,
				croppedHeight = 20,
				xmpCameraRaw = '<xmp fooEdit=0 />',
				needsUpdateAISettings = true
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT 	aspectRatio, captureDate, displayDate,
						copyTimestamp, thumbnailMD5, importedBy, 
						contentType, wasDeveloped, croppedWidth, 
						croppedHeight, fileName, modifiedDate, 
						width, height, apertureValue, isoSpeedRatings, 
						exposureTime, cameraMaker, cameraModel, flag,
						rating, copyright, isVideo, localUrl, fnumber,
						importedByUser, syncStatus, linkedLocationId, linkedLocationSource, needsUpdateAISettings
				FROM coreInfo]],
				quiesceUntilUpToDate = true
		} )
	
	obs:expectDataWithinTime( 2, {
			{
				1.25, 			-- aspect ratio
				'2012-08-15T15:22:29', 	-- capture date
				'2012-08-15',		-- displayDate
				'2013-11-09',		-- copy timestamp
				'hash',			-- thumbnailMD5
				'iPhone 10S',		-- importedBy
				1000,			-- contentType
				1,			-- wasDeveloped
				25,			-- croppedWidth
				20,			-- croppedHeight
				'File01.dng',		-- fileName
				'2012-09-14T15:22:29',	-- modifiedDate
				30,			-- width
				20,			-- height
				'100.0',		-- apertureValue
				'100',			-- isoSpeedRatings
				'100',			-- exposureTime
				'Make',			-- cameraMaker
				'Model',		-- cameraModel
				'pick',			-- flag
				5,			-- rating
				'Copyright',		-- copyright
				0,			-- isVideo
				'asset-url://file.dng',	-- localUrl
				'100.0',		-- fnumber
				'imported by someone',	-- importedByUser
				1,			-- syncStatus
				'linked-location-1',	-- linkedLocationId
				'apple.icloud',		-- linkedLocationSource
				1	-- needsUpdateAISettings
			}
		} )
end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfo_VideoType( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'video',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			_localOnly = {
				thumbnail2x = {
					md5 = 'hash',
				},
				preview = {
					md5 = 'hash',
				},
				files ={
					proxies = {
						['1080p'] = {
							relativePath = 'originals/foo_proxy.jpeg',
						}
					}
				}
			},
			video = {
			},
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
				contentType = 'video/mp4',
			}
		} )
	
	local obs = rxTest:observe( indexStore:query{ sql =
			[[	
				SELECT 
					isVideo, contentType
				FROM 
					coreInfo
			]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData(
		{
			{
				1,
				2001
			}
		} )

end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfo_RatedAssetFromAnonymous( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
		-- Add one "photo" to the doc store.
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
			},
			captureDate = '2012-08-15T15:22:29',
			_localOnly = {
				thumbnail2x = {
					md5 = 'md5_hash',
				},
				preview = {
					md5 = 'md5_hash',
				},
				localUrl = KSIdGenerator.uuid(),
			},
			ratings = {
				[ WFOzSyncConstants.kGlobalDocumentId ] = {
					rating = 5,
				}
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, rating FROM coreInfo]],
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData(	{
			{ 
				assetId, 
				5 
			}
		} )
		
end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfo_ModifiedDate( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
				fileName = 'file1',
			},
			captureDate = '2012-08-15T15:22:29',
			_localOnly = {
				thumbnail2x = {
					md5 = 'md5_hash',
				},
				preview = {
					md5 = 'md5_hash',
				},
				localUrl = KSIdGenerator.uuid(),
			},
		},
		':ignore:' )

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId2,
			captureDate = '2012-08-15T15:22:29',
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
				importTimestamp = '2015-08-15',
				fileName = 'file2',
			},
			_localOnly = {
				thumbnail2x = {
					md5 = 'md5_hash',
				},
				preview = {
					md5 = 'md5_hash',
				},
				localUrl = KSIdGenerator.uuid(),
			},
		},
		':ignore:' )
		
	
	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId FROM coreInfo ORDER BY modifiedDate DESC, captureDate DESC, fileName DESC]],
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData(	{
			{ 
				assetId2
			},
			{
				assetId,
			}
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			userUpdated = '2015-08-17',
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId FROM coreInfo ORDER BY modifiedDate DESC, fileName DESC]],
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData(	{
			{ 
				assetId,
			},
			{
				assetId2,
			}
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId2,
			userUpdated = '2015-08-18',
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId FROM coreInfo ORDER BY modifiedDate DESC, fileName DESC]],
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData(	{
			{ 
				assetId2,
			},
			{
				assetId,
			}
		} )
		
end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfoForAdobeCameraImages( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
		-- Add one "photo" to the doc store.
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
			},
			captureDate = '2012-08-15T15:22:29',
			_localOnly = {
				thumbnail2x = {
					md5 = 'md5_hash',
				},
				preview = {
					md5 = 'md5_hash',
				},
				localUrl = KSIdGenerator.uuid(),
			},
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, isCapturedWithAdobeCamera FROM coreInfo]],
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData(	{
			{ 
				assetId, 
				0
			}
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			_id = assetId,
			xmp = {
				xmp = {
					CreatorTool = 'Adobe Camera 1.0',
				},
			}
		},
		':ignore:' )
		
	obs:expectData(	{
			{ 
				assetId, 
				1
			}
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			_id = assetId,
			xmp = {
				xmp = {
					CreatorTool = 5,
				},
			}
		},
		':ignore:' )
		
	obs:expectData(	{
			{ 
				assetId, 
				0
			}
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			_id = assetId,
			xmp = {
				xmp = {
					CreatorTool = 'Adobe Camera    3',
				},
			}
		},
		':ignore:' )
		
	obs:expectData(	{
			{ 
				assetId, 
				1
			}
		} )
		
end

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

function LrmCatalogIndexDefinitionsTest.rxTestCoreInfoIsDisplayable( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	-- asset without local binary and _serverProvidedMetadata links
	rxTest:expectEqual( false, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'image',
			_id = assetId
		}))
	
	-- asset has local master
	rxTest:expectEqual( true, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				localUrl = KSIdGenerator.uuid(),
			}
		}))
		
	rxTest:expectEqual( true, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				originalFilePath = "/originals/file.jpeg"
			}
		}))
		
	rxTest:expectEqual( true, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				latestOriginal = {
					filePath = "/originals/file.jpeg"
				}
			}
		}))
		
	-- asset has local proxy 
	rxTest:expectEqual( true, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				proxy = {
					filePath = "/originals/file_proxy.jpeg"
				}
			}
		}))
		
	-- asset has _serverProvidedMetadata links
	rxTest:expectEqual( true, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_serverProvidedMetadata = {
				links = {
					['/rels/proxy_type/2560'] = {
						href = 'catalogs/assets/revisions/proxies'
					},
					['/rels/master'] = {
						href = 'catalogs/assets/revisions/master'
					}
				}
			}
		}))
		
	rxTest:expectEqual( true, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'asset',
			subtype = 'video',
			_id = assetId,
			_serverProvidedMetadata = {
				links = {
					['/rels/proxy_type/2560'] = {
						href = 'catalogs/assets/revisions/proxies'
					},
					['/rels/master'] = {
						href = 'catalogs/assets/revisions/master'
					}
				}
			}
		}))
		
	-- Only support type asset
	rxTest:expectEqual( false, LrmCoreInfoIndexDefinitions.assetIsDisplayable(
		{
			type = 'album',
			subtype = 'collection',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			name = 'collection 2015',
			updated = '2012-08-15T15:22:29',
		}))
end

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

-- @mark album_asset table

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

function LrmCatalogIndexDefinitionsTest.rxTestAlbumAssets( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local albumId = KSIdGenerator.uuidInLowercaseHex()
	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local albumAssetId = KSIdGenerator.uuidInLowercaseHex()
	
	local docValue = makeAssetDoc()
	
	-- add asset
	
	docValue = WFTableMerge.applyOverlay( docValue, {
		type = 'asset',
		subtype = 'image',
		_id = assetId,
		importSource = {
			originalWidth = 200,
			originalHeight = 100,
		}
	} )
	
	rxTest:expectSingleValue( docStore:applyOverlay( docValue ),
		':ignore:' )
		
		
	-- add album_asset
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album_asset',
			_id = albumAssetId,
			album = {
				id = albumId,
			},
			asset = {
				id = assetId,
			}
		},
		':ignore:' )
	
	-- verify result in index store
	
	local obs = rxTest:observe( indexStore:query { 
		sql = [[SELECT 
					coreInfo.docId 
				FROM 
					coreInfo 
				LEFT JOIN 
					album_asset 
				ON 
					album_asset.assetId == coreInfo.docId 
				WHERE 
					albumId == ?]],
		quiesceUntilUpToDate = true,
		albumId
	} )
	
	obs:expectData( {
		{ assetId }
	} )
		
end

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

-- @mark albums table

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

function LrmCatalogIndexDefinitionsTest.rxTestAlbums( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local albumId1 = KSIdGenerator.uuidInLowercaseHex()
	local albumId2 = KSIdGenerator.uuidInLowercaseHex()
	local folderId1 = KSIdGenerator.uuidInLowercaseHex()
	local folderId2 = KSIdGenerator.uuidInLowercaseHex()
	local coverId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection',
			_id = albumId1,
			name = 'collection 2015',
			updated = '2012-08-15T15:22:29',
			-- parent not set
		},
		':ignore:' )
		
	-- Add two folders to the doc store.

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection_set',
			_id = folderId1,
			name = 'Folder 1',
			updated = '2017-07-20T15:22:29',
			-- parent not set
		},
		':ignore:' )

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection_set',
			_id = folderId2,
			name = 'Folder 2',
			updated = '2017-07-20T15:40:29',
			parent = {
				id = folderId1
			}
		},
		':ignore:' )

	-- Add another album to the doc store.

	rxTest:expectSingleValue ( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection',
			_id = albumId2,
			name = '   Collection 2014   ',
			updated = '2012-08-15T15:22:29',
			parent = {
				id = folderId2
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, name, nameLC, updateTimeStamp, localTimeStamp, useOffline, coverId, parentId, subtype FROM albums]],
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData( {
			{
				albumId1,
				'collection 2015',
				'collection 2015',
				'2012-08-15T15:22:29',
				nil,
				0,
				nil,
				'root',
				'collection'
			},
			{
				folderId1,
				'Folder 1',
				'folder 1',
				'2017-07-20T15:22:29',
				nil,
				0,
				nil,
				'root',
				'collection_set'
			},
			{
				folderId2,
				'Folder 2',
				'folder 2',
				'2017-07-20T15:40:29',
				nil,
				0,
				nil,
				folderId1,
				'collection_set'
			},
			{
				albumId2,
				'   Collection 2014   ',
				'collection 2014',
				'2012-08-15T15:22:29',
				nil,
				0,
				nil,
				folderId2,
				'collection'
			}
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection',
			_id = albumId2,
			_localOnly = {
				useOffline = true,
				updateTimeStamp = '2015-11-09',
			},
			updated = { _delete = true },
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, useOffline, localTimeStamp, updateTimeStamp FROM albums WHERE docId = ?]],
			albumId2,
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData( { 
			{
				albumId2,
				1,
				'2015-11-09',
				'2015-11-09'
			} 
		} )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection',
			_id = albumId2,
			_localOnly = {
				useOffline = true,
				updateTimeStamp = { _delete = true },
			},
			updated = { _delete = true },
			_serverProvidedMetadata = {
				updated = '2015-10-27',
			},
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, useOffline, localTimeStamp, updateTimeStamp FROM albums WHERE docId = ?]],
			albumId2,
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData(	{ 
			{
				albumId2,
				1,
				nil,
				'2015-10-27'
			} 
		} )
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'album',
			subtype = 'collection',
			_id = albumId2,
			cover = {
				id = coverId,
			}
		},
		':ignore:' )
		
	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, coverId FROM albums WHERE docId = ?]],
			albumId2,
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData(	{
			{
				albumId2,
				coverId,
			} 
		} )

end

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

function LrmCatalogIndexDefinitionsTest.rxTestHideInOrganize( rxTest )

	rxTest:setTimeLimit( 40 )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local albumId1 = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:expectSingleValue( docStore:applyOverlay {
		type = 'album',
		subtype = 'collection',
		_id = albumId1,
		name = 'collection 2015',
		updated = '2012-08-15T15:22:29',
		hideInOrganize = false
		
	},
	':ignore:' )
	
	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, hideInOrganize FROM albums]],
			quiesceUntilUpToDate = true
		}
		)
		
	obs:expectData( {
		{
			albumId1, 0
		}
	} )
	
	rxTest:expectSingleValue( docStore:applyOverlay {
		_id = albumId1,
		hideInOrganize = true
		
	},
	':ignore:' )
	
	obs:expectData( {
		{
			albumId1, 1
		}
	} )
	
	rxTest:expectSingleValue( docStore:applyOverlay {
		_id = albumId1,
		hideInOrganize = { _delete = true }
		
	},
	':ignore:' )
	
	obs:expectData( {
		{
			albumId1, 0
		}
	} )

end

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

-- @mark flags table

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

function LrmCatalogIndexDefinitionsTest.rxTestFlags( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	local userId = KSIdGenerator.uuidInLowercaseHex()

	local docValue = makeAssetDoc()

	docValue = WFTableMerge.applyOverlay( docValue, {
		type = 'asset',
		subtype = 'image',
		_id = assetId,
	} )

	rxTest:expectSingleValue( docStore:applyOverlay( docValue ),
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
	[[SELECT docId, flag FROM coreInfo]],
		quiesceUntilUpToDate = true
	} )

	obs:expectData( {
		{
			assetId,
			'unflagged'
		}
	} )


	docValue = makeAssetDoc()

	docValue = WFTableMerge.applyOverlay( docValue, {

		type = 'asset',
		subtype = 'image',
		_id = assetId,

		reviews = {
			[ userId ] = {
				date = '2015-11-09',
				flag = 'pick',
			}
		}

	} )

	rxTest:expectSingleValue( docStore:applyOverlay( docValue ),
		':ignore:')

	obs = rxTest:observe( indexStore:query{ sql =
	[[SELECT docId, flag FROM coreInfo]],
		quiesceUntilUpToDate = true
	} )

	obs:expectData( {
		{
			assetId,
			'pick'
		}
	} )

end

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

-- @mark space 

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

function LrmCatalogIndexDefinitionsTest.rxTestSpace( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local spaceId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'space',
			subtype = 'shared',
			_id = spaceId,
			private = false,
			download = false,
			updated = '2015-11-09',
			created = '2015-11-09'
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
				[[SELECT created, updateTimeStamp, private, download FROM space WHERE isDeleted == 0]],
				quiesceUntilUpToDate = true
			} )

	obs:expectData( {
			{
				'2015-11-09',
				'2015-11-09',
				0,
				0
			},
		} )
		
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'space',
			subtype = 'shared',
			_id = spaceId,
			updated = '2015-12-09',
			private = true,
		},
		':ignore:' )
		
	obs = rxTest:observe( indexStore:query{ sql =
				[[SELECT created, updateTimeStamp, private, download FROM space WHERE isDeleted == 0]],
				quiesceUntilUpToDate = true
			} )
		
	obs:expectData( {
			{
				'2015-11-09',
				'2015-12-09',
				1,
				0
			},
		} )

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'space',
			subtype = 'shared',
			_id = spaceId,
			created = { _delete = true },
			_localOnly = {
				created = '2014-01-10',
			}
		},
		':ignore:' )
		

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT created, updateTimeStamp, private, download FROM space WHERE isDeleted == 0]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				'2014-01-10',
				'2015-12-09',
				1,
				0
			},
		} )
	
end

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

-- @mark persons

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

function LrmCatalogIndexDefinitionsTest.rxTestPersons( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local personId = KSIdGenerator.uuidInLowercaseHex()
	local personId2 = KSIdGenerator.uuidInLowercaseHex()

	rxTest:expectSingleValue( docStore:applyOverlay {
			_id = personId,
			type = 'asset',
			subtype = 'person',
			_serverProvidedMetadata = {
				links = {
					['/rels/rendition_type/thumbnail2x'] = {
						href = '/v2/abc',
					}
				}
			},
			name = 'foo',
			hidden = true,
			primary = 'abc',
		},
		':ignore:' )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			_id = personId2,
			type = 'asset',
			subtype = 'person',
			_serverProvidedMetadata = {
				links = {
					['/rels/rendition_type/thumbnail2x'] = {
						href = '/v2/abc',
					}
				}
			},
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, name, hidden, primaryId, thumnailLink FROM persons ORDER BY name]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				personId2,
				'',
				0,
				'',
				'/v2/abc'
			},
			{
				personId,
				'foo',
				1,
				'abc',
				'/v2/abc'
			},
		} )
		
end

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

-- @mark avatarCacheReferences

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

function LrmCatalogIndexDefinitionsTest.rxTestCachedAvatars( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local feedbackuserId = KSIdGenerator.uuidInLowercaseHex()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'feedbackuser',
			_id = feedbackuserId,
			avatars = {
				small2x = {
					md5 = 'md5-hash',
					size = 1000,
					epoch = 1,
				}
			}
		},
		':ignore:' )
		
	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, md5, avatarType, size, epoch FROM avatarCacheReferences]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				feedbackuserId,
				'md5-hash',
				'small2x',
				1000,
				1
			},
		} )
		
end

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

-- @mark renditionRevision

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

function LrmCatalogIndexDefinitionsTest.rxTestRenditionRevisions_basic( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId_image = 'assetId_image'
	local assetId_video = 'assetId_video'

	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId_image,
			_localOnly = {
				files = {
					thumbnail2x = {},
					preview = {},
				}
			}
		} )
		
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'video',
			_id = assetId_video,
			_localOnly = {
				files = {
					thumbnail2x = {},
					preview = {},
				}
			}
		} )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT assetId, renditionName FROM renditionRevisions ORDER BY assetId, renditionName]],
			quiesceUntilUpToDate = true
		} )

	obs:expectDataWithinTime( 1, {} )
	
	-- Apply links without master link to image
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId_image,
			_localOnly = {
				thumbnail2x = {
					revId = '16b97d9d9e3042d09633c3878622d48b',
					renditionId = '835c23790d534b28b8b7bb99740d13bb',
				},
				preview = {
					revId = '16b97d9d9e3042d09633c3878622d48c',
					renditionId = '835c23790d534b28b8b7bb99740d13bc',
				},
			},
			_serverProvidedMetadata = {
				links = {
					[ '/rels/rendition_type/thumbnail2x' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/renditions/835c23790d534b28b8b7bb99740d13ba',
					},
					[ '/rels/rendition_type/2048' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/renditions/835c23790d534b28b8b7bb99740d13ba',
					},
					[ '/rels/proxy_type/2560' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/proxies/a5429e4c4bc7402bb8fb9102dbde4317'
					}
				},
			}
		} )
		
	obs:expectDataWithinTime( 1, {
			{
				assetId_image, 'preview',
			},
			{
				assetId_image, 'proxy',
			},
			{
				assetId_image, 'proxyWithoutMaster',
			},
			{
				assetId_image, 'thumbnail2x',
			}
		} )
	
	-- Apply links without master link to video
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'video',
			_id = assetId_video,
			_localOnly = {
				thumbnail2x = {
					revId = '16b97d9d9e3042d09633c3878622d48b',
					renditionId = '835c23790d534b28b8b7bb99740d13bb',
				},
				preview = {
					revId = '16b97d9d9e3042d09633c3878622d48c',
					renditionId = '835c23790d534b28b8b7bb99740d13bc',
				},
			},
			_serverProvidedMetadata = {
				links = {
					[ '/rels/rendition_type/thumbnail2x' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/renditions/835c23790d534b28b8b7bb99740d13ba',
					},
					[ '/rels/rendition_type/2048' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/renditions/835c23790d534b28b8b7bb99740d13ba',
					},
					[ '/rels/proxy_type/1080p' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/proxies/a5429e4c4bc7402bb8fb9102dbde4317'
					}
				},
			}
		} )
		
	obs:expectDataWithinTime( 1, {
			{
				assetId_image, 'preview',
			},
			{
				assetId_image, 'proxy',
			},
			{
				assetId_image, 'proxyWithoutMaster',
			},
			{
				assetId_image, 'thumbnail2x',
			},
			{
				assetId_video, 'preview',
			},
			{
				assetId_video, 'proxy',
			},
			{
				assetId_video, 'proxyWithoutMaster',
			},
			{
				assetId_video, 'thumbnail2x',
			}
		} )
		
	-- apply master links to image and video
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId_image,
			_serverProvidedMetadata = {
				links = {
					[ '/rels/master' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/master',
					}
				},
			}
		} )
		
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'video',
			_id = assetId_video,
			_serverProvidedMetadata = {
				links = {
					[ '/rels/master' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/master',
					}
				},
			}
		} )
	
	obs:expectDataWithinTime( 1, {
			{
				assetId_image, 'master',
			},
			{
				assetId_image, 'preview',
			},
			{
				assetId_image, 'proxy',
			},
			{
				assetId_image, 'thumbnail2x',
			},
			{
				assetId_video, 'master',
			},
			{
				assetId_video, 'preview',
			},
			{
				assetId_video, 'proxy',
			},
			{
				assetId_video, 'thumbnail2x',
			}
		} )
	
	-- Add file paths to image and video
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId_image,
			_localOnly = {
				thumbnail2x = {
					md5 = '<hash>',
					revId = '16b97d9d9e3042d09633c3878622d48a',
					renditionId = '835c23790d534b28b8b7bb99740d13ba',
				},
				preview = {
					md5 = '<hash>',
					revId = '16b97d9d9e3042d09633c3878622d48a',
					renditionId = '835c23790d534b28b8b7bb99740d13ba',
				},
				proxy = {
					filePath = '<path>',
				},
				originalFilePath = '<path>'
			}
		} )
		
	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'video',
			_id = assetId_video,
			_localOnly = {
				thumbnail2x = {
					md5 = '<hash>',
					revId = '16b97d9d9e3042d09633c3878622d48a',
					renditionId = '835c23790d534b28b8b7bb99740d13ba',
				},
				preview = {
					md5 = '<hash>',
					revId = '16b97d9d9e3042d09633c3878622d48a',
					renditionId = '835c23790d534b28b8b7bb99740d13ba',
				},
				files = {
					proxies = {
						['1080p'] = {
							relativePath = '<path>'
						}
					}
				},
				originalFilePath = '<path>'
			}
		} )

	obs:expectDataWithinTime( 1, {} )

end

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

function LrmCatalogIndexDefinitionsTest.rxTestRenditionRevisions_Aux( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local function sortResults( tbl )
	
		table.sort( tbl, function( a, b )
		
			if a[ 1 ] == b[ 1 ] then
			
				return a[ 2 ] > b[ 2 ]
			
			end
		
			return a[ 1 ] > b[ 1 ]
		
		end )
	
		return tbl
	
	end

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT assetId, renditionName FROM renditionRevisions ORDER BY assetId, renditionName]],
			quiesceUntilUpToDate = true
		}:map( sortResults ) )

	obs:expectDataWithinTime( 1, {} )

	-- Local Masks & Masks On Oz

	local optArguments = {
		hasDevelopAux = true
	}

	local docValue = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optArguments )

	rxTest:waitFor( docStore:setDocValue( docValue ) )

	local expected = {
		{
			docValue._id,
			'preview'
		},
		{
			docValue._id,
			'thumbnail2x'
		}
	}

	obs:expectDataWithinTime( 1, sortResults( expected ) )

	rxTest:waitFor( docStore:deleteDoc( docValue._id ) )

	-- Local Masks & No Masks On Oz

	optArguments = {
		hasDevelopAux = true,
		noDevelopAuxLinks = true
	}

	docValue = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optArguments )

	rxTest:waitFor( docStore:setDocValue( docValue ) )

	expected = {
		{
			docValue._id,
			'preview'
		},
		{
			docValue._id,
			'thumbnail2x'
		}
	}

	obs:expectDataWithinTime( 1, sortResults( expected ) )

	rxTest:waitFor( docStore:deleteDoc( docValue._id ) )
	
	-- No Local Masks & No Masks On Oz

	optArguments = {
		hasDevelopAux = true,
		noLocalDevelopAux = true,
		noDevelopAuxLinks = true
	}

	docValue = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optArguments )

	rxTest:waitFor( docStore:setDocValue( docValue ) )

	expected = {
		{
			docValue._id,
			'preview'
		},
		{
			docValue._id,
			'thumbnail2x'
		}
	}

	obs:expectDataWithinTime( 1, sortResults( expected ) )

	rxTest:waitFor( docStore:deleteDoc( docValue._id ) )

	-- No Local Masks & Masks On Oz

	-- This is the only case where the auxiliary objects should be emitted.
	
	optArguments = {
		hasDevelopAux = true,
		noLocalDevelopAux = true
	}

	docValue = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optArguments )

	rxTest:waitFor( docStore:setDocValue( docValue ) )

	expected = {
		{
			docValue._id,
			'preview'
		},
		{
			docValue._id,
			'thumbnail2x'
		},
		{
			docValue._id,
			'aux-proxy-2560'
		},
		{
			docValue._id,
			'aux-proxy-2560'
		},
		{
			docValue._id,
			'aux-proxy-2560'
		},
		{
			docValue._id,
			'aux-original'
		},
		{
			docValue._id,
			'aux-original'
		},
		{
			docValue._id,
			'aux-original'
		}
	}

	obs:expectDataWithinTime( 1, sortResults( expected ) )

	rxTest:waitFor( docStore:deleteDoc( docValue._id ) )

	-- no auxiliary objects should be emitted, because there is no develop settings link
	
	optArguments = {
		hasDevelopAux = true,
		noLocalDevelopAux = true,
		noDevelopSettingsLink = true
	}

	docValue = WFCatAssetTestUtils.createAssetDocument( rxTest, wfCatalog, nil, optArguments )

	rxTest:waitFor( docStore:setDocValue( docValue ) )

	expected = {
		{
			docValue._id,
			'preview'
		},
		{
			docValue._id,
			'thumbnail2x'
		}
	}

	obs:expectDataWithinTime( 1, sortResults( expected ) )

	rxTest:waitFor( docStore:deleteDoc( docValue._id ) )

end

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

function LrmCatalogIndexDefinitionsTest.rxTestRenditionRevisions_preferMaster( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				thumbnail2x = {
					revId = '16b97d9d9e3042d09633c3878622d48b',
					renditionId = '835c23790d534b28b8b7bb99740d13bb',
				},
				preview = {
					revId = '16b97d9d9e3042d09633c3878622d48c',
					renditionId = '835c23790d534b28b8b7bb99740d13bc',
				},
			},
			_serverProvidedMetadata = {
				links = {
					[ '/rels/rendition_type/thumbnail2x' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/renditions/835c23790d534b28b8b7bb99740d13ba',
					},
					[ '/rels/rendition_type/2048' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/renditions/835c23790d534b28b8b7bb99740d13ba',
					},
					[ '/rels/proxy_type/2560' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/proxies/a5429e4c4bc7402bb8fb9102dbde4317'
					},
					[ '/rels/master' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/master'
					}
				},
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT renditionName FROM renditionRevisions ORDER BY renditionName]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				'master',
			},
			{
				'preview',
			},
			{
				'proxy',
			},
			{
				'thumbnail2x',
			}
		} )

	rxTest:expectSingleValue( docStore:applyOverlay {
				type = 'asset',
				subtype = 'image',
				_id = assetId,
				importSource = {
					fileSize = 4000000,
				}
			},
			':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT renditionName FROM renditionRevisions ORDER BY renditionName]],
			quiesceUntilUpToDate = true
		} )


	obs:expectData( {
			{
				'master',
			},
			{
				'preview',
			},
			{
				'proxy',
			},
			{
				'thumbnail2x',
			}
		} )
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			doctype = 'image',
			_id = assetId,
			_localOnly = {
				thumbnail2x = {
					md5 = '<hash>',
					revId = '16b97d9d9e3042d09633c3878622d48a',
					renditionId = '835c23790d534b28b8b7bb99740d13ba',
				},
				preview = {
					md5 = '<hash>',
					revId = '16b97d9d9e3042d09633c3878622d48a',
					renditionId = '835c23790d534b28b8b7bb99740d13ba',
				},
				originalFilePath = '/var/foo/...',
			}
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT renditionName FROM renditionRevisions ORDER BY renditionName]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
		{
			'proxy',
		},
	} )
		
end

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

function LrmCatalogIndexDefinitionsTest.rxTestRenditionRevisions_masterAndProxySizeVideo( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()

	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'video',
			_id = assetId,
			importSource = {
				fileSize = 400000,
			},
			_localOnly = {
				thumbnail2x = {
					md5 = '<hash>',
				},
				preview = {
					md5 = '<hash>',
				},
			},
			_serverProvidedMetadata = {
				links = {
					[ '/rels/master' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/master',
					},
					[ '/rels/proxy_type/1080p' ] = {
						href = 'catalogs/f50509f546184519afa38d4e55e442fc/assets/496e4bec7eff1bee558b4760ae00efa3/revisions/16b97d9d9e3042d09633c3878622d48a/proxies/5dcae4af',
						fileSize = 37664,
					}
				}
			}
		} )

	local obs = rxTest:observe( indexStore:query { sql =
			[[SELECT renditionName, size FROM renditionRevisions ORDER BY renditionName]],
			quiesceUntilUpToDate = true
		} )
		
	obs:expectDataWithinTime( 1, { { 'master', 400000 }, { 'proxy', 37664 } } )

end

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

-- @mark assetProfileLink

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

function LrmCatalogIndexDefinitionsTest.rxTestAssetProfileLink( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				thumbnail2x = {
					md5 = 'hash'
				},
				preview = {
					md5 = 'hash',
				},
				proxy = {
					filePath = 'originals/foo_proxy.jpeg',
				},
			},
			develop = {
				profiles = {
					camera = {
						href = '/v2/foo/master',
						filename = 'Adobe Standard.dcp',
					}
				}
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT subtype, fileName, masterUrl, uniqueId FROM assetProfileLinks]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				'camera',
				'Adobe Standard.dcp',
				'/v2/foo/master',
				'/v2/foo/master',
			}
		} )
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			develop = {
				profiles = {
					lens = {
						href = '/v2/foo/master',
						filename = 'Adobe Standard.lcp',
						
					}
				}
			}
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT subtype, fileName, masterUrl, uniqueId FROM assetProfileLinks ORDER BY subtype]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				'camera',
				'Adobe Standard.dcp',
				'/v2/foo/master',
				'/v2/foo/master',
			},
			{
				'lens',
				'Adobe Standard.lcp',
				'/v2/foo/master',
				'/v2/foo/master',
			}
		} )

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			develop = {
				profiles = {
					lens = {
						href = 'foo/master',
						filename = 'Adobe Standard.lcp',
						
					}
				}
			}
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			'SELECT subtype, fileName, masterUrl, uniqueId FROM assetProfileLinks ORDER BY subtype',
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData( {
			{
				'camera',
				'Adobe Standard.dcp',
				'/v2/foo/master',
				'/v2/foo/master',
			},
		} )		
	
	-- test invalid lens profile href
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			develop = {
				profiles = {
					lens = {
						href = 'foo/master',
						filename = { _delete = true }
					}
				}
			}
		},
		':ignore:' )
	
	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT subtype, fileName, masterUrl, uniqueId FROM assetProfileLinks ORDER BY subtype]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData( {
			{
				'camera',
				'Adobe Standard.dcp',
				'/v2/foo/master',
				'/v2/foo/master',
			},
		} )
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			develop = {
				profiles = {
					camera = {
						_delete = true,
					}
				}
			}
		},
		':ignore:' )
		
	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT subtype, fileName, masterUrl, uniqueId FROM assetProfileLinks ORDER BY subtype]],
			quiesceUntilUpToDate = true
		} )
		
	obs:expectData( {} )
	
end

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

-- @mark profileRegistration

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

function LrmCatalogIndexDefinitionsTest.rxTestProfileRegistration( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'profile',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			_localOnly = {
				subtype = 'camera',
				fileName = 'Adobe Standard Camera Landscape.dcp',
				uniqueId = 'foo/master',
			}
		},
		':ignore:' )
		
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'profile',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			_localOnly = {
				subtype = 'lens',
				fileName = 'Nikon D3200.lcp',
				uniqueId = 'foo/master',
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT subtype, fileName, uniqueId FROM profileRegistration ORDER BY subtype]],
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData( {
			{
				'camera',
				'Adobe Standard Camera Landscape.dcp',
				'foo/master'
			},
			{
				'lens',
				'Nikon D3200.lcp',
				'foo/master'
			},
		} )
		
end

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

-- @mark importSource

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

function LrmCatalogIndexDefinitionsTest.rxTestImportSource_withLocalUrl( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId = KSIdGenerator.uuidInLowercaseHex()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				localUrl = '1234',
			},
			importSource = {
				sha256 = '5678',
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT localUrl, sha256 FROM coreInfo]],
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData( {
			{
				'1234',
				'5678',
			},
		} )
	
	--[[ TODO [immisch 2016-04-18]: This test fails, because the new docstore does not allow the deletion of 
	  _localOnly:
	
		\b Important: The top-level key \c _localOnly gets special handling. If
		no value is provided for this key, any previous value is left in place.
		This behavior does not apply to any other key. This does imply that you
		can not delete any existing \c _localOnly entry in the document.
	
	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				_delete = true,
			}
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			'SELECT localUrl FROM importSource',
			quiesceUntilUpToDate = true
		} )
	
	obs:expectData( {
			{},
		} )

	]]--

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'image',
			_id = assetId,
			_localOnly = {
				localUrl = '9876',
			},
			importSource = {
				_delete = true,
			}
		},
		':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT localUrl, sha256 FROM coreInfo]],
			quiesceUntilUpToDate = true
		},
		':ignore:'
 	)
	
	obs:expectData( {
			{ '9876' },
		} )
		
end

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

-- @mark presetsProfiles

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

function LrmCatalogIndexDefinitionsTest.rxTestPresetsAndProfiles( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	local assetId1 = KSIdGenerator.uuidInLowercaseHex()
	local assetId2 = KSIdGenerator.uuidInLowercaseHex()
	local assetId3 = KSIdGenerator.uuidInLowercaseHex()

	-- Create a remote preset and a remote profile

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'preset',
			_id = assetId1,
			_serverProvidedMetadata = {
				links =  {
					[ '/rels/master' ] = {
						href = "foo"
					}
				}
			},
			name = "a preset",
			importSource = {
				sha256 = '1234',
			}
		},
		':ignore:' )

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'profile',
			_id = assetId2,
			_serverProvidedMetadata = {
				links =  {
					[ '/rels/master' ] = {
						href = "bar"
					}
				}
			},
			name = "a profile",
			importSource = {
				sha256 = '5678',
			}
		},
		':ignore:' )

	-- Create a local preset which needs no saving

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'preset',
			_id = assetId3,
			name = "local preset",
			_localOnly = {
				files = {
					presetProfile = {
						path = 'some localpath',
						sha256 = '4444'
					},
				},
			},
			importSource = {
				sha256 = '4444',
			}
		},
		':ignore:' )

	local obs = rxTest:observe( indexStore:query{ sql =
			[[SELECT docId, sha256 FROM presetsProfiles where needsSave = 1 ]],
			quiesceUntilUpToDate = true
		})

	obs:expectData( {
			{
				assetId1,
				'1234',
			},
			{
				assetId2,
				'5678',
			},
		} )

	obs:dispose()

	-- Locally save the preset from remote

	rxTest:expectSingleValue( docStore:applyOverlay {
		_id = assetId1,
		_localOnly = {
			files = {
				presetProfile = {
					path = 'localpath',
					sha256 = '1234'
				},
			},
		},
	},
	':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
		[[SELECT docId, sha256 FROM presetsProfiles where needsSave = 1 ]],
		quiesceUntilUpToDate = true
	})

	obs:expectData( {
			{
				assetId2,
				'5678',
			},
		} )

	obs:dispose()

	-- Remote updates the preset, master link not yet updated

	rxTest:expectSingleValue( docStore:applyOverlay {
		_id = assetId1,
		_serverProvidedMetadata = {
			links =  {
				[ '/rels/master' ] = {
					href = "foo",
					invalid = true,
				}
			}
		},
		importSource = {
			sha256 = '2345',
		},
	},
	':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
		[[SELECT docId, sha256 FROM presetsProfiles where needsSave = 1 ]],
		quiesceUntilUpToDate = true
	} )

	obs:expectData( {
			{
				assetId2,
				'5678',
			},
		} )

	obs:dispose()

	-- Remote updates the preset, new master link available

	rxTest:expectSingleValue( docStore:applyOverlay {
		_id = assetId1,
		_serverProvidedMetadata = {
			links =  {
				[ '/rels/master' ] = {
					href = "new foo",
					invalid = { _delete = true },
				},
			}
		},
		importSource = {
			sha256 = 'deadbeef',
		},

	},
	':ignore:' )

	obs = rxTest:observe( indexStore:query{ sql =
		[[SELECT docId, sha256 FROM presetsProfiles where needsSave = 1 ]],
		quiesceUntilUpToDate = true
	} )

	obs:expectData( {
		{
			assetId2,
			'5678',
		},
		{
			assetId1,
			'deadbeef',
		},
	} )

end

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

-- @mark trashAssets

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

function LrmCatalogIndexDefinitionsTest.rxTestTrashAssets_FullAssetSet( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	rxTest:expectSingleValue( docStore:applyOverlay {
			type = 'asset',
			subtype = 'deleted_image',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			purgeDate = '2018-12-06T21:25:33.078Z',
			userCreated = '2012-01-15T11:12:15',
			userUpdated = '2012-09-14T15:22:29',
			captureDate = '2012-08-15T15:22:29',
			_serverProvidedMetadata = {
				updated = '2012-09-15T15:22:29',
				importedByUser = {
					id = 'imported by someone'
				},
			},
			_localOnly = {
				thumbnail2x = {
					md5 = 'hash',
				},
				preview = {
					md5 = 'hash',
				},
				proxy = {
					filePath = 'originals/foo_proxy.jpeg',
				},
				localUrl = 'asset-url://file.dng',
			},
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
				fileName = 'File01.dng',
				importedBy = 'iPhone 10S',
				importTimestamp = '2012-01-15T11:12:15',
				hasEmbeddedDepthMap = true,
				camera = {
					name = "A camera maker",
				},
				lens = {
					name = "A lens"
				},
			},
			reviews = {
				[ KSIdGenerator.uuidInLowercaseHex() ] = {
					flag = 'pick',
				},
			},
			ratings = {
				[ KSIdGenerator.uuidInLowercaseHex() ] = {
					rating = 5,
				},
			},
			xmp = {
					dc = {
					rights = 'Copyright',
				},
				exif = {
					ExposureTime = { 100, 1 },
					FNumber = { 100, 1 },
					ApertureValue = { 100, 1 },
					FocalLength = { 100, 1 },
					ISOSpeedRatings = 100,
					FlashFired = true,
				},
				tiff = {
					Make = 'Make',
					Model = 'Model',
				},
				aux = {
					IsMergedPanorama = true,
					Lens = 'Lens',
				}
			},
			develop = {
				croppedWidth = 25,
				croppedHeight = 20,
				xmpCameraRaw = '<xmp fooEdit=0 />',
				userOrientation = 6,
				userUpdated = '2012-01-18T11:12:15'
			}
		},
		':ignore:' )

	if WFPlatformInfo.isAndroid then
	
		local obs = rxTest:observe( indexStore:query{ sql =
				[[SELECT 	
						purgeDate, thumbnailMD5, captureDate, importTimestamp, modifiedDate, 
						contentType, duration, flag, rating,
						croppedWidth, croppedHeight, fileName, width, height, 
						apertureValue, isoSpeedRatings, exposureTime, fnumber, 
						cameraMaker, cameraModel, isVideo, localUrl, isMergedHDR, hasThumbnail,
						importedByUser, syncStatus
					FROM trashAssets]],
					quiesceUntilUpToDate = true
			} )

		obs:expectData( {
			{
				'2018-12-06T21:25:33.078Z',		-- purgeDate
				'hash',							-- thumbnailmd5
				'2012-08-15T15:22:29', 			-- capture date
				'2012-01-15T11:12:15',			-- timestamp
				'2012-09-14T15:22:29',			-- modifiedDate
				1000,							-- contentType
				nil,							-- duration
				'pick',							-- flag
				5,								-- rating
				25,								-- croppedWidth
				20,								-- croppedHeight
				'File01.dng',					-- fileName
				30,								-- width
				20,								-- height
				'100.0',						-- apertureValue
				'100',							-- isoSpeedRatings
				'100',							-- exposureTime
				'100.0',						-- fnumber
				'Make',							-- cameraMaker
				'Model',						-- cameraModel
				0,								-- isVideo
				'asset-url://file.dng',			-- localUrl
				0,								-- isMergedHDR
				1,								-- hasThumbnail
				'imported by someone',			-- importedByUser
				1,
			}
		} )
		
	end

end

function LrmCatalogIndexDefinitionsTest.rxTestTrashAssets_VideoType( rxTest )

	rxTest:setTimeLimit( TEST_TIMEOUT )

	local wfCatalog = WFCatMockCatalog.createFakeWFCatalog( rxTest, nil, nil, catalogOptions )
	
	local docStore = wfCatalog:docStore()
	local indexStore = wfCatalog:indexStore()

	rxTest:waitFor( docStore:applyOverlay {
			type = 'asset',
			subtype = 'deleted_video',
			_id = KSIdGenerator.uuidInLowercaseHex(),
			_localOnly = {
				thumbnail2x = {
					path = 'blobs/...',
				},
				preview = {
					path = 'blobs/...',
				},
				files = {
					proxies = {
						['1080p'] = {
							relativePath = 'originals/foo_proxy.jpeg',
						}
					}
				}
			},
			purgeDate = '2018-12-06T21:25:33.078Z',
			video = {
			},
			importSource = {
				originalWidth = 30,
				originalHeight = 20,
				contentType = 'video/mp4',
			}
		} )
	
	local obs = rxTest:observe( indexStore:query{ sql =
			[[	
				SELECT 
					purgeDate, captureDate, importTimestamp, modifiedDate, 
					contentType, duration, flag, rating,
					croppedWidth, croppedHeight, fileName, width, height, 
					apertureValue, isoSpeedRatings, exposureTime, fnumber, 
					cameraMaker, cameraModel, isVideo, localUrl, isMergedHDR
				FROM 
					trashAssets
			]],
			quiesceUntilUpToDate = true
		} )

	obs:expectData(
		{
			{
				'2018-12-06T21:25:33.078Z',		-- purgeDate
				nil, 							-- capture date
				nil,							-- timestamp
				nil,							-- modifiedDate
				2001,							-- contentType
				nil,							-- duration
				'unflagged',					-- flag
				0,								-- rating
				30,								-- croppedWidth
				20,								-- croppedHeight
				nil,							-- fileName
				30,								-- width
				20,								-- height
				"",								-- apertureValue
				"",								-- isoSpeedRatings
				"",								-- exposureTime
				"",								-- fnumber
				nil,							-- cameraMaker
				nil,							-- cameraModel
				1,								-- isVideo
				nil,							-- localUrl
				0,								-- isMergedHDR
			}
		} )

end

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

return WFRxTestCase.wrapSuite( 'LrmCatalogIndexDefinitionsTest', LrmCatalogIndexDefinitionsTest )

