module Development.Bake.Server.Brains(
brains, Neuron(..)
) where
import Development.Bake.Message
import Development.Bake.Type
import Development.Bake.Server.Type
import Data.Maybe
import Control.Monad
import Data.List.Extra
data Neuron
= Sleep
| Task Question
| Update
| Reject Patch (Maybe Test)
| Broken (Maybe Test)
deriving Show
brains :: (Test -> TestInfo Test) -> Server -> Ping -> Neuron
brains _ Server{active=(_, [])} _ = Sleep
brains info Server{..} Ping{..}
| allTestsPass active = Update
| t:_ <- minimumRelation dependsMay $ failingTests active = erroneous t active
| otherwise = let next = filter (suitableTest active) $ allTests active
in taskMay active $ listToMaybe next
where
taskMay c t = maybe Sleep (\t -> Task $ Question c t (threadsForTest t) pClient) t
dependsMay Nothing = []
dependsMay (Just t) = Nothing : map Just (testRequire $ info t)
erroneous t (s, o@(unsnoc -> Just (ps,p))) =
case (stateTest (s, o) t, stateTest (s, ps) t) of
(Just True, _) -> error "logical inconsistentcy in brains, expected erroneous test"
(Just False, Just True) -> Reject p t
(Just False, Just False) -> erroneous t (s,ps)
(Nothing, _) -> taskMay (s, o ) $ scheduleTest (s, o ) t
(_, Nothing) -> taskMay (s, ps) $ scheduleTest (s, ps) t
erroneous t (s, []) = Broken t
allTests c = (Nothing:) $ map Just $ concat $ take 1 $
map (uncurry (++) . aTests . snd) $ success' $ test' Nothing $ answered' $ candidate' c it
allTestsPass c = flip all (allTests c) $ \t ->
not $ null $ success' $ test' t $ answered' $ candidate' c it
failingTests c = map (qTest . fst) $ failure' $ answered' $ candidate' c it
threadsForTest = maybe 1 (fromMaybe pMaxThreads . testThreads . info)
suitableTest c t
| threadsForTest t > pNowThreads = False
suitableTest c Nothing
| null $ self' $ test' Nothing $ candidate' c it
= True
suitableTest c t@(Just tt)
| [clientTests] <- map (fst . aTests . snd) $ self' $ success' $ test' Nothing $ answered' $ candidate' c it
, tt `elem` clientTests
, null $ test' t $ self' $ candidate' c it
, clientDone <- map (qTest . fst) $ success' $ answered' $ self' $ candidate' c it
, all (`elem` clientDone) $ map Just $ testRequire $ info tt
= True
suitableTest _ _ = False
stateTest c t = fmap aSuccess $ join $ fmap snd $ listToMaybe $ test' t $ candidate' c it
scheduleTest c Nothing =
if suitableTest c Nothing then Just Nothing else Nothing
scheduleTest c t@(Just tt)
| [clientTests] <- map (fst . aTests . snd) $ self' $ success' $ test' Nothing $ answered' $ candidate' c it
, tt `elem` clientTests
= listToMaybe $ filter (suitableTest c) $ transitiveClosure dependsMay t
scheduleTest c t@(Just tt)
| null $ self' $ test' Nothing $ candidate' c it
= Just Nothing
scheduleTest _ _ = Nothing
it = [(q,a) | (_,q,a) <- history]
candidate' c = filter ((==) c . qCandidate . fst)
test' t = filter ((==) t . qTest . fst)
self' = filter ((==) pClient . qClient . fst)
success' = filter (aSuccess . snd)
failure' = filter (not . aSuccess . snd)
answered' x = [(q,a) | (q,Just a) <- x]
transitiveClosure :: Eq a => (a -> [a]) -> a -> [a]
transitiveClosure f = nub . g
where g x = x : concatMap g (f x)
minimumRelation :: Eq a => (a -> [a]) -> [a] -> [a]
minimumRelation f (x:xs) = [x | disjoint (transitiveClosure f x) xs] ++ minimumRelation f xs
minimumRelation f [] = []