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

NmbErrorHandlerTest.lua

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

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

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

local WFRxTestCase = require 'WFRxTestCase'
local WFRxTestUtils = require 'WFRxTestUtils'
local WFCatSpecMock = require 'WFCatSpecMock'
local WFCatMockCatalog = require 'WFCatMockCatalog'
local WFMockHttpRequest = require 'WFMockHttpRequest'

local WFCatOzErrors = require 'WFCatOzErrors'

local KSData = require 'KSData'
local KSIdGenerator = require 'KSIdGenerator'
local WFFileUtils = require 'WFFileUtils'
local WFPlatformInfo = require 'WFPlatformInfo'

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

local NmbErrorHandlerTest = {}

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

-- these are LrCC only tests, so don't run them on iOS or Android
if not WFPlatformInfo.isiOS and not WFPlatformInfo.isAndroid then

-- this require may fail on iOS and Android due to dependencies so it's moved inside the if
local NmbErrorHandler = require 'NmbErrorHandler'

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

local function fileCleanup( rxTest, path )
	
	rxTest:finally( function()
		WFFileUtils.delete( path )
	end )
	
end

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

local function stripWobblyBitsAndSPMFromDocValue( docValue )
	docValue._localId = nil
	docValue._revId = nil
	docValue._changeCounter = nil
	docValue._serverProvidedMetadata = nil
	docValue._labels = nil
	return docValue
end

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

local function presetDocJsonFromOzWith( id, maybeRevisions, maybeName, maybeSha256 )
	
	maybeRevisions = maybeRevisions or { '22ceb6dc1bfb47ae95c2094bbd3e726f' }
	
	local revisions = ""
	for i = 1,#maybeRevisions - 1,1 do
		revisions = revisions .. [["]] .. maybeRevisions[ i ] .. [["]] .. ", "
	end
	revisions = revisions .. [["]] .. maybeRevisions[ #maybeRevisions ] .. [["]]
	return [[while (1) {} {
				"base":"https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				"id":"]] .. id .. [[",
				"updated":"2018-04-16T20:25:29.670356Z",
				"created":"2018-04-16T20:25:15.902592Z",
				"type":"asset",
				"subtype":"preset",
				"revision_ids": []] .. revisions .. [[],
				"links":{"self":{"href":"assets/7b12cf2c0f6944c0a1d884b6653992ec"},
						"/rels/master_create": {"href":"assets/7b12cf2c0f6944c0a1d884b6653992ec/revisions/{revision_id}/master","templated":true},
						"/rels/master":{"href":"assets/7b12cf2c0f6944c0a1d884b6653992ec/revisions/22ceb6dc1bfb47ae95c2094bbd3e726f/master","content_type":"application/rdf+xml"
						}},
				"payload":{
					"userUpdated":"2018-04-16T20:25:13.488Z",
					"name":"]] .. ( maybeName or 'Test' ) .. [[",
					"importSource":
						{
						"fileSize":3937,
						"contentType":"application/rdf+xml",
						"sha256": "]] .. ( maybeSha256 or '5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2' ).. [["
						},
					"userCreated":"2018-04-16T20:25:13.488Z",
					"captureDate":"0000-00-00T00:00:00"
				}}]]
end

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

-- @mark PreconditionFailed

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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_NoLocalMatchingDoc( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )
	
	local errorHandler = NmbErrorHandler( catalog )

	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	-- create some dummy data at the path to the preset
	local presetPath = catalog:fileSpec():pathForStyle( presetId )

	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	local preexistingPresetPath = catalog:fileSpec():pathForStyle( preexistingPresetId )
	fileCleanup( rxTest, preexistingPresetPath )

	local preexistingPresetRelativePath = WFFileUtils.removeVolumeFromPath( preexistingPresetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
	
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
		
	-- duplicate doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, presetId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should have a local master
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			captureDate = "0000-00-00T00:00:00",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
	
end

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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_LocalMatchingDocNoMaster( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )
			
	local errorHandler = NmbErrorHandler( catalog )

	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()
	
	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	local preexistingPresetPath = catalog:fileSpec():pathForStyle( preexistingPresetId )
	fileCleanup( rxTest, preexistingPresetPath )

	local preexistingPresetRelativePath = WFFileUtils.removeVolumeFromPath( preexistingPresetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	fileCleanup( rxTest, presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
	
	-- create basic preexisting preset doc that came from Oz, but has no master file locally (we're skipping the _spm here
	-- which should be fine)
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = preexistingPresetId,
			_newRevId = "22ceb6dc1bfb47ae95c2094bbd3e726f",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		},
		':ignore:' )
	
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- duplicate doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, presetId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should have master attached
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			captureDate = "0000-00-00T00:00:00",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
	
end

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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_LocalMatchingDocWithMaster( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )
	
	local errorHandler = NmbErrorHandler( catalog )

	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
		
	-- make the preexisting path a custom filename so that we know that it's not been copied over from the 
	-- dupe and changed
	local preexistingPresetPath = catalog:fileSpec():pathForStyle( preexistingPresetId ) .. "-test"
	fileCleanup( rxTest, preexistingPresetPath )

	local preexistingPresetRelativePath = WFFileUtils.removeVolumeFromPath( preexistingPresetPath )
	
	-- create some dummy data at the path to the preexisting preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), preexistingPresetPath )
	
	-- create basic preexisting preset doc that came from Oz that also has a master file
	-- which should be fine)
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = preexistingPresetId,
			_newRevId = "22ceb6dc1bfb47ae95c2094bbd3e726f",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		},
		':ignore:' )
	
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- duplicate doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, presetId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should have original master attached - it should not have been copied over
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			captureDate = "0000-00-00T00:00:00",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
	
