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

WFMockHttpRequestTest.lua

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

ADOBE CONFIDENTIAL
------------------
Copyright 2020 Adobe
All Rights Reserved.

NOTICE: All information contained herein is, and remains
the property of Adobe and its suppliers, if any. The intellectual
and technical concepts contained herein are proprietary to Adobe
and its suppliers and are protected by all applicable intellectual
property laws, including trade secret and copyright laws.
Dissemination of this information or reproduction of this material
is strictly forbidden unless prior written permission is obtained
from Adobe.

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

local WFMockHttpRequest = require 'WFMockHttpRequest'
local WFRxHttpClientMock = require 'WFRxHttpClientMock'
local WFRxTestCase = require 'WFRxTestCase'

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


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

local WFMockHttpRequestTest = {}

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

function WFMockHttpRequestTest.rxTestSimpleGet( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:respond( '200', 'get' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:expectSingleValue( mockHttp.get( "/v2/catalogs/000000000000", {} ), 'get', ':ignore:' )
	
end

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

function WFMockHttpRequestTest.rxTestSimpleGet_fail( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:respond( '200', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	-- an HTTP get call with the wrong URL should fail
	local ok, errorMsg = pcall( mockHttp.get, "/v2/catalogs/wrong", {} )
	
	-- ensure the get call failed
	rxTest:expectEqual( false, ok )
	-- validate the error message contains both URLs so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( "/v2/catalogs/000000000000" ) ) and 
								( not not errorMsg:match( "/v2/catalogs/wrong" ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()
	
end
--------------------------------------------------------------------------------

function WFMockHttpRequestTest.rxTestSimplePost( rxTest )
	
	local post = WFMockHttpRequest()
		:post( "/v2/catalogs/000000000000" )
		:respond( '201', 'post' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( post )
	
	rxTest:expectSingleValue( mockHttp.put( "/v2/catalogs/000000000000", nil, {} ), 'post', ':ignore:' )
end

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

function WFMockHttpRequestTest.rxTestSimplePut( rxTest )
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:respond( '201', 'put' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:expectSingleValue( mockHttp.put( "/v2/catalogs/000000000000", nil, {} ), 'put', ':ignore:' )
end

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

function WFMockHttpRequestTest.rxTestExpectRequestData( rxTest )
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( 'some data' )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'some data', {} ) )
	
	local post = WFMockHttpRequest()
		:post( "/v2/catalogs/000000000000" )
		:expectRequestData( 'some data' )
		:respond( '201', '' )
	
	mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( post )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'some data', {} ) )
	
end

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

function WFMockHttpRequestTest.rxTestExpectRequestData_table( rxTest )
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( { data = 'some data' } )
		:requestDataTransformation( function( actualData, expectedData )
			return { data = actualData }, expectedData
		end )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'some data', {} ) )
	
end

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

function WFMockHttpRequestTest.rxTestExpectRequestData_fail( rxTest )

	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( 'some data' )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	-- an HTTP call with the wrong data should fail
	local ok, errorMsg = pcall( mockHttp.put, "/v2/catalogs/000000000000", 'wrong data', {} )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( 'some data' ) ) and 
								( not not errorMsg:match( 'wrong data' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()
end

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

function WFMockHttpRequestTest.rxTestExpectRequestDataAfterTransformation( rxTest )
	
	local transformFn = function( requestData ) 
				if requestData == 'some data' then
					return 'transformed data'
				else
					return requestData
				end
			end
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestDataAfterTransformation( 'transformed data', transformFn )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'some data', {} ) )
	
	local post = WFMockHttpRequest()
		:post( "/v2/catalogs/000000000000" )
		:expectRequestDataAfterTransformation( 'transformed data', transformFn )
		:respond( '201', '' )
	
	mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( post )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'some data', {} ) )
	
end

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

function WFMockHttpRequestTest.rxTestExpectRequestDataAfterTransformation_table( rxTest )
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestDataAfterTransformation( { data = 'some data' }, function( actualData )
			return { data = actualData }
		end )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'some data', {} ) )
	
end

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

