@@ -21,7 +21,7 @@ module Roboservant.Direct
22 -- TODO come up with something smarter than exporting all this, we should
22 -- TODO come up with something smarter than exporting all this, we should
23 -- have some nice error-display functions
23 -- have some nice error-display functions
24− , RoboservantException(..), FuzzState(..), FuzzOp(..)
24+ , RoboservantException(..), FuzzState(..), FuzzOp(..), FailureType(..), Report(..)
@@ -36,7 +36,6 @@ import Data.Maybe (mapMaybe)
36import Data.Typeable (TypeRep)
36import Data.Typeable (TypeRep)
37import Servant (Endpoints, Proxy (Proxy), Server, ServerError(..))
37import Servant (Endpoints, Proxy (Proxy), Server, ServerError(..))
38import System.Random(StdGen,randomR,mkStdGen)
38import System.Random(StdGen,randomR,mkStdGen)
39−import System.Timeout.Lifted(timeout)
40import qualified Data.List.NonEmpty as NEL
39import qualified Data.List.NonEmpty as NEL
41import qualified Data.Map.Strict as Map
40import qualified Data.Map.Strict as Map
42import Data.Time.Clock
41import Data.Time.Clock
@@ -50,16 +49,19 @@ import Roboservant.Types
52data RoboservantException
51data RoboservantException
53− = RoboservantException FailureType (Maybe SomeException) Int FuzzState
52+ = RoboservantException
53+ { failureReason :: FailureType
54+ , serverException :: Maybe SomeException
55+ , fuzzState :: FuzzState
54− deriving (Show)
56+ } deriving (Show)
55−-- we believe in nussink, lebowski
57+
56instance Exception RoboservantException
58instance Exception RoboservantException
58data FailureType
60data FailureType
59 = ServerCrashed
61 = ServerCrashed
60 | CheckerFailed
62 | CheckerFailed
61 | NoPossibleMoves
63 | NoPossibleMoves
62− | InsufficientCoverage
64+ | InsufficientCoverage Double
63 deriving (Show,Eq)
65 deriving (Show,Eq)
@@ -90,8 +92,9 @@ data StopReason
90 deriving (Show,Eq)
92 deriving (Show,Eq)
92data Report = Report
94data Report = Report
93− { textual :: String }
95+ { textual :: String
96+ , rsException :: RoboservantException}
94− deriving (Show,Eq)
97+ deriving (Show)
96fuzz :: forall api. (FlattenServer api, ToReifiedApi (Endpoints api))
99fuzz :: forall api. (FlattenServer api, ToReifiedApi (Endpoints api))
97 => Server api
100 => Server api
@@ -116,16 +119,20 @@ fuzz server Config{..} checker = handle (pure . Just . formatException) $ do
117 -- something less terrible later
120 -- something less terrible later
118 formatException :: RoboservantException -> Report
121 formatException :: RoboservantException -> Report
119− formatException = Report . show
122+ formatException r@(RoboservantException failureType exception _state) = Report
120−
123+ (unlines [ show failureType , show exception ])
121 -- evaluateCoverage :: FuzzState -> m ()
126 -- evaluateCoverage :: FuzzState -> m ()
122 evaluateCoverage f@FuzzState{..}
127 evaluateCoverage f@FuzzState{..}
123− | hitRoutes / totalRoutes > coverageThreshold = do
128+ | coverage > coverageThreshold = pure ()
124− liftIO $ print ("passed coverage", hitRoutes, totalRoutes)
129+ | otherwise = do
125− pure ()
130+ liftIO $ do putStrLn "api endpoints covered"
131+ mapM_ print (Set.toList $ Set.fromList $ map apiOffset path)
126− | otherwise = throw $ RoboservantException InsufficientCoverage Nothing routeCount f
132+ throw $ RoboservantException (InsufficientCoverage coverage) Nothing f
127 where hitRoutes = (fromIntegral . Set.size . Set.fromList $ map apiOffset path)
133 where hitRoutes = (fromIntegral . Set.size . Set.fromList $ map apiOffset path)
128 totalRoutes = (fromIntegral routeCount)
134 totalRoutes = (fromIntegral routeCount)
135+ coverage = hitRoutes / totalRoutes
131 untilDone :: MonadIO m => (Integer,UTCTime) -> m a -> m StopReason
138 untilDone :: MonadIO m => (Integer,UTCTime) -> m a -> m StopReason
@@ -143,7 +150,7 @@ fuzz server Config{..} checker = handle (pure . Just . formatException) $ do
144 elementOrFail :: (MonadState FuzzState m, MonadIO m)
151 elementOrFail :: (MonadState FuzzState m, MonadIO m)
145 => [a] -> m a
152 => [a] -> m a
146− elementOrFail [] = liftIO . throw . RoboservantException NoPossibleMoves Nothing routeCount =<< get
153+ elementOrFail [] = liftIO . throw . RoboservantException NoPossibleMoves Nothing =<< get
147 elementOrFail l = do
154 elementOrFail l = do
148 st <- get
155 st <- get
149 let (index,newGen) = randomR (0, length l - 1) (currentRng st)
156 let (index,newGen) = randomR (0, length l - 1) (currentRng st)
@@ -212,10 +219,10 @@ fuzz server Config{..} checker = handle (pure . Just . formatException) $ do
212 op <- genOp
219 op <- genOp
213 catches (execute op)
220 catches (execute op)
214 [ Handler (\(e :: SomeAsyncException) -> throw e)
221 [ Handler (\(e :: SomeAsyncException) -> throw e)
215− , Handler (\(e :: SomeException) -> throw . RoboservantException ServerCrashed (Just e) routeCount =<< get)
222+ , Handler (\(e :: SomeException) -> throw . RoboservantException ServerCrashed (Just e) =<< get)
217 catch (liftIO checker)
224 catch (liftIO checker)
218− (\(e :: SomeException) -> throw . RoboservantException CheckerFailed (Just e) routeCount =<< get)
225+ (\(e :: SomeException) -> throw . RoboservantException CheckerFailed (Just e) =<< get)
220 -- actions <-
227 -- actions <-
221 -- forAll $ do
228 -- forAll $ do