/* Ċ Ġ* ĠCopyright Ġ 2 0 1 9 ĠF rol lo Ċ Ġ* Ċ Ġ* ĠLicensed Ġunder Ġthe ĠApache ĠLicense , ĠVersion Ġ 2 . 0 Ġ( the Ġ" License "); Ċ Ġ* Ġyou Ġmay Ġnot Ġuse Ġthis Ġfile Ġexcept Ġin Ġcompliance Ġwith Ġthe ĠLicense . Ċ Ġ* ĠYou Ġmay Ġobtain Ġa Ġcopy Ġof Ġthe ĠLicense Ġat Ċ Ġ* Ċ Ġ* ĠĠĠ Ġhttp :// www . apache . org / licenses / LICENSE - 2 . 0 Ċ Ġ* Ċ Ġ* ĠUnless Ġrequired Ġby Ġapplicable Ġlaw Ġor Ġagreed Ġto Ġin Ġwriting , Ġsoftware Ċ Ġ* Ġdistributed Ġunder Ġthe ĠLicense Ġis Ġdistributed Ġon Ġan Ġ" AS ĠIS " ĠBASIS , Ċ Ġ* ĠWITHOUT ĠWARRANTIES ĠOR ĠCONDITIONS ĠOF ĠANY ĠKIND , Ġeither Ġexpress Ġor Ġimplied . Ċ Ġ* ĠSee Ġthe ĠLicense Ġfor Ġthe Ġspecific Ġlanguage Ġgoverning Ġpermissions Ġand Ċ Ġ* Ġlimitations Ġunder Ġthe ĠLicense . Ċ Ġ*/ Ċ Ċ package Ġus . f rol lo . f rol lo sdk . network Ċ Ċ import Ġokhttp 3 . mock webserver . Dispatcher Ċ import Ġokhttp 3 . mock webserver . Mock Response Ċ import Ġokhttp 3 . mock webserver . Re corded Request Ċ import Ġorg . junit . Assert . assertEquals Ċ import Ġorg . junit . Assert . assertNotNull Ċ import Ġorg . junit . Assert . assertNull Ċ import Ġorg . junit . Test Ċ import Ġorg . th reet en . bp . LocalDateTime Ċ import Ġorg . th reet en . bp . Zone Offset Ċ import Ġus . f rol lo . f rol lo sdk . Base Android Test Ċ import Ġus . f rol lo . f rol lo sdk . base . Resource Ċ import Ġus . f rol lo . f rol lo sdk . error . API Error Ċ import Ġus . f rol lo . f rol lo sdk . error . API ErrorType Ċ import Ġus . f rol lo . f rol lo sdk . extensions . enqueue Ċ import Ġus . f rol lo . f rol lo sdk . model . api . payments . Payment Transfer Request Ċ import Ġus . f rol lo . f rol lo sdk . network . api . Payments API Ċ import Ġus . f rol lo . f rol lo sdk . network . api . User API Ċ import Ġus . f rol lo . f rol lo sdk . test . R Ċ import Ġus . f rol lo . f rol lo sdk . test utils . readString FromJson Ċ import Ġus . f rol lo . f rol lo sdk . test utils . trimmed Path Ċ import Ġjava . math . BigDecimal Ċ import Ġjava . util . concurrent . Count DownLatch Ċ import Ġjava . util . concurrent . TimeUnit Ċ Ċ class ĠNetwork Authenticator Test Ġ: ĠBase Android Test () Ġ{ ĊĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġuser API : ĠUser API ĊĠĠĠ Ġprivate Ġlateinit Ġvar Ġpayments API : ĠPay ments API ĊĊĠĠĠ Ġoverride Ġfun Ġinit Setup () Ġ{ ĊĠĠĠĠĠĠĠ Ġsuper . init Setup () ĊĊĠĠĠĠĠĠĠ Ġuser API Ġ= Ġnetwork . create ( User API :: class . java ) ĊĠĠĠĠĠĠĠ Ġpayments API Ġ= Ġnetwork . create ( Payments API :: class . java ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Pre empt ive AccessToken Refresh () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠUser API . URL _ USER _ DETAILS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . user _ details _ complete )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġmock Token Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠTOKEN _ URL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . token _ valid )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 3 0 Ġ// Ġ 3 0 Ġseconds Ġin Ġthe Ġfuture Ġfalls Ġwithin Ġthe Ġ 5 Ġminute Ġaccess Ġtoken Ġexpiry ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . SUCCESS , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 1 , Ġmock Server . request Count ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 1 , Ġmock Token Server . request Count ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" MT Q 0 Nj Jk Zm Q 5 OT M 2 N DE 1 Z TZ j NG Zm Zj I 3 ", Ġkeystore . decrypt ( preferences . encrypted AccessToken )) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" Iw OG Yz YT lm M 2 Yx OT Q 5 M GE 3 Ym Nm M DF k NT Vk ", Ġkeystore . decrypt ( preferences . encrypted RefreshToken )) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 2 5 5 0 7 9 4 7 9 9 , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Invalid AccessToken Refresh () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġfailed Once Ġ= Ġfalse ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠUser API . URL _ USER _ DETAILS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( failed Once ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . user _ details _ complete )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġfailed Once Ġ= Ġtrue ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ invalid _ access _ token )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġmock Token Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠTOKEN _ URL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . token _ valid )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . SUCCESS , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 2 , Ġmock Server . request Count ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 1 , Ġmock Token Server . request Count ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" MT Q 0 Nj Jk Zm Q 5 OT M 2 N DE 1 Z TZ j NG Zm Zj I 3 ", Ġkeystore . decrypt ( preferences . encrypted AccessToken )) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" Iw OG Yz YT lm M 2 Yx OT Q 5 M GE 3 Ym Nm M DF k NT Vk ", Ġkeystore . decrypt ( preferences . encrypted RefreshToken )) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 2 5 5 0 7 9 4 7 9 9 , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Requests Get Cancelled After Multiple Invalid AccessToken From Server () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠUser API . URL _ USER _ DETAILS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ invalid _ access _ token )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġmock Token Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠTOKEN _ URL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . token _ valid )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( API ErrorType . INVALID _ ACCESS _ TOKEN , Ġ( resource . error Ġas ĠAPI Error ). type ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 6 , Ġmock Server . request Count ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 5 , Ġmock Token Server . request Count ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠRet ries Ġis Ġnot Ġreset ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 6 , Ġnetwork . invalid Token Retries ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Invalid AccessToken Retries Reset () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġuser Request Count Ġ= Ġ 0 ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠUser API . URL _ USER _ DETAILS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( user Request Count Ġ< Ġ 3 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġuser Request Count ++ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ invalid _ access _ token )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . user _ details _ complete )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġmock Token Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠTOKEN _ URL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . token _ valid )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . SUCCESS , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 4 , Ġmock Server . request Count ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 3 , Ġmock Token Server . request Count ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠRet ries Ġis Ġreset ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 0 , Ġnetwork . invalid Token Retries ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Invalid RefreshToken Fails () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ invalid _ refresh _ token )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 1 , Ġmock Server . request Count ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( preferences . encrypted AccessToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( preferences . encrypted RefreshToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (- 1 , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Requests Get Ret ried After Refresh ing AccessToken () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 3 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġvar Ġuser Request Count Ġ= Ġ 0 ĊĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠUser API . URL _ USER _ DETAILS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( user Request Count Ġ< Ġ 3 ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġuser Request Count ++ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ invalid _ access _ token )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . user _ details _ complete )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġmock Token Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠTOKEN _ URL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 2 0 0 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . token _ valid )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . SUCCESS , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . data ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . SUCCESS , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . data ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . SUCCESS , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . data ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠassertEquals (" MT Q 0 Nj Jk Zm Q 5 OT M 2 N DE 1 Z TZ j NG Zm Zj I 3 ", Ġkeystore . decrypt ( preferences . encrypted AccessToken )) ĊĠĠĠĠĠĠĠ ĠassertEquals (" Iw OG Yz YT lm M 2 Yx OT Q 5 M GE 3 Ym Nm M DF k NT Vk ", Ġkeystore . decrypt ( preferences . encrypted RefreshToken )) ĊĠĠĠĠĠĠĠ ĠassertEquals ( 2 5 5 0 7 9 4 7 9 9 , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Requests Get Cancelled After Refresh ing AccessToken Fails () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 3 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠUser API . URL _ USER _ DETAILS ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ invalid _ access _ token )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġmock Token Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( request . trimmed Path Ġ== ĠTOKEN _ URL ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ oauth 2 _ invalid _ client )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response (). set Response Code ( 4 0 4 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( preferences . encrypted AccessToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( preferences . encrypted RefreshToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (- 1 , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġuser API . fetch User (). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 8 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Invalid O tp DoesNot Force Logout () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ payment _ invalid _ otp )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġval Ġexpiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= Ġexpiry ĊĊĠĠĠĠĠĠĠ Ġval Ġpayment Request Ġ= ĠPayment Transfer Request ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġamount Ġ= ĠBigDecimal . TEN , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsource AccountId Ġ= Ġ 1 2 3 , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdestination AccountId Ġ= Ġ 4 5 6 ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpayments API . transfer ( payment Request , Ġ" 1 2 3 4 5 6 "). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( API ErrorType . INVALID _ SECURITY _ CODE , Ġ( resource . error Ġas ? ĠAPI Error )?. type ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrequest Ġ= Ġmock Server . take Request () ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" 1 2 3 4 5 6 ", Ġrequest . getHeader ( Network Helper . HEADER _ OTP )) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" Bearer ĠExisting AccessToken ", Ġrequest . getHeader (" Authorization ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" X - Api - Version ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" us . f rol lo . f rol lo sdk ", Ġrequest . getHeader (" X - Bundle - Id ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" X - Device - Version ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" X - Software - Version ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" User - Agent ")) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 1 , Ġmock Server . request Count ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( preferences . encrypted AccessToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( preferences . encrypted RefreshToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( expiry , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ@ Test ĊĠĠĠ Ġfun Ġtest Missing O tp DoesNot Force Logout () Ġ{ ĊĠĠĠĠĠĠĠ Ġinit Setup () ĊĊĠĠĠĠĠĠĠ Ġval Ġsignal Ġ= ĠCount DownLatch ( 1 ) ĊĊĠĠĠĠĠĠĠ Ġmock Server . dispatcher Ġ= Ġ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġobject Ġ: ĠDispatcher () Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġdispatch ( request : ĠRe corded Request ): ĠMock Response Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĠMock Response () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Response Code ( 4 0 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. set Body ( readString FromJson ( app , ĠR . raw . error _ payment _ missing _ otp )) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpreferences . encrypted AccessToken Ġ= Ġkeystore . encrypt (" Existing AccessToken ") ĊĠĠĠĠĠĠĠ Ġpreferences . encrypted RefreshToken Ġ= Ġkeystore . encrypt (" Existing RefreshToken ") ĊĠĠĠĠĠĠĠ Ġval Ġexpiry Ġ= ĠLocalDateTime . now ( Zone Offset . UTC ). to Epoch Second ( Zone Offset . UTC ) Ġ+ Ġ 9 0 0 ĊĠĠĠĠĠĠĠ Ġpreferences . accessToken Expiry Ġ= Ġexpiry ĊĊĠĠĠĠĠĠĠ Ġval Ġpayment Request Ġ= ĠPayment Transfer Request ( ĊĠĠĠĠĠĠĠĠĠĠĠ Ġamount Ġ= ĠBigDecimal . TEN , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġsource AccountId Ġ= Ġ 1 2 3 , ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdestination AccountId Ġ= Ġ 4 5 6 ĊĠĠĠĠĠĠĠ Ġ) ĊĊĠĠĠĠĠĠĠ Ġpayments API . transfer ( payment Request , Ġnull ). enqueue Ġ{ Ġresource Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( Resource . Status . ERROR , Ġresource . status ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( resource . error ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( API ErrorType . SECURITY _ CODE _ REQUIRED , Ġ( resource . error Ġas ? ĠAPI Error )?. type ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġrequest Ġ= Ġmock Server . take Request () ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNull ( request . getHeader ( Network Helper . HEADER _ OTP )) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" Bearer ĠExisting AccessToken ", Ġrequest . getHeader (" Authorization ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" X - Api - Version ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals (" us . f rol lo . f rol lo sdk ", Ġrequest . getHeader (" X - Bundle - Id ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" X - Device - Version ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" X - Software - Version ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( request . getHeader (" User - Agent ")) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( network . o Auth 2 Helper . config . sessionId Provider ?. sessionId , Ġrequest . getHeader (" X - Session - Id ")) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( 1 , Ġmock Server . request Count ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( preferences . encrypted AccessToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertNotNull ( preferences . encrypted RefreshToken ) ĊĠĠĠĠĠĠĠĠĠĠĠ ĠassertEquals ( expiry , Ġpreferences . accessToken Expiry ) ĊĊĠĠĠĠĠĠĠĠĠĠĠ Ġsignal . count Down () ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġsignal . await ( 3 , ĠTimeUnit . SECONDS ) ĊĊĠĠĠĠĠĠĠ ĠtearDown () ĊĠĠĠ Ġ} Ċ } Ċ