function WFMockHttpRequestTest.rxTestExpectRequestDataAfterTransformation_fail( rxTest )
	
	local transformFn = function( requestData ) 
				if requestData == 'some data' then
					return 'transformed data'
				else
					return requestData
				end
			end
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestDataAfterTransformation( 'transformed data', transformFn )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	-- an HTTP call with the wrong data should fail
	local ok, errorMsg = pcall( mockHttp.put, "/v2/catalogs/000000000000", 'wrong data', {} )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( 'transformed data' ) ) and 
								( not not errorMsg:match( 'wrong data' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()
	
end

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

function WFMockHttpRequestTest.rxTestRequestUrlTransformation( rxTest )

	local urlTransformFn = function( requestUrl )
		if requestUrl == '/v2/catalogs/000000000000' then
			return '/v2/catalogs/transformedUrl'
		end
	end
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/transformedUrl" )
		:requestUrlTransformation( urlTransformFn )
		:respond( '200', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:waitFor( mockHttp.get( "/v2/catalogs/000000000000", {} ) )

end

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

function WFMockHttpRequestTest.rxTestRequestUrlTransformation_fail( rxTest )

	local urlTransformFn = function( requestUrl )
		if requestUrl == '/v2/catalogs/000000000000' then
			requestUrl = '/v2/catalogs/transformedUrl'
		end
		return requestUrl
	end
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/transformedUrl" )
		:requestUrlTransformation( urlTransformFn )
		:respond( '200', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	-- an HTTP call with the wrong URL should fail
	local ok, errorMsg = pcall( mockHttp.get, "/v2/catalogs/wrongUrl", {} )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( '/v2/catalogs/transformedUrl' ) ) and 
								( not not errorMsg:match( '/v2/catalogs/wrongUrl' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()
	
end

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

function WFMockHttpRequestTest.rxTestRequestDataTransformation( rxTest )
	
	local transformFn = function( actualData, expectedData ) 
				if actualData == 'actual request data' then
					actualData = 'transformed data'
				end
				if expectedData == 'expected request data' then
					expectedData = 'transformed data'
				end
				return actualData, expectedData
			end
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( 'expected request data' )
		:requestDataTransformation( transformFn )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'actual request data', {} ) )
		
end

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

function WFMockHttpRequestTest.rxTestRequestDataTransformation_fail( rxTest )
	
	local transformFn = function( actualData, expectedData ) 
				if actualData == 'actual request data' then
					actualData = 'transformed data'
				end
				if expectedData == 'expected request data' then
					expectedData = 'transformed data'
				end
				return actualData, expectedData
			end
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( 'expected request data' )
		:requestDataTransformation( transformFn )
		:respond( '201', '' )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	local ok, errorMsg = pcall( mockHttp.put, "/v2/catalogs/000000000000", 'wrong request data', {} )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( 'transformed data' ) ) and 
								( not not errorMsg:match( 'wrong request data' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()
	
end

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

function WFMockHttpRequestTest.rxTestValidateRequestData( rxTest )
	
	local validationFn = function( requestData )
		return not not requestData:match( 'request data' )
	end
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( 'request data' )
		:validateRequestData( validationFn )
		:respond( '201', '' )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	rxTest:waitFor( mockHttp.put( "/v2/catalogs/000000000000", 'request data', {} ) )

end

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

function WFMockHttpRequestTest.rxTestValidateRequestData_fail( rxTest )
	
	local validationFn = function( requestData )
		return not not requestData:match( 'request data' )
	end
	
	local put = WFMockHttpRequest()
		:put( "/v2/catalogs/000000000000" )
		:expectRequestData( 'request data' )
		:validateRequestData( validationFn )
		:respond( '201', '' )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( put )
	
	local ok, errorMsg = pcall( mockHttp.put, "/v2/catalogs/000000000000", 'wrong data', {} )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( 'request data' ) ) and 
								( not not errorMsg:match( 'wrong data' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()
	
end


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

function WFMockHttpRequestTest.rxTestWithRequestHeaders( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:withRequestHeaders( { { header = 'Accept', value = 'application/rxTest' } } )
		:respond( '200', '' )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:waitFor( mockHttp.get( "/v2/catalogs/000000000000", { requestHeaders = { { header = 'Accept', value = 'application/rxTest' } } } ) )

end

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

function WFMockHttpRequestTest.rxTestWithRequestHeaders_fail( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:withRequestHeaders( { { header = 'Accept', value = 'application/rxTest' } } )
		:respond( '200', '' )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	local ok, errorMsg = pcall( mockHttp.get, "/v2/catalogs/000000000000", { requestHeaders = { { header = 'Accept', value = 'application/wrong' } } } )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( 'application/rxTest' ) ) and 
								( not not errorMsg:match( 'application/wrong' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()

end

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

function WFMockHttpRequestTest.rxTestWithRequestOptions( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:withRequestOptions( { requestHeaders = { { header = 'Accept', value = 'application/rxTest' } } } )
		:respond( '200', '' )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:waitFor( mockHttp.get( "/v2/catalogs/000000000000", { requestHeaders = { { header = 'Accept', value = 'application/rxTest' } } } ) )

end

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

function WFMockHttpRequestTest.rxTestWithRequestOptions_fail( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:withRequestOptions( { requestHeaders = { { header = 'Accept', value = 'application/rxTest' } } } )
		:respond( '200', '' )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	local ok, errorMsg = pcall( mockHttp.get, "/v2/catalogs/000000000000", { requestHeaders = { { header = 'Accept', value = 'application/wrong' } } } )
	
	-- ensure the HTTP call failed
	rxTest:expectEqual( false, ok )
	
	-- validate the error message contains both data so it likely contains enough info to understand why it failed
	rxTest:expectEqual( true, ( not not errorMsg:match( 'application/rxTest' ) ) and 
								( not not errorMsg:match( 'application/wrong' ) ) )
	
	-- clear the error count or else the finally fn in WFRxHttpClientMock will fail the test
	mockHttp._debugClearRequestErrorCount()

end

--------------------------------------------------------------------------------
 
function WFMockHttpRequestTest.rxTestResponseFn( rxTest )
	
	local responseDataFn = function()
		return 'response data from function'
	end
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:respond( '200', responseDataFn )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:expectSingleValue( mockHttp.get( "/v2/catalogs/000000000000", {} ), 'response data from function', ':ignore:' )

end

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

function WFMockHttpRequestTest.rxTestWithResponseHeaders( rxTest )
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:respond( '200', '' )
		:withResponseHeaders( { [ 'Content-Length' ] = 13 } )
		
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:expectSingleValue( mockHttp.get( "/v2/catalogs/000000000000", {} ), '', { [ 'Content-Length' ] = 13, status_code = '200' } )
end

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

function WFMockHttpRequestTest.rxTestWithResponseTransformationFn( rxTest )
	
	local transformFn = function( responseData )
		if responseData == '' then
			responseData = 'response was empty'
		end
		return responseData
	end
	
	local get = WFMockHttpRequest()
		:get( "/v2/catalogs/000000000000" )
		:respond( '200', '' )
		:withResponseTransformationFn( transformFn )
	
	local mockHttp = WFRxHttpClientMock( rxTest )
	mockHttp.addHttpRequest( get )
	
	rxTest:expectSingleValue( mockHttp.get( "/v2/catalogs/000000000000", {} ), 'response was empty', ':ignore:' )

end

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

return WFRxTestCase.wrapSuite( WFMockHttpRequestTest )