end

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


function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_LocalMatchingDocAnnotationMissingMaster( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )
	
	local errorHandler = NmbErrorHandler( catalog )

	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
		
	local preexistingPresetPath = catalog:fileSpec():pathForStyle( preexistingPresetId )
	fileCleanup( rxTest, preexistingPresetPath )

	local preexistingPresetRelativePath = WFFileUtils.removeVolumeFromPath( preexistingPresetPath )
	
	-- create basic preexisting preset doc that came from Oz that has a master file annotation,
	-- but the master file doesn't actually exist
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = preexistingPresetId,
			_newRevId = "22ceb6dc1bfb47ae95c2094bbd3e726f",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		},
		':ignore:' )
	
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- duplicate doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, presetId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should have original master attached - it should not have been copied over
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			captureDate = "0000-00-00T00:00:00",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
	
end

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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_MatchingDocWithConflict( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )

	local conflictResolver = require 'WFCatConflictResolver'( catalog:docStore(), catalog:indexStore() )
	rxTest:addCloseTarget( conflictResolver )	
	
	local errorHandler = NmbErrorHandler( catalog )
	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
		
	-- make the preexisting path a custom filename so that we know that it's not been copied over from the 
	-- dupe and changed
	local preexistingPresetPath = catalog:fileSpec():pathForStyle( preexistingPresetId )
	fileCleanup( rxTest, preexistingPresetPath )

	local preexistingPresetRelativePath = WFFileUtils.removeVolumeFromPath( preexistingPresetPath )
	
	-- create basic preexisting preset doc that came from Oz 
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = preexistingPresetId,
			_newRevId = "22ceb6dc1bfb47ae95c2094bbd3e726f",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		},
		':ignore:' )
		
	-- create a second revision locally
	rxTest:expectSingleValue(
		docStore:applyOverlay {
			_id = preexistingPresetId,
			group = "GROUP"
		}, ':ignore:' )
	
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId, 
									{ "22ceb6dc1bfb47ae95c2094bbd3e726f", KSIdGenerator.uuidInLowercaseHex() },
									"Test3" ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- duplicate doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, presetId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should have master attached
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = preexistingPresetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			captureDate = "0000-00-00T00:00:00",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test3",
			group = "GROUP",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
	
end

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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_MatchingDocLocalSha256Change( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )

	local conflictResolver = require 'WFCatConflictResolver'( catalog:docStore(), catalog:indexStore() )
	rxTest:addCloseTarget( conflictResolver )	
	
	local errorHandler = NmbErrorHandler( catalog )
	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
		
	-- create basic preexisting preset doc
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = preexistingPresetId,
			_newRevId = "22ceb6dc1bfb47ae95c2094bbd3e726f",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",

		},
		':ignore:' )
		
	-- create a second revision locally
	rxTest:expectSingleValue(
		docStore:applyOverlay {
			_id = preexistingPresetId,
			importSource = {
				sha256 = "updatedsha256"
			}
		}, ':ignore:' )
	
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should be in same state it was previously
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "updatedsha256",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
		
	-- duplicate doc should remain with a sequence number increase that will cause it to be resent to Oz
	rxTest:observe( docStore:ongoingDocValue( presetId )
		:map( function( docValue )
			return docValue._changeCounter > 1
		end ) )
		:expectDataWithinTime( 3, true )
	
end

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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_MatchingDocOzSha256Change( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )

	local conflictResolver = require 'WFCatConflictResolver'( catalog:docStore(), catalog:indexStore() )
	rxTest:addCloseTarget( conflictResolver )	
	
	local errorHandler = NmbErrorHandler( catalog )
	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
		
	-- create basic preexisting preset doc
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = preexistingPresetId,
			_newRevId = "22ceb6dc1bfb47ae95c2094bbd3e726f",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",

		},
		':ignore:' )
		
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request which 
	-- will return the matching doc, but this will contain an update that makes it match no longer
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '200', presetDocJsonFromOzWith( preexistingPresetId, 
									{ "22ceb6dc1bfb47ae95c2094bbd3e726f", KSIdGenerator.uuidInLowercaseHex() },
									"Test", "updatedsha256" ) ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- matching doc should be in same state it was previously
	rxTest:expectSingleValue( docStore:docValue( preexistingPresetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = "7b12cf2c0f6944c0a1d884b6653992ec",
			captureDate = "0000-00-00T00:00:00",
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "updatedsha256",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-16T20:25:13.488Z",
			userUpdated = "2018-04-16T20:25:13.488Z",
		} )
		
	-- duplicate doc should remain with a sequence number increase that will cause it to be resent to Oz
	rxTest:observe( docStore:ongoingDocValue( presetId )
		:map( function( docValue )
			return docValue._changeCounter > 1
		end ) )
		:expectDataWithinTime( 3, true )
	
