packages feed

paypal-adaptive-hoops-0.9.0.0: tests/Remote.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}

module Main where

import Control.Applicative
import Control.Monad
import Data.Aeson
import qualified Data.ByteString.Lazy as B
import Data.Default
import Data.HashMap.Strict as H
import Data.Text (Text)
import Test.Framework (Test, defaultMain, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.HUnit hiding (Test)
import Utils
import Web.PayPal.Adaptive
import Web.PayPal.Adaptive.Internal

main :: IO ()
main = defaultMain [integrationRemote]

integrationRemote :: Test
integrationRemote = testGroup "remote"
  [ testCase
      "withdrawal succeeds with good arguments"
      correctWithdrawal
  , testCase
      "withdrawal with a bad account address gives the correct error"
      withdrawalAccountAddressDNE
  , testCase
      "withdrawal with a bad user address gives the correct error"
      withdrawalUserAddressDNE
  , testCase
      "withdrawal without a large enough balance gives the correct error"
      withdrawalNotEnoughFunds
  , testCase
      "deposit succeeds with good arguments"
      correctDeposit
  , testCase
      "deposit with a bad account address does NOT produce an error"
      depositAccountAddressDNE
  , testCase
      "deposit with a bad user address gives the correct error"
      depositUserAddressDNE
  ]

-- | Currently the ID for all sandbox apps.
appId :: Text
appId = "APP-80W284485P519543T"

instance FromJSON Client where
  parseJSON = withObject "client credentials" $ \o ->
    Client appId                 <$>
    o .: "sandboxClientUid"      <*>
    pure Sandbox                 <*>
    o .: "sandboxClientPassword" <*>
    o .: "sandboxClientSig"      <*>
    o .: "sandboxAccountEmail"

config :: IO (Client, Text, Text)
config = do
  b <- B.readFile "sandbox.json"
  client <- assertRight (eitherDecode b)
  Object o <- assertRight (eitherDecode b)
  String userEmail <- assertJust "sandboxUserEmail not found"
    $ H.lookup "sandboxUserEmail" o
  String notSandboxEmail <- assertJust "randomNonSandboxUserEmail not found"
    $ H.lookup "randomNonSandboxUserEmail" o
  return (client, userEmail, notSandboxEmail)

incorrectEmailClient :: Text -> Client -> Client
incorrectEmailClient badAccountEmail (Client a b c d e _) = Client a b c d e badAccountEmail

withdrawal :: Text -> Withdrawal
withdrawal userAddr = def
  { _wdAmount = USD 1
  , _wdReceiverEmail = userAddr
  }

deposit :: Text -> Deposit
deposit userAddr = def
  { _dpAmount = USD 1
  , _dpSenderEmail = userAddr
  }

assrt :: Either AdaptiveErr () -> IO ()
assrt (Left e) = assertFailure (show e) >> fail "check failed"
assrt (Right _) = return ()


correctWithdrawal :: Assertion
correctWithdrawal = do
  (client, userEmail, _) <- config
  payResp <- assertRight =<< toPayPal client (withdrawal userEmail)
  (assrt . checkLookup) =<< assertRight =<< toPayPal client (LookupPayKey . _prPayKey $ payResp)
  where
    checkLookup :: PayResp -> Either AdaptiveErr ()
    checkLookup a = do
      payExecStatusCompleted a
      info <- getPayInfo a
      transactionStatusCompleted a info
      errorFieldNothing a
      checkPayKey a
      Right ()

withdrawalAccountAddressDNE :: Assertion
withdrawalAccountAddressDNE = do
  (client, userEmail, notSandboxEmail) <- config
  let c = incorrectEmailClient notSandboxEmail client
  adaptiveErr <- assertLeft =<< toPayPal c (withdrawal userEmail)
  assertEqual "send error due to a nonexistent account address" AeNoSuchEmail adaptiveErr

withdrawalUserAddressDNE :: Assertion
withdrawalUserAddressDNE = do
  (client, _, notSandboxEmail) <- config
  payResp <- checkResp =<< assertLeft =<< toPayPal client (withdrawal notSandboxEmail)
  (assrt . checkLookup) =<< assertRight =<< toPayPal client (LookupPayKey . _prPayKey $ payResp)
  where
    checkResp :: AdaptiveErr -> IO PayResp
    checkResp (AePending payResp) = do
      assertEqual
        "withdraw to nonexistent user addresses return no PayResps"
        0 (length $ _prPayInfo payResp)
      return payResp
    checkResp _ =
      assertFalse "send error due to a nonexistent user address didn't return AePending"
      >> fail "checkResp failed"

    checkLookup :: PayResp -> Either AdaptiveErr ()
    checkLookup a = do
      payExecStatusCompleted a
      info <- getPayInfo a
      unless (_piTransactionStatus info == Nothing) $ Left (AeShouldNotHappen a
        "a pending withdrawal should not have transaction status in this situation")
      errorFieldNothing a
      checkPayKey a
      Right ()

withdrawalNotEnoughFunds :: Assertion
withdrawalNotEnoughFunds = do
  (client, userEmail, _) <- config
  adaptiveErr <- assertLeft =<< toPayPal client (largeWithdrawal userEmail)
  assertEqual "send error due to not enough funds" (AeErrCodes [520009]) adaptiveErr
  where
    largeWithdrawal :: Text -> Withdrawal
    largeWithdrawal userAddr = def
      { _wdAmount = USD 1000000
      , _wdReceiverEmail = userAddr
      }

correctDeposit :: Assertion
correctDeposit = do
  (client, userEmail, _) <- config
  payResp <- assertRight =<< toPayPal client (deposit userEmail)
  (assrt . checkLookup) =<< assertRight =<< toPayPal client (LookupPayKey . _prPayKey $ payResp)
  where
    checkLookup :: PayResp -> Either AdaptiveErr ()
    checkLookup a = do
      payExecStatusCreated a
      info <- getPayInfo a
      unless (_piTransactionStatus info == Nothing) $ Left (AeShouldNotHappen a
        "an uncompleted deposit should not have transaction status in this situation")
      errorFieldNothing a
      checkPayKey a
      Right ()

depositAccountAddressDNE :: Assertion
depositAccountAddressDNE = do
  (client, userEmail, notSandboxEmail) <- config
  let c = incorrectEmailClient notSandboxEmail client
  payResp <- assertRight =<< toPayPal c (deposit userEmail)
  (assrt . checkLookup) =<< assertRight =<< toPayPal client (LookupPayKey . _prPayKey $ payResp)
  where
    checkLookup :: PayResp -> Either AdaptiveErr ()
    checkLookup a = do
      payExecStatusCreated a
      info <- getPayInfo a
      unless (_piTransactionStatus info == Nothing) $ Left (AeShouldNotHappen a
        "a deposit should not have transaction status in this situation")
      errorFieldNothing a
      checkPayKey a
      Right ()

depositUserAddressDNE :: Assertion
depositUserAddressDNE = do
  (client, _, notSandboxEmail) <- config
  adaptiveErr <- assertLeft =<< toPayPal client (deposit notSandboxEmail)
  assertEqual "create error due to a nonexistent user address" AeNoSuchEmail adaptiveErr