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

WFOAuth2SessionTestFactory.lua

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

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.

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

This file allows us to share the test suite for WFOAuth2SessionImp and
WFOAuth2Session.

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

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

	-- WF.core.utils
local KSIdGenerator = require 'KSIdGenerator'
local WFCloseSupport = require 'WFCloseSupport'
local WFImsAppIdentity = require 'WFImsAppIdentity'

	-- WF.oz_client.account
local WFOzUserTestSession = require 'WFOzUserTestSession'

	-- WF.oz_client.catalog
local OzCatalogUrls = require 'OzCatalogUrls'

	-- WF.web.utils
local WFURI = require 'WFURI'


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

return function( oAuth2SessionClass )

	local oAuth2SessionTestSuite = {}

	local coveragePath

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

	local function setUpOAuth2Session( rxTest, session )

		assert( rxTest )
		assert( session )

		rxTest:finally( function()

			if coveragePath and session and not WFCloseSupport.hasBeenOrWillBeClosed( session ) then
				session:DEBUG_dumpCoverage( coveragePath )
			end

			session:close()
			session = nil

		end )

		return session

	end

	oAuth2SessionTestSuite.setUpOAuth2Session = setUpOAuth2Session

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

	function oAuth2SessionTestSuite.setUp( _coveragePath )

		coveragePath = _coveragePath

	end

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

	function oAuth2SessionTestSuite.rxTestStoreTokens_testNightly( rxTest )

		rxTest:setTimeLimit( 60 )

		local oAuth2Session = setUpOAuth2Session( rxTest, oAuth2SessionClass( 'testUser' ) )

		rxTest:expectOnlyCompleted( oAuth2Session:storeTokens( 'access', 'refresh' ) )

	end

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

	function oAuth2SessionTestSuite.rxTestTokenReload_testNightly( rxTest )

		rxTest:setTimeLimit( 60 )

		local userId = KSIdGenerator.uuidInLowercaseHex()

		local oAuth2Session1 = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		local hasValidLogin1 = rxTest:observe( oAuth2Session1:hasValidLogin() )

		hasValidLogin1:expectDataWithinTime( 15, false )

		rxTest:expectOnlyCompleted( oAuth2Session1:storeTokens( 'access', 'refresh' ) )

		hasValidLogin1:expectDataWithinTime( 2, true )
		hasValidLogin1:dispose()

		rxTest:sleep( 2 )

		oAuth2Session1:close()

		rxTest:sleep( 5 )

		local oAuth2Session2 = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		local hasValidLogin2 = rxTest:observe( oAuth2Session2:hasValidLogin() )
		hasValidLogin2:expectDataWithinTime( 2, true )

	end

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

	function oAuth2SessionTestSuite.rxTestGet_testNightly( rxTest )

		rxTest:setTimeLimit( 120 )

		-- Acquire a test account.

		local userTestSession = WFOzUserTestSession( rxTest )

		local userId

		rxTest:expectSingleValue(

			userTestSession:getCleanOzAccount()
				:tap( function( _userId )
					userId = _userId
				end ),

			':ignore:' )

		-- Create a corresponding OAuth2 session.

		local session = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		rxTest:expectOnlyCompleted( session:storeTokens( userTestSession:accessAndRefreshTokens() ) )

		local url = WFURI.resolve( OzCatalogUrls.baseServerUrl,
								   '/v2/accounts/00000000000000000000000000000000' )

		local imsClientId = WFImsAppIdentity.getClientId()
		local args = {
			requestHeaders = {
				{ header = 'X-Api-Key', value = imsClientId }
			}
		}
		rxTest:expectSingleValue(

			session:get( url, args )
				:map( function( data, headers )
					return tostring( data ), headers
				end ),
			':ignore:', ':ignore:' )
				-- TODO [scouten 2015-07-19]: Write better test here

	end

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

	function oAuth2SessionTestSuite.rxTestGet_errorNoTokens_testNightly( rxTest )

		rxTest:setTimeLimit( 120 )

		-- Acquire a test account.

		local userTestSession = WFOzUserTestSession( rxTest, { suppressStoreTokens = true } )

		local userId

		rxTest:expectSingleValue(

			userTestSession:getCleanOzAccount()
				:tap( function( _userId )
					userId = _userId
				end ),

			':ignore:' )

		-- Create a corresponding OAuth2 session.

		local session = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		-- Whoops. Don't provide tokens, so request below can never start.

		local url = WFURI.resolve( OzCatalogUrls.baseServerUrl,
								   '/v2/accounts/00000000000000000000000000000000' )

		rxTest:expectOnlyError(

			session:get( url )
				:map( function( data, headers )
					return tostring( data ), headers
				end ),

			"No access token available" )

	end

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

	function oAuth2SessionTestSuite.rxTestGet_withProgress_testNightly( rxTest )

		rxTest:setTimeLimit( 120 )

		-- This test verifies that progress is passed through the OAuth2 session,

		local userTestSession = WFOzUserTestSession( rxTest, { suppressStoreTokens = true } )

		local userId

		rxTest:expectSingleValue(

			userTestSession:getCleanOzAccount()
				:tap( function( _userId )
					userId = _userId
				end ),

			':ignore:' )

		-- Create a corresponding OAuth2 session.

		local session = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		rxTest:expectOnlyCompleted( session:storeTokens( userTestSession:accessAndRefreshTokens() ) )

		local gotProgress = false

		rxTest:expectSingleValue(

			-- This is good for debugging: 'https://helpx.adobe.com/content/dam/help/en/photoshop/how-to/photoshop-merge-to-hdr_1408x792.jpg'

			session:get( 'http://sj1010120180138.corp.adobe.com:8888//http-get-test-data.txt',
				{ includeProgress = true } )

				:filter( function( data, headers, progress )

					if data ~= 'requestInProgress' then

						rxTest:expectEqual( true, gotProgress )
						rxTest:expectEqual( 'userdata', type(data))
						rxTest:expectEqual( "Hello, Wichita!\n", tostring(data) )
						rxTest:expectEqual( type(headers), 'table' )
						rxTest:expectEqual( "200", headers.status_code )

						return true
					elseif progress then
						gotProgress = true
						return false
					end

				end )
				:take ( 1 ),

			':ignore:', ':ignore:', ':ignore:'

		)

	end

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

	function oAuth2SessionTestSuite.rxTestPut_testNightly( rxTest )

		-- TODO [scouten 2015-07-19]: We should probably test more scenarios
		-- and maybe an actual OAuth2 PUT.

		rxTest:setTimeLimit( 20 )

		-- Acquire a test account.

		local userTestSession = WFOzUserTestSession( rxTest )

		local userId

		rxTest:expectSingleValue(

			userTestSession:getCleanOzAccount()
				:tap( function( _userId )
					userId = _userId
				end ),

			':ignore:' )

		-- Create a corresponding OAuth2 session.

		local session = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		rxTest:expectOnlyCompleted( session:storeTokens( userTestSession:accessAndRefreshTokens() ) )

		-- Now send a PUT-style request. This is kind of a cop-out since we're
		-- not actually relying on OAuth2 signature here.

		rxTest:expectSingleValue(

			session:put(
				'http://sj1010120180138.corp.adobe.com:8888/AgHttpClientTest3.post.cgi',
				"Post Data",
				{
					requestMethod = "POST",
					timeout = 10,
				} )

				:tap( function( data, headers )
					rxTest:expectEqual( 'userdata', type( data ) )
					rxTest:expectEqual( "<p>Thanks. You said: Post Data</p>", tostring( data ) )
				end ),

			':ignore:', ':ignore:'

		)

	end

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

	function oAuth2SessionTestSuite.rxTestPutWithProgress_testNightly( rxTest )

		rxTest:setTimeLimit( 20 )

		-- Acquire a test account.

		local userTestSession = WFOzUserTestSession( rxTest )

		local userId

		rxTest:expectSingleValue(

			userTestSession:getCleanOzAccount()
				:tap( function( _userId )
					userId = _userId
				end ),

			':ignore:' )

		-- Create a corresponding OAuth2 session.

		local session = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		rxTest:expectOnlyCompleted( session:storeTokens( userTestSession:accessAndRefreshTokens() ) )

		-- Now send a PUT-style request. This is kind of a cop-out since we're
		-- not actually relying on OAuth2 signature here.

		local gotProgress = false

		rxTest:expectSingleValue(

			session:put(
				'http://sj1010120180138.corp.adobe.com:8888/AgHttpClientTest3.post.cgi',
				"Post Data",
				{
					requestMethod = "POST",
					timeout = 10,
					includeProgress = true
				} )

				:tap( function( _, _, progress )

					if progress then
						gotProgress = true
					end

				end )

				:tap( function( data, headers )

					if data ~= 'requestInProgress' then

						rxTest:expectEqual( 'userdata', type( data ) )
						rxTest:expectEqual( "<p>Thanks. You said: Post Data</p>", tostring( data ) )
						rxTest:expectEqual( true, gotProgress )

					end

				end )

				:take( 1 ),

			':ignore:', ':ignore:', ':ignore:'

		)

	end

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

	function oAuth2SessionTestSuite.DISABLED_rxTestLogout_testNightly( rxTest )

		-- TODO [scouten 2015-07-19]: Logout isn't implemented for now.
		-- Enable this test when it is.

		rxTest:setTimeLimit( 60 )

		-- Acquire a test account.

		local userTestSession = WFOzUserTestSession( rxTest )

		local userId

		rxTest:expectSingleValue(

			userTestSession:getCleanOzAccount()
				:tap( function( _userId )
					userId = _userId
				end ),

			':ignore:' )

		-- Create a corresponding OAuth2 session.

		local session = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		rxTest:expectOnlyCompleted( session:storeTokens( userTestSession:accessAndRefreshTokens() ) )

		local hasValidLogin = rxTest:observe( session:hasValidLogin() )

		hasValidLogin:expectDataWithinTime( 2, true )

		-- And then logout.

		rxTest:expectOnlyCompleted( session:logout() )

		hasValidLogin:expectDataWithinTime( 2, false )

		-- TODO [scouten 2015-07-19]: Test logging back in.

	end

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

	function oAuth2SessionTestSuite.rxTestSimulateForcedLogout_testNightly( rxTest )

		rxTest:setTimeLimit( 60 )

		local userId = KSIdGenerator.uuidInLowercaseHex()

		local oAuth2Session1 = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		local hasValidLogin1 = rxTest:observe( oAuth2Session1:hasValidLogin() )

		hasValidLogin1:expectDataWithinTime( 15, false )

		rxTest:expectOnlyCompleted( oAuth2Session1:storeTokens( 'access', 'refresh' ) )

		hasValidLogin1:expectDataWithinTime( 2, true )

		rxTest:expectOnlyCompleted( oAuth2Session1:simulateForcedLogout() )

		hasValidLogin1:expectDataWithinTime( 2, false )

		hasValidLogin1:dispose()

		rxTest:sleep( 2 )

		oAuth2Session1:close()

		rxTest:sleep( 5 ) -- time for previous OAuth2 session imp to be GC'd

		local oAuth2Session2 = setUpOAuth2Session( rxTest, oAuth2SessionClass( userId ) )

		local hasValidLogin2 = rxTest:observe( oAuth2Session2:hasValidLogin() )
		hasValidLogin2:expectDataWithinTime( 15, false )

	end

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

	return WFRxTestCase.wrapSuite( 'WFOAuth2SessionTest', oAuth2SessionTestSuite )

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

end