end


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

function NmbErrorHandlerTest.rxTestAssetPreconditionFailedDuplicate_MatchingDoc404Oz( rxTest )
	
	rxTest:setTimeLimit( 60 )
	
	local errorDocId = 'f72de423053352e6737a2bb3d3bdccca'
	local preexistingPresetId = "7b12cf2c0f6944c0a1d884b6653992ec"
	local presetId = "b3f8d2351ab942a298300bb5c5262771"
	
	local catalogSpec = WFCatSpecMock( '98db98bfd554470dab2f862a4b853c40', 'd45516d8f82c4b2cbe78610ff9042d8a', rxTest )
	local catalog = WFCatMockCatalog.createWFCatalogForTestWithSpec( rxTest, catalogSpec )

	local conflictResolver = require 'WFCatConflictResolver'( catalog:docStore(), catalog:indexStore() )
	rxTest:addCloseTarget( conflictResolver )	
	
	local errorHandler = NmbErrorHandler( catalog )
	rxTest:addCloseTarget( errorHandler )
	
	local docStore = catalog:docStore()

	local presetPath = catalog:fileSpec():pathForStyle( presetId )
	fileCleanup( rxTest, presetPath )
	
	local presetVolume = WFFileUtils.getVolumeGuidForPath( presetPath )
	local presetRelativePath = WFFileUtils.removeVolumeFromPath( presetPath )
	
	-- create some dummy data at the path to the preset
	KSData.saveToFile( KSData.make( 'dummypresetdata' ), presetPath )
	
	-- create basic 'preset' doc that has not been synced to Oz
	rxTest:expectSingleValue( 
		docStore:setDocValue {
			_id = presetId,
			_newRevId = "19caf1ed81be46d1bb1f1bb995e86aca",
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		},
		':ignore:' )
		
	-- create PreconditionFailed error doc for asset that indicates the resource is a duplicate
	-- of an existing asset on Oz. When it's processed, it should make an HTTP request which 
	-- will return a 404
	catalogSpec:expectHttpRequest(
		WFMockHttpRequest()
			:get( "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId )
			:respond( '404', 'Resource Not Found' ) )
			
	rxTest:expectSingleValue(
		docStore:setDocValue {
			_id = errorDocId,
			_newRevId = "8bb5ad0a645a41f891a822786f2fea58",
			subtype = WFCatOzErrors.Errors.kPreconditionFailedError,
			type = "error",
			_serverProvidedMetadata = {
				base = "https://photos-stage.adobe.io/v2/catalogs/98db98bfd554470dab2f862a4b853c40/",
				errors = {
				},
				matching_asset = {
					href = "/v2/catalogs/98db98bfd554470dab2f862a4b853c40/updates/" .. preexistingPresetId,
				},
				source = {
					action = "create",
					id = "b3f8d2351ab942a298300bb5c5262771",
					revision_id = "19caf1ed81be46d1bb1f1bb995e86aca",
					type = "asset",
				},
				status = 412,
				updated = "2018-04-19T19:04:27.882432Z",
			},
		},
		':ignore:' )
	
	-- error doc should be deleted
	rxTest:observe( WFRxTestUtils.ongoingDocValueIsEmpty( docStore, errorDocId ) )
		:expectDataWithinTime( 3, true )
	
	-- preset doc should be in same state it was previously (we should be trying to resync it)
	rxTest:expectSingleValue( docStore:docValue( presetId ):map( stripWobblyBitsAndSPMFromDocValue ),
		{
			_id = presetId,
			_localOnly = {
				files = {
					original = {
						master = {
							relativePath = presetRelativePath,
							sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
							size = 3937,
							volumeGuid = presetVolume,
						},
					},
				},
				ozError = {
					reason = "if_none_match",
					retryCount = 1,
					subtype = "PreconditionFailed",
				},
			},
			importSource = {
				contentType = "application/rdf+xml",
				fileSize = 3937,
				sha256 = "5a7ed787c67503c2dcf8aba4a8e23d11e278bf00b0a740978d82815bf67853c2",
			},
			name = "Test",
			subtype = "preset",
			type = "asset",
			userCreated = "2018-04-19T19:02:43.158Z",
			userUpdated = "2018-04-19T19:02:43.158Z",
		} )
		
	-- preset doc should remain with a sequence number increase that will cause it to be resent to Oz
	rxTest:observe( docStore:ongoingDocValue( presetId )
		:map( function( docValue )
			return docValue._changeCounter > 1
		end ) )
		:expectDataWithinTime( 3, true )
	
end

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

-- end of if not WFPlatformInfo.isiOS and not WFPlatformInfo.isAndroid then
end

return WFRxTestCase.wrapSuite( 'NmbErrorHandlerTest', NmbErrorHandlerTest )
