2017-03-02 01:06:58 +03:00
|
|
|
module GitmonClientSpec where
|
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
import Control.Exception
|
2017-03-02 01:06:58 +03:00
|
|
|
import Data.Aeson
|
|
|
|
import Data.Aeson.Types
|
2017-03-24 02:12:11 +03:00
|
|
|
import Data.ByteString.Char8 (ByteString, pack, unpack)
|
2017-03-02 03:53:13 +03:00
|
|
|
import Data.Foldable
|
2017-03-24 03:05:57 +03:00
|
|
|
import Data.HashMap.Lazy (empty)
|
2017-03-24 03:08:21 +03:00
|
|
|
import Data.Maybe (fromMaybe)
|
2017-03-24 03:05:57 +03:00
|
|
|
import Data.Text hiding (empty)
|
2017-03-02 01:06:58 +03:00
|
|
|
import Git.Libgit2
|
|
|
|
import Git.Repository
|
|
|
|
import Git.Types hiding (Object)
|
|
|
|
import GitmonClient
|
|
|
|
import Network.Socket hiding (recv)
|
|
|
|
import Network.Socket.ByteString
|
2017-03-02 01:48:39 +03:00
|
|
|
import Prelude hiding (lookup)
|
2017-03-03 00:16:38 +03:00
|
|
|
import Prologue (liftIO, runReaderT)
|
2017-03-02 01:48:39 +03:00
|
|
|
import System.Environment (setEnv)
|
2017-03-03 00:16:38 +03:00
|
|
|
import Test.Hspec hiding (shouldBe, shouldSatisfy, shouldThrow, anyErrorCall)
|
2017-03-02 01:06:58 +03:00
|
|
|
import Test.Hspec.Expectations.Pretty
|
2017-03-24 02:12:11 +03:00
|
|
|
import Text.Regex
|
2017-03-02 01:06:58 +03:00
|
|
|
|
|
|
|
spec :: Spec
|
2017-03-22 00:49:24 +03:00
|
|
|
spec =
|
2017-03-02 01:06:58 +03:00
|
|
|
describe "gitmon" $ do
|
2017-03-02 03:57:32 +03:00
|
|
|
let wd = "test/fixtures/git/examples/all-languages.git"
|
2017-03-22 00:49:24 +03:00
|
|
|
|
2017-03-07 19:46:44 +03:00
|
|
|
it "receives commands in order" . withSocketPair $ \(_, server, socketFactory) ->
|
2017-03-02 03:57:32 +03:00
|
|
|
withRepository lgFactory wd $ do
|
2017-03-03 00:16:38 +03:00
|
|
|
liftIO $ sendAll server "continue"
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-07 19:46:44 +03:00
|
|
|
commit <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
2017-03-02 01:06:58 +03:00
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
let [updateData, scheduleData, finishData] = infoToCommands info
|
2017-03-02 01:06:58 +03:00
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
shouldBe (commitOid commit) object
|
2017-03-24 02:12:11 +03:00
|
|
|
shouldBe updateData (Just "update")
|
|
|
|
shouldBe scheduleData (Just "schedule")
|
|
|
|
shouldBe finishData (Just "finish")
|
2017-03-02 01:06:58 +03:00
|
|
|
|
2017-03-07 19:46:44 +03:00
|
|
|
it "receives update command with correct data" . withSocketPair $ \(_, server, socketFactory) ->
|
2017-03-02 01:48:39 +03:00
|
|
|
withRepository lgFactory wd $ do
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
setEnv "GIT_DIR" wd
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_real_ip" "127.0.0.1"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_name" "examples/all-languages"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_id" "uint:10"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_user_id" "uint:20"
|
|
|
|
sendAll server "continue"
|
2017-03-02 01:48:39 +03:00
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-07 19:46:44 +03:00
|
|
|
commit <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
2017-03-02 01:48:39 +03:00
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
2017-03-02 03:53:13 +03:00
|
|
|
let [updateData, _, finishData] = infoToData info
|
2017-03-02 01:48:39 +03:00
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
shouldBe (commitOid commit) object
|
|
|
|
shouldBe (either id gitDir updateData) wd
|
|
|
|
shouldBe (either id program updateData) "cat-file"
|
|
|
|
shouldBe (either Just realIP updateData) (Just "127.0.0.1")
|
|
|
|
shouldBe (either Just repoName updateData) (Just "examples/all-languages")
|
|
|
|
shouldBe (either (const $ Just 1) repoID updateData) (Just 10)
|
|
|
|
shouldBe (either (const $ Just 1) userID updateData) (Just 20)
|
|
|
|
shouldBe (either id via updateData) "semantic-diff"
|
|
|
|
|
|
|
|
shouldSatisfy (either (const (-1)) cpu finishData) (>= 0)
|
|
|
|
shouldSatisfy (either (const (-1)) diskReadBytes finishData) (>= 0)
|
|
|
|
shouldSatisfy (either (const (-1)) diskWriteBytes finishData) (>= 0)
|
|
|
|
shouldSatisfy (either (const (-1)) resultCode finishData) (>= 0)
|
|
|
|
|
|
|
|
it "reads Nothing for user_id and repo_id when valid prefix but invalid value" . withSocketPair $ \(_, server, socketFactory) ->
|
|
|
|
withRepository lgFactory wd $ do
|
|
|
|
liftIO $ do
|
|
|
|
setEnv "GIT_DIR" wd
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_real_ip" "127.0.0.1"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_name" "examples/all-languages"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_id" "uint:not_valid"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_user_id" "uint:not_valid"
|
|
|
|
sendAll server "continue"
|
2017-03-21 20:33:37 +03:00
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-21 20:33:37 +03:00
|
|
|
_ <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
|
|
|
let [updateData, _, _] = infoToData info
|
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
shouldBe (either (const $ Just 1) repoID updateData) Nothing
|
|
|
|
shouldBe (either (const $ Just 1) userID updateData) Nothing
|
2017-03-21 20:34:33 +03:00
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
it "reads Nothing for user_id and repo_id when valid prefix but value is preceeded by invalid chars" . withSocketPair $ \(_, server, socketFactory) ->
|
|
|
|
withRepository lgFactory wd $ do
|
|
|
|
liftIO $ do
|
|
|
|
setEnv "GIT_DIR" wd
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_real_ip" "127.0.0.1"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_name" "examples/all-languages"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_id" "uint:abc100"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_user_id" "uint:abc100"
|
|
|
|
sendAll server "continue"
|
2017-03-21 20:34:33 +03:00
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-21 20:34:33 +03:00
|
|
|
_ <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
|
|
|
let [updateData, _, _] = infoToData info
|
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
shouldBe (either (const $ Just 1) repoID updateData) Nothing
|
|
|
|
shouldBe (either (const $ Just 1) userID updateData) Nothing
|
2017-03-21 20:34:33 +03:00
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
it "reads Nothing for user_id and repo_id when valid prefix but value is proceeded by invalid chars" . withSocketPair $ \(_, server, socketFactory) ->
|
|
|
|
withRepository lgFactory wd $ do
|
|
|
|
liftIO $ do
|
|
|
|
setEnv "GIT_DIR" wd
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_real_ip" "127.0.0.1"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_name" "examples/all-languages"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_id" "uint:100abc"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_user_id" "uint:100abc"
|
|
|
|
sendAll server "continue"
|
2017-03-21 20:35:03 +03:00
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-21 20:35:03 +03:00
|
|
|
_ <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
|
|
|
let [updateData, _, _] = infoToData info
|
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
shouldBe (either (const $ Just 1) repoID updateData) Nothing
|
|
|
|
shouldBe (either (const $ Just 1) userID updateData) Nothing
|
2017-03-21 20:35:22 +03:00
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
it "reads Nothing for user_id and repo_id when missing prefix but value is valid" . withSocketPair $ \(_, server, socketFactory) ->
|
|
|
|
withRepository lgFactory wd $ do
|
|
|
|
liftIO $ do
|
|
|
|
setEnv "GIT_DIR" wd
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_real_ip" "127.0.0.1"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_name" "examples/all-languages"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_repo_id" "100"
|
|
|
|
setEnv "GIT_SOCKSTAT_VAR_user_id" "100"
|
|
|
|
sendAll server "continue"
|
2017-03-21 20:35:22 +03:00
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-21 20:35:22 +03:00
|
|
|
_ <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
|
|
|
let [updateData, _, _] = infoToData info
|
|
|
|
|
2017-03-22 00:49:24 +03:00
|
|
|
liftIO $ do
|
|
|
|
shouldBe (either (const $ Just 1) repoID updateData) Nothing
|
|
|
|
shouldBe (either (const $ Just 1) userID updateData) Nothing
|
2017-03-21 20:35:22 +03:00
|
|
|
|
2017-03-07 19:46:44 +03:00
|
|
|
it "returns the correct git result if the socket is unavailable" . withSocketPair $ \(client, server, socketFactory) ->
|
2017-03-02 04:24:43 +03:00
|
|
|
withRepository lgFactory wd $ do
|
|
|
|
liftIO $ close client
|
|
|
|
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-07 19:46:44 +03:00
|
|
|
commit <- reportGitmon' socketFactory "cat-file" $ lookupCommit object
|
2017-03-02 04:24:43 +03:00
|
|
|
info <- liftIO $ recv server 1024
|
|
|
|
|
|
|
|
liftIO $ shouldBe (commitOid commit) object
|
|
|
|
liftIO $ shouldBe "" info
|
|
|
|
|
2017-03-07 19:46:44 +03:00
|
|
|
it "throws if schedule response is fail" . withSocketPair $ \(_, server, socketFactory) ->
|
2017-03-03 00:16:38 +03:00
|
|
|
withRepository lgFactory wd $ do
|
|
|
|
repo <- getRepository
|
|
|
|
liftIO $ sendAll server "fail too busy"
|
2017-03-24 02:12:11 +03:00
|
|
|
object <- parseObjOid (Data.Text.pack "dfac8fd681b0749af137aebf3203e77a06fbafc2")
|
2017-03-03 00:16:38 +03:00
|
|
|
|
2017-03-08 22:10:57 +03:00
|
|
|
liftIO $ shouldThrow (runReaderT (reportGitmon' socketFactory "cat-file" (lookupCommit object)) repo) gitmonException
|
|
|
|
|
|
|
|
gitmonException :: GitmonException -> Bool
|
|
|
|
gitmonException = const True
|
2017-03-03 00:16:38 +03:00
|
|
|
|
2017-03-07 19:46:44 +03:00
|
|
|
withSocketPair :: ((Socket, Socket, SocketFactory) -> IO c) -> IO c
|
|
|
|
withSocketPair = bracket create release
|
|
|
|
where
|
|
|
|
create = do
|
|
|
|
(client, server) <- socketPair AF_UNIX Stream defaultProtocol
|
|
|
|
pure (client, server, SocketFactory (\f -> f client))
|
|
|
|
release (client, server, _) = do
|
|
|
|
close client
|
|
|
|
close server
|
2017-03-02 21:22:18 +03:00
|
|
|
|
2017-03-02 01:06:58 +03:00
|
|
|
infoToCommands :: ByteString -> [Maybe Text]
|
2017-03-24 02:12:11 +03:00
|
|
|
infoToCommands input = command' . toObject <$> extract regex input
|
2017-03-02 01:06:58 +03:00
|
|
|
where
|
|
|
|
command' :: Object -> Maybe Text
|
|
|
|
command' = parseMaybe (.: "command")
|
|
|
|
|
2017-03-02 03:53:13 +03:00
|
|
|
infoToData :: ByteString -> [Either String ProcessData]
|
2017-03-24 02:12:11 +03:00
|
|
|
infoToData input = data' . toObject <$> extract regex input
|
|
|
|
where
|
|
|
|
data' = parseEither parser
|
|
|
|
parser o = do
|
|
|
|
dataO <- o .: "data"
|
|
|
|
asum [ ProcessUpdateData <$> (dataO .: "git_dir") <*> (dataO .: "program") <*> (dataO .:? "real_ip") <*> (dataO .:? "repo_name") <*> (dataO .:? "repo_id") <*> (dataO .:? "user_id") <*> (dataO .: "via")
|
|
|
|
, ProcessFinishData <$> (dataO .: "cpu") <*> (dataO .: "disk_read_bytes") <*> (dataO .: "disk_write_bytes") <*> (dataO .: "result_code")
|
|
|
|
, pure ProcessScheduleData
|
|
|
|
]
|
2017-03-02 01:06:58 +03:00
|
|
|
|
2017-03-02 01:48:39 +03:00
|
|
|
toObject :: ByteString -> Object
|
2017-03-24 03:05:57 +03:00
|
|
|
toObject input = fromMaybe empty (decodeStrict input)
|
2017-03-24 02:12:11 +03:00
|
|
|
|
|
|
|
regex :: Regex
|
2017-03-24 03:33:17 +03:00
|
|
|
regex = mkRegexWithOpts "(\\{.*\"update\".*\"\\}\\})(\\{.*\"schedule\"\\})(\\{.*\"finish\".*\\}\\})" False True
|
2017-03-24 02:12:11 +03:00
|
|
|
|
|
|
|
extract :: Regex -> ByteString -> [ByteString]
|
2017-03-24 03:05:57 +03:00
|
|
|
extract regex input = Data.ByteString.Char8.pack <$> fromMaybe [""] (matchRegex regex (Data.ByteString.Char8.unpack input))
|