net-spider-0.2.0.0: test/ServerTest/Common.hs
{-# LANGUAGE OverloadedStrings #-}
module ServerTest.Common
( withServer,
withSpider,
withSpider',
sortSnapshotElements,
AText(..),
AInt(..),
APorts(..),
subIdWithAPorts,
alignAPortsToLinkDirection
) where
import Control.Applicative ((<$>))
import Control.Category ((<<<))
import Control.Exception.Safe (bracket, withException)
import Data.Greskell (parseOneValue, gProperty, newBind)
import Data.List (sort)
import Data.Text (Text)
import Data.Vector (Vector)
import qualified Data.Vector as V
import Test.Hspec
import Test.Hspec.NeedEnv (needEnvHostPort, EnvMode(Need))
import NetSpider.Found (LinkState(..))
import NetSpider.Graph (NodeAttributes(..), LinkAttributes(..), VNode)
import NetSpider.Pair (Pair(..))
import NetSpider.Spider.Config
( Host, Port, Config(..), defConfig, LogLevel(..)
)
import NetSpider.Spider
( connectWith, close, clearAll, Spider
)
import NetSpider.Snapshot
( SnapshotNode, SnapshotLink
)
import NetSpider.Unify
( LinkSample(..)
)
withServer :: SpecWith (Host,Port) -> Spec
withServer = before $ needEnvHostPort Need "NET_SPIDER_TEST"
withSpider :: Eq n => (Spider n na fla -> IO ()) -> (Host, Port) -> IO ()
withSpider = withSpider' $ defConfig { logThreshold = LevelWarn }
withSpider' :: Config n na fla -> (Spider n na fla -> IO ()) -> (Host, Port) -> IO ()
withSpider' orig_conf action (host, port) = bracket (connectWith conf) close $ \spider -> do
clearAll spider
action spider
where
conf = orig_conf { wsHost = host,
wsPort = port
}
sortSnapshotElements :: (Ord n, Eq na, Eq la)
=> ([SnapshotNode n na], [SnapshotLink n la])
-> (Vector (SnapshotNode n na), Vector (SnapshotLink n la))
sortSnapshotElements (ns, ls) = (sortV ns, sortV ls)
where
sortV :: Ord a => [a] -> Vector a
sortV = V.fromList . sort
newtype AText = AText Text
deriving (Show,Eq,Ord)
instance NodeAttributes AText where
writeNodeAttributes (AText t) = gProperty "text" <$> newBind t
parseNodeAttributes ps = AText <$> parseOneValue "text" ps
instance LinkAttributes AText where
writeLinkAttributes (AText t) = gProperty "text" <$> newBind t
parseLinkAttributes ps = AText <$> parseOneValue "text" ps
newtype AInt = AInt Int
deriving (Show,Eq,Ord)
instance NodeAttributes AInt where
writeNodeAttributes (AInt n) = gProperty "integer" <$> newBind n
parseNodeAttributes ps = AInt <$> parseOneValue "integer" ps
instance LinkAttributes AInt where
writeLinkAttributes (AInt n) = gProperty "integer" <$> newBind n
parseLinkAttributes ps = AInt <$> parseOneValue "integer" ps
-- | Pair of ports.
--
-- This type is used in two ways. (subject port, target port) and
-- (source port, destination port).
data APorts =
APorts
{ apFst :: Text,
apSnd :: Text
}
deriving (Show,Eq,Ord)
instance LinkAttributes APorts where
writeLinkAttributes ap = do
writeSource <- gProperty "subject_port" <$> newBind (apFst ap)
writeDest <- gProperty "target_port" <$> newBind (apSnd ap)
return (writeDest <<< writeSource)
parseLinkAttributes ps = APorts
<$> parseOneValue "subject_port" ps
<*> parseOneValue "target_port" ps
swapAPorts :: APorts -> APorts
swapAPorts ap = ap { apFst = apSnd ap,
apSnd = apFst ap
}
-- | Link sub-ID with 'APorts'.
subIdWithAPorts :: LinkSample n APorts -> Pair (n, Text)
subIdWithAPorts ls = Pair ( (lsSubjectNode ls, apFst $ lsLinkAttributes ls),
(lsTargetNode ls, apSnd $ lsLinkAttributes ls)
)
-- | Sort 'APorts' according to 'LinkState'. This converts the
-- 'APorts' as (subject port, target port) into (source port,
-- destination port).
alignAPortsToLinkDirection :: LinkSample n APorts -> LinkSample n APorts
alignAPortsToLinkDirection ls = ls { lsLinkAttributes = updated }
where
updated = case lsLinkState ls of
LinkToSubject -> swapAPorts $ lsLinkAttributes ls
_ -> lsLinkAttributes ls