servant-benchmark-0.2.0.0: src/Servant/Benchmark/Tools/Drill.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ViewPatterns #-}
{- |
Support for the [Drill](https://github.com/fcsonline/drill) load testing application
-}
module Servant.Benchmark.Tools.Drill (Settings (..), export) where
import Data.Aeson (ToJSON (..), object, (.=))
import Data.Aeson.Key (fromText)
import Data.Aeson.Types (Pair, Value)
import qualified Data.ByteString as BS
import Data.CaseInsensitive (original)
import Data.Ord (comparing)
import qualified Data.Text as T
import qualified Data.Yaml.Pretty as Y
import Network.HTTP.Types (Header)
import Servant.Benchmark.Endpoint
import Servant.Benchmark.ToText
-- | Drill specific settings. See the project's [ documentation ](https://github.com/fcsonline/drill) for more details
data Settings = MkSettings
{ concurrency :: Word
, base :: T.Text
, iterations :: Word
, rampup :: Word
}
data Output = MkOutput Settings [Endpoint]
instance ToJSON Output where
toJSON (MkOutput settings plan) =
object
[ "concurrency" .= concurrency settings
, "base" .= base settings
, "iterations" .= iterations settings
, "rampup" .= rampup settings
, "plan"
.= requests plan
]
requests :: [Endpoint] -> [Value]
requests endpoints = endpointToJSON <$> endpoints
endpointToJSON :: Endpoint -> Value
endpointToJSON endpoint =
object
[ "name" .= name endpoint
, "request"
.= object
[ "url" .= path endpoint
, "method" .= fmap toText (method endpoint)
, "body" .= fmap toText (body endpoint)
, "headers"
.= object
(headerToValue <$> headers endpoint)
]
]
headerToValue :: Header -> Pair
headerToValue (headerName, value) =
fromText (toText (original headerName)) .= toText value
-- | Export a benchmark file given a list of `Endpoint`s
export :: FilePath -> Settings -> [Endpoint] -> IO ()
export filepath settings endpoints = do
let output = MkOutput settings $ pack <$> endpoints
let encoding = Y.encodePretty config output
BS.writeFile filepath encoding
config :: Y.Config
config =
Y.setConfCompare ordering Y.defConfig
-- Explicit ordering for root Yaml fields
ordering :: T.Text -> T.Text -> Ordering
ordering "plan" _ = GT
ordering _ "plan" = LT
ordering t1 t2 = comparing T.length t1 t2