packages feed

symantic-http-test-0.0.1.20190410: Hspec/Client/BasicAuth.hs

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# OPTIONS_GHC -Wno-missing-signatures #-}
module Hspec.Client.BasicAuth where

import Control.Monad (Monad(..))
import Data.Bool
import Data.Either (Either(..))
import Data.Eq (Eq(..))
import Data.Function (($))
import Data.Functor ((<$>))
import Data.Int (Int)
import Data.Map.Strict (Map)
import Data.Maybe (Maybe(..))
import Data.Text (Text)
import System.IO (IO)
import Test.Hspec
import Test.Tasty
import Test.Tasty.Hspec
import Text.Show (Show(..))
import qualified Data.Map.Strict as Map
import qualified Network.HTTP.Client as Client
import qualified Network.HTTP.Types as HTTP

import Symantic.HTTP
import Symantic.HTTP.Client
import Symantic.HTTP.Server
import Hspec.Utils ()
import Hspec.Utils.Server

api =
 "auth" </> basicAuth @User "realm"
        <.> get @() @'[PlainText]
 <!>
 "body" </> body @() @'[PlainText]
        <.> post @() @'[PlainText]

srv = server api $
	route_auth :!:
	route_body
	where
	route_auth User{} = return ()
	route_body (ServerBodyArg _a) = return ()

cli_auth
 :!: cli_body
 = client api

hspec :: IO [TestTree]
hspec = testSpecs $ describe "BasicAuth" $
	beforeAll (runTestServer srv) $
	afterAll killTestServer $ do
		it "can allow user (200)" $ \TestServer{..} -> do
			runClient env (cli_auth (user_name alice) (user_pass alice))
			 `shouldReturn` Right ()
		it "can deny user (401)" $ \TestServer{..} -> do
			Left (ClientError_FailureResponse r) <-
				runClient env $ cli_auth "no-user" (user_pass alice)
			Client.responseStatus r `shouldBe` HTTP.Status 401 "Unauthorized"
		it "can deny pass (401)" $ \TestServer{..} -> do
			Left (ClientError_FailureResponse r) <-
				runClient env $ cli_auth (user_name alice) "no-pass"
			Client.responseStatus r `shouldBe` HTTP.Status 401 "Unauthorized"
		it "can deny auth (403)" $ \TestServer{..} -> do
			Left (ClientError_FailureResponse r) <-
				runClient env $ cli_auth (user_name bob) (user_pass bob)
			Client.responseStatus r `shouldBe` HTTP.Status 403 "Forbidden"

-- * Type "User"
data User
 =   User
 {   user_name :: Text
 ,   user_pass :: Text
 ,   user_auth :: Bool
 ,   user_age  :: Int
 } deriving (Eq, Show)
instance ServerBasicAuth User where
	serverBasicAuth user pass =
		return $
			case Map.lookup user users of
			 Nothing -> BasicAuth_NoSuchUser
			 Just u@User{..}
			  | user_pass == pass ->
				if user_auth
				then BasicAuth_Authorized u
				else BasicAuth_Unauthorized
			  | otherwise -> BasicAuth_BadPassword

users :: Map Text User
users =
	Map.fromList $
	(\u -> (user_name u, u)) <$>
	[ alice
	, bob
	]

alice, bob :: User
alice = User "Alice" "pass" True 19
bob   = User "Bob" "pass" False 31