Refactor error types returned by the library
This commit is contained in:
parent
5f1ee7fc67
commit
f26fbc82a7
@ -41,6 +41,7 @@ library
|
|||||||
, cryptonite
|
, cryptonite
|
||||||
, cryptonite-conduit
|
, cryptonite-conduit
|
||||||
, data-default
|
, data-default
|
||||||
|
, exceptions
|
||||||
, filepath
|
, filepath
|
||||||
, http-client
|
, http-client
|
||||||
, http-conduit
|
, http-conduit
|
||||||
@ -83,6 +84,7 @@ test-suite minio-hs-test
|
|||||||
, cryptonite
|
, cryptonite
|
||||||
, cryptonite-conduit
|
, cryptonite-conduit
|
||||||
, data-default
|
, data-default
|
||||||
|
, exceptions
|
||||||
, filepath
|
, filepath
|
||||||
, http-client
|
, http-client
|
||||||
, http-conduit
|
, http-conduit
|
||||||
@ -110,6 +112,7 @@ test-suite minio-hs-test
|
|||||||
, NoImplicitPrelude
|
, NoImplicitPrelude
|
||||||
, MultiParamTypeClasses
|
, MultiParamTypeClasses
|
||||||
, MultiWayIf
|
, MultiWayIf
|
||||||
|
, ScopedTypeVariables
|
||||||
, RankNTypes
|
, RankNTypes
|
||||||
, TupleSections
|
, TupleSections
|
||||||
, TypeFamilies
|
, TypeFamilies
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
module Network.Minio.Data where
|
module Network.Minio.Data where
|
||||||
|
|
||||||
import Control.Monad.Base
|
import Control.Monad.Base
|
||||||
|
import qualified Control.Monad.Catch as MC
|
||||||
import Control.Monad.Trans.Control
|
import Control.Monad.Trans.Control
|
||||||
import Control.Monad.Trans.Resource
|
import Control.Monad.Trans.Resource
|
||||||
import qualified Data.ByteString as B
|
import qualified Data.ByteString as B
|
||||||
@ -149,25 +150,8 @@ getPathFromRI ri = B.concat $ parts
|
|||||||
getRegionFromRI :: RequestInfo -> Text
|
getRegionFromRI :: RequestInfo -> Text
|
||||||
getRegionFromRI ri = maybe "us-east-1" identity (riRegion ri)
|
getRegionFromRI ri = maybe "us-east-1" identity (riRegion ri)
|
||||||
|
|
||||||
-- | Various validation errors
|
|
||||||
data MErrV = MErrVSinglePUTSizeExceeded Int64
|
|
||||||
| MErrVPutSizeExceeded Int64
|
|
||||||
| MErrVETagHeaderNotFound
|
|
||||||
deriving (Show)
|
|
||||||
|
|
||||||
-- |
|
|
||||||
-- Minio Error data type for various errors/exceptions caught and
|
|
||||||
-- returned.
|
|
||||||
data MinioErr = MErrMsg ByteString -- generic
|
|
||||||
| MErrHttp HttpException -- http exceptions
|
|
||||||
| MErrXml ByteString -- XML parsing/generation errors
|
|
||||||
| MErrService ByteString -- error response from service
|
|
||||||
| MErrValidation MErrV -- client-side validation errors
|
|
||||||
| MErrIO IOException -- exceptions while working with files
|
|
||||||
deriving (Show)
|
|
||||||
|
|
||||||
newtype Minio a = Minio {
|
newtype Minio a = Minio {
|
||||||
unMinio :: ReaderT MinioConn (ExceptT MinioErr (ResourceT IO)) a
|
unMinio :: ReaderT MinioConn (ResourceT IO) a
|
||||||
}
|
}
|
||||||
deriving (
|
deriving (
|
||||||
Functor
|
Functor
|
||||||
@ -175,14 +159,14 @@ newtype Minio a = Minio {
|
|||||||
, Monad
|
, Monad
|
||||||
, MonadIO
|
, MonadIO
|
||||||
, MonadReader MinioConn
|
, MonadReader MinioConn
|
||||||
, MonadError MinioErr
|
|
||||||
, MonadThrow
|
, MonadThrow
|
||||||
|
, MC.MonadCatch
|
||||||
, MonadBase IO
|
, MonadBase IO
|
||||||
, MonadResource
|
, MonadResource
|
||||||
)
|
)
|
||||||
|
|
||||||
instance MonadBaseControl IO Minio where
|
instance MonadBaseControl IO Minio where
|
||||||
type StM Minio a = Either MinioErr a
|
type StM Minio a = a
|
||||||
liftBaseWith f = Minio $ liftBaseWith $ \q -> f (q . unMinio)
|
liftBaseWith f = Minio $ liftBaseWith $ \q -> f (q . unMinio)
|
||||||
restoreM = Minio . restoreM
|
restoreM = Minio . restoreM
|
||||||
|
|
||||||
@ -203,7 +187,42 @@ connect ci = do
|
|||||||
runMinio :: ConnectInfo -> Minio a -> ResourceT IO (Either MinioErr a)
|
runMinio :: ConnectInfo -> Minio a -> ResourceT IO (Either MinioErr a)
|
||||||
runMinio ci m = do
|
runMinio ci m = do
|
||||||
conn <- liftIO $ connect ci
|
conn <- liftIO $ connect ci
|
||||||
runExceptT . flip runReaderT conn . unMinio $ m
|
flip runReaderT conn . unMinio $
|
||||||
|
(m >>= (return . Right))
|
||||||
|
`MC.catch` handlerME
|
||||||
|
`MC.catch` handlerHE
|
||||||
|
`MC.catch` handlerFE
|
||||||
|
where
|
||||||
|
handlerME = return . Left . ME
|
||||||
|
handlerHE = return . Left . MEHttp
|
||||||
|
handlerFE = return . Left . MEFile
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
s3Name :: Text -> Name
|
s3Name :: Text -> Name
|
||||||
s3Name s = Name s (Just "http://s3.amazonaws.com/doc/2006-03-01/") Nothing
|
s3Name s = Name s (Just "http://s3.amazonaws.com/doc/2006-03-01/") Nothing
|
||||||
|
|
||||||
|
---------------------------------
|
||||||
|
-- Errors
|
||||||
|
---------------------------------
|
||||||
|
-- | Various validation errors
|
||||||
|
data MErrV = MErrVSinglePUTSizeExceeded Int64
|
||||||
|
| MErrVPutSizeExceeded Int64
|
||||||
|
| MErrVETagHeaderNotFound
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
-- | Errors thrown by the library
|
||||||
|
data MinioErr = ME MError
|
||||||
|
| MEHttp HttpException
|
||||||
|
| MEFile IOException
|
||||||
|
deriving (Show)
|
||||||
|
|
||||||
|
instance Exception MinioErr
|
||||||
|
|
||||||
|
-- | Library internal errors
|
||||||
|
data MError = XMLParseError Text
|
||||||
|
| ResponseError (NC.Response LByteString)
|
||||||
|
| ValidationError MErrV
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance Exception MError
|
||||||
|
|||||||
@ -66,7 +66,7 @@ putObject b o (ODFile fp sizeMay) = do
|
|||||||
etag <- putObjectSingle b o [] h 0 size
|
etag <- putObjectSingle b o [] h 0 size
|
||||||
R.release rKey
|
R.release rKey
|
||||||
return etag
|
return etag
|
||||||
| size > maxObjectSize -> throwError $ MErrValidation $
|
| size > maxObjectSize -> R.throwM $ ValidationError $
|
||||||
MErrVPutSizeExceeded size
|
MErrVPutSizeExceeded size
|
||||||
| isSeekable -> parallelMultipartUpload b o fp size
|
| isSeekable -> parallelMultipartUpload b o fp size
|
||||||
| otherwise -> sequentialMultipartUpload b o (Just size) $
|
| otherwise -> sequentialMultipartUpload b o (Just size) $
|
||||||
|
|||||||
@ -35,6 +35,7 @@ module Network.Minio.S3API
|
|||||||
|
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Resource
|
||||||
import qualified Data.Conduit as C
|
import qualified Data.Conduit as C
|
||||||
import Data.Default (def)
|
import Data.Default (def)
|
||||||
import qualified Network.HTTP.Conduit as NC
|
import qualified Network.HTTP.Conduit as NC
|
||||||
@ -96,7 +97,7 @@ putObjectSingle :: Bucket -> Object -> [HT.Header] -> Handle -> Int64
|
|||||||
putObjectSingle bucket object headers h offset size = do
|
putObjectSingle bucket object headers h offset size = do
|
||||||
-- check length is within single PUT object size.
|
-- check length is within single PUT object size.
|
||||||
when (size > maxSinglePutObjectSizeBytes) $
|
when (size > maxSinglePutObjectSizeBytes) $
|
||||||
throwError $ MErrValidation $ MErrVSinglePUTSizeExceeded size
|
throwM $ ValidationError $ MErrVSinglePUTSizeExceeded size
|
||||||
|
|
||||||
-- content-length header is automatically set by library.
|
-- content-length header is automatically set by library.
|
||||||
resp <- executeRequest $
|
resp <- executeRequest $
|
||||||
@ -110,7 +111,7 @@ putObjectSingle bucket object headers h offset size = do
|
|||||||
let rheaders = NC.responseHeaders resp
|
let rheaders = NC.responseHeaders resp
|
||||||
etag = getETagHeader rheaders
|
etag = getETagHeader rheaders
|
||||||
maybe
|
maybe
|
||||||
(throwError $ MErrValidation MErrVETagHeaderNotFound)
|
(throwM $ ValidationError MErrVETagHeaderNotFound)
|
||||||
return etag
|
return etag
|
||||||
|
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ putObjectPart bucket object uploadId partNumber headers payload = do
|
|||||||
let rheaders = NC.responseHeaders resp
|
let rheaders = NC.responseHeaders resp
|
||||||
etag = getETagHeader rheaders
|
etag = getETagHeader rheaders
|
||||||
maybe
|
maybe
|
||||||
(throwError $ MErrValidation MErrVETagHeaderNotFound)
|
(throwM $ ValidationError MErrVETagHeaderNotFound)
|
||||||
(return . PartInfo partNumber) etag
|
(return . PartInfo partNumber) etag
|
||||||
where
|
where
|
||||||
params = [
|
params = [
|
||||||
|
|||||||
@ -3,9 +3,10 @@ module Network.Minio.Utils where
|
|||||||
import qualified Control.Concurrent.Async.Lifted as A
|
import qualified Control.Concurrent.Async.Lifted as A
|
||||||
import qualified Control.Concurrent.QSem as Q
|
import qualified Control.Concurrent.QSem as Q
|
||||||
import qualified Control.Exception.Lifted as ExL
|
import qualified Control.Exception.Lifted as ExL
|
||||||
|
import Control.Monad.Catch (throwM)
|
||||||
|
import qualified Control.Monad.Catch as MC
|
||||||
import Control.Monad.Trans.Control (liftBaseOp_, StM)
|
import Control.Monad.Trans.Control (liftBaseOp_, StM)
|
||||||
import qualified Control.Monad.Trans.Resource as R
|
import qualified Control.Monad.Trans.Resource as R
|
||||||
import qualified Data.ByteString.Lazy as LBS
|
|
||||||
import qualified Data.Conduit as C
|
import qualified Data.Conduit as C
|
||||||
import Data.Text.Encoding.Error (lenientDecode)
|
import Data.Text.Encoding.Error (lenientDecode)
|
||||||
import qualified Network.HTTP.Client as NClient
|
import qualified Network.HTTP.Client as NClient
|
||||||
@ -18,26 +19,27 @@ import Lib.Prelude
|
|||||||
|
|
||||||
import Network.Minio.Data
|
import Network.Minio.Data
|
||||||
|
|
||||||
allocateReadFile :: (R.MonadResource m, MonadError MinioErr m)
|
allocateReadFile :: (R.MonadResource m, R.MonadResourceBase m)
|
||||||
=> FilePath -> m (R.ReleaseKey, Handle)
|
=> FilePath -> m (R.ReleaseKey, Handle)
|
||||||
allocateReadFile fp = do
|
allocateReadFile fp = do
|
||||||
(rk, hdlE) <- R.allocate (openReadFile fp) cleanup
|
(rk, hdlE) <- R.allocate (openReadFile fp) cleanup
|
||||||
either (throwError . MErrIO) (return . (rk,)) hdlE
|
either (MC.throwM . MEFile) (return . (rk,)) hdlE
|
||||||
where
|
where
|
||||||
openReadFile f = ExL.try $ IO.openBinaryFile f IO.ReadMode
|
openReadFile f = ExL.try $ IO.openBinaryFile f IO.ReadMode
|
||||||
cleanup = either (const $ return ()) IO.hClose
|
cleanup = either (const $ return ()) IO.hClose
|
||||||
|
|
||||||
getFileSize :: (R.MonadResourceBase m, R.MonadResource m, MonadError MinioErr m)
|
getFileSize :: (R.MonadResourceBase m, R.MonadResource m)
|
||||||
=> Handle -> m (Either IOException Int64)
|
=> Handle -> m (Either IOException Int64)
|
||||||
getFileSize h = ExL.try $ liftIO $ fromIntegral <$> IO.hFileSize h
|
getFileSize h = ExL.try $ liftIO $ fromIntegral <$> IO.hFileSize h
|
||||||
|
|
||||||
isFileSeekable :: (R.MonadResource m, MonadError MinioErr m)
|
isFileSeekable :: (R.MonadResource m, R.MonadResourceBase m)
|
||||||
=> FilePath -> m Bool
|
=> FilePath -> m Bool
|
||||||
isFileSeekable fp = do
|
isFileSeekable fp = do
|
||||||
(rKey, h) <- allocateReadFile fp
|
(rKey, h) <- allocateReadFile fp
|
||||||
isSeekable <- liftIO $ IO.hIsSeekable h
|
resE <- liftIO $ try $ IO.hIsSeekable h
|
||||||
R.release rKey
|
R.release rKey
|
||||||
return isSeekable
|
either (MC.throwM . MEFile) return resE
|
||||||
|
|
||||||
|
|
||||||
lookupHeader :: HT.HeaderName -> [HT.Header] -> Maybe ByteString
|
lookupHeader :: HT.HeaderName -> [HT.Header] -> Maybe ByteString
|
||||||
lookupHeader hdr = headMay . map snd . filter (\(h, _) -> h == hdr)
|
lookupHeader hdr = headMay . map snd . filter (\(h, _) -> h == hdr)
|
||||||
@ -52,30 +54,34 @@ isSuccessStatus :: HT.Status -> Bool
|
|||||||
isSuccessStatus sts = let s = HT.statusCode sts
|
isSuccessStatus sts = let s = HT.statusCode sts
|
||||||
in (s >= 200 && s < 300)
|
in (s >= 200 && s < 300)
|
||||||
|
|
||||||
checkEither :: (Monad m, MonadError MinioErr m)
|
httpLbs :: (R.MonadThrow m, MonadIO m)
|
||||||
=> (e -> MinioErr) -> (Either e a) -> m a
|
|
||||||
checkEither f = either (throwError . f) return
|
|
||||||
|
|
||||||
httpLbs :: (MonadError MinioErr m, MonadIO m)
|
|
||||||
=> NC.Request -> NC.Manager
|
=> NC.Request -> NC.Manager
|
||||||
-> m (NC.Response LByteString)
|
-> m (NC.Response LByteString)
|
||||||
httpLbs req mgr = do
|
httpLbs req mgr = do
|
||||||
respE <- liftIO $ try $ NClient.httpLbs req mgr
|
respE <- liftIO $ tryHttpEx $ (NClient.httpLbs req mgr)
|
||||||
resp <- checkEither MErrHttp respE
|
resp <- either throwM return respE
|
||||||
unless (isSuccessStatus $ NC.responseStatus resp) $
|
unless (isSuccessStatus $ NC.responseStatus resp) $
|
||||||
throwError $ MErrService $ LBS.toStrict $ NC.responseBody resp
|
throwM $ ResponseError resp
|
||||||
return resp
|
return resp
|
||||||
|
where
|
||||||
|
tryHttpEx :: (IO (NC.Response LByteString))
|
||||||
|
-> IO (Either NC.HttpException (NC.Response LByteString))
|
||||||
|
tryHttpEx = try
|
||||||
|
|
||||||
http :: (MonadError MinioErr m, R.MonadResourceBase m, R.MonadResource m)
|
http :: (R.MonadResourceBase m, R.MonadResource m)
|
||||||
=> NC.Request -> NC.Manager
|
=> NC.Request -> NC.Manager
|
||||||
-> m (Response (C.ResumableSource m ByteString))
|
-> m (Response (C.ResumableSource m ByteString))
|
||||||
http req mgr = do
|
http req mgr = do
|
||||||
respE <- ExL.try $ NC.http req mgr
|
respE <- tryHttpEx $ NC.http req mgr
|
||||||
resp <- checkEither MErrHttp respE
|
resp <- either throwM return respE
|
||||||
unless (isSuccessStatus $ NC.responseStatus resp) $ do
|
unless (isSuccessStatus $ NC.responseStatus resp) $ do
|
||||||
lbsResp <- NC.lbsResponse resp
|
lbsResp <- NC.lbsResponse resp
|
||||||
throwError $ MErrService $ LBS.toStrict $ NC.responseBody lbsResp
|
throwM $ ResponseError lbsResp
|
||||||
return resp
|
return resp
|
||||||
|
where
|
||||||
|
tryHttpEx :: (R.MonadResourceBase m) => (m a)
|
||||||
|
-> m (Either NC.HttpException a)
|
||||||
|
tryHttpEx = ExL.try
|
||||||
|
|
||||||
-- like mapConcurrently but with a limited number of concurrent
|
-- like mapConcurrently but with a limited number of concurrent
|
||||||
-- threads.
|
-- threads.
|
||||||
|
|||||||
@ -8,7 +8,8 @@ module Network.Minio.XmlParser
|
|||||||
, parseListPartsResponse
|
, parseListPartsResponse
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Data.List (zip3, zip4)
|
import Control.Monad.Trans.Resource
|
||||||
|
import Data.List (zip3, zip4)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import Data.Text.Read (decimal)
|
import Data.Text.Read (decimal)
|
||||||
import Data.Time
|
import Data.Time
|
||||||
@ -32,24 +33,24 @@ s3TimeFormat :: [Char]
|
|||||||
s3TimeFormat = iso8601DateFormat $ Just "%T%QZ"
|
s3TimeFormat = iso8601DateFormat $ Just "%T%QZ"
|
||||||
|
|
||||||
-- | Parse time strings from XML
|
-- | Parse time strings from XML
|
||||||
parseS3XMLTime :: (MonadError MinioErr m) => Text -> m UTCTime
|
parseS3XMLTime :: (MonadThrow m) => Text -> m UTCTime
|
||||||
parseS3XMLTime = either (throwError . MErrXml) return
|
parseS3XMLTime = either (throwM . XMLParseError) return
|
||||||
. parseTimeM True defaultTimeLocale s3TimeFormat
|
. parseTimeM True defaultTimeLocale s3TimeFormat
|
||||||
. T.unpack
|
. T.unpack
|
||||||
|
|
||||||
parseDecimals :: (MonadError MinioErr m, Integral a) => [Text] -> m [a]
|
parseDecimals :: (MonadThrow m, Integral a) => [Text] -> m [a]
|
||||||
parseDecimals numStr = forM numStr $ \str ->
|
parseDecimals numStr = forM numStr $ \str ->
|
||||||
either (throwError . MErrXml . show) return $ fst <$> decimal str
|
either (throwM . XMLParseError . show) return $ fst <$> decimal str
|
||||||
|
|
||||||
s3Elem :: Text -> Axis
|
s3Elem :: Text -> Axis
|
||||||
s3Elem = element . s3Name
|
s3Elem = element . s3Name
|
||||||
|
|
||||||
parseRoot :: (MonadError MinioErr m) => LByteString -> m Cursor
|
parseRoot :: (MonadThrow m) => LByteString -> m Cursor
|
||||||
parseRoot = either (throwError . MErrXml . show) (return . fromDocument)
|
parseRoot = either (throwM . XMLParseError . show) (return . fromDocument)
|
||||||
. parseLBS def
|
. parseLBS def
|
||||||
|
|
||||||
-- | Parse the response XML of a list buckets call.
|
-- | Parse the response XML of a list buckets call.
|
||||||
parseListBuckets :: (MonadError MinioErr m) => LByteString -> m [BucketInfo]
|
parseListBuckets :: (MonadThrow m) => LByteString -> m [BucketInfo]
|
||||||
parseListBuckets xmldata = do
|
parseListBuckets xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
let
|
let
|
||||||
@ -60,27 +61,27 @@ parseListBuckets xmldata = do
|
|||||||
return $ map (\(n, t) -> BucketInfo n t) $ zip names times
|
return $ map (\(n, t) -> BucketInfo n t) $ zip names times
|
||||||
|
|
||||||
-- | Parse the response XML of a location request.
|
-- | Parse the response XML of a location request.
|
||||||
parseLocation :: (MonadError MinioErr m) => LByteString -> m Region
|
parseLocation :: (MonadThrow m) => LByteString -> m Region
|
||||||
parseLocation xmldata = do
|
parseLocation xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
return $ T.concat $ r $/ content
|
return $ T.concat $ r $/ content
|
||||||
|
|
||||||
-- | Parse the response XML of an newMultipartUpload call.
|
-- | Parse the response XML of an newMultipartUpload call.
|
||||||
parseNewMultipartUpload :: (MonadError MinioErr m)
|
parseNewMultipartUpload :: (MonadThrow m)
|
||||||
=> LByteString -> m UploadId
|
=> LByteString -> m UploadId
|
||||||
parseNewMultipartUpload xmldata = do
|
parseNewMultipartUpload xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
return $ T.concat $ r $// element (s3Name "UploadId") &/ content
|
return $ T.concat $ r $// element (s3Name "UploadId") &/ content
|
||||||
|
|
||||||
-- | Parse the response XML of completeMultipartUpload call.
|
-- | Parse the response XML of completeMultipartUpload call.
|
||||||
parseCompleteMultipartUploadResponse :: (MonadError MinioErr m)
|
parseCompleteMultipartUploadResponse :: (MonadThrow m)
|
||||||
=> LByteString -> m ETag
|
=> LByteString -> m ETag
|
||||||
parseCompleteMultipartUploadResponse xmldata = do
|
parseCompleteMultipartUploadResponse xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
return $ T.concat $ r $// s3Elem "ETag" &/ content
|
return $ T.concat $ r $// s3Elem "ETag" &/ content
|
||||||
|
|
||||||
-- | Parse the response XML of a list objects call.
|
-- | Parse the response XML of a list objects call.
|
||||||
parseListObjectsResponse :: (MonadError MinioErr m)
|
parseListObjectsResponse :: (MonadThrow m)
|
||||||
=> LByteString -> m ListObjectsResult
|
=> LByteString -> m ListObjectsResult
|
||||||
parseListObjectsResponse xmldata = do
|
parseListObjectsResponse xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
@ -106,7 +107,7 @@ parseListObjectsResponse xmldata = do
|
|||||||
return $ ListObjectsResult hasMore nextToken objects prefixes
|
return $ ListObjectsResult hasMore nextToken objects prefixes
|
||||||
|
|
||||||
-- | Parse the response XML of a list incomplete multipart upload call.
|
-- | Parse the response XML of a list incomplete multipart upload call.
|
||||||
parseListUploadsResponse :: (MonadError MinioErr m)
|
parseListUploadsResponse :: (MonadThrow m)
|
||||||
=> LByteString -> m ListUploadsResult
|
=> LByteString -> m ListUploadsResult
|
||||||
parseListUploadsResponse xmldata = do
|
parseListUploadsResponse xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
@ -126,7 +127,7 @@ parseListUploadsResponse xmldata = do
|
|||||||
|
|
||||||
return $ ListUploadsResult hasMore nextKey nextUpload uploads prefixes
|
return $ ListUploadsResult hasMore nextKey nextUpload uploads prefixes
|
||||||
|
|
||||||
parseListPartsResponse :: (MonadError MinioErr m)
|
parseListPartsResponse :: (MonadThrow m)
|
||||||
=> LByteString -> m ListPartsResult
|
=> LByteString -> m ListPartsResult
|
||||||
parseListPartsResponse xmldata = do
|
parseListPartsResponse xmldata = do
|
||||||
r <- parseRoot xmldata
|
r <- parseRoot xmldata
|
||||||
|
|||||||
@ -3,14 +3,15 @@ module Network.Minio.XmlParser.Test
|
|||||||
xmlParserTests
|
xmlParserTests
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Test.Tasty
|
import qualified Control.Monad.Catch as MC
|
||||||
import Test.Tasty.HUnit
|
import Data.Time (fromGregorian, UTCTime(..))
|
||||||
import Data.Time (fromGregorian, UTCTime(..))
|
import Test.Tasty
|
||||||
|
import Test.Tasty.HUnit
|
||||||
|
|
||||||
import Lib.Prelude
|
import Lib.Prelude
|
||||||
|
|
||||||
import Network.Minio.Data
|
import Network.Minio.Data
|
||||||
import Network.Minio.XmlParser
|
import Network.Minio.XmlParser
|
||||||
|
|
||||||
xmlParserTests :: TestTree
|
xmlParserTests :: TestTree
|
||||||
xmlParserTests = testGroup "XML Parser Tests"
|
xmlParserTests = testGroup "XML Parser Tests"
|
||||||
@ -22,19 +23,26 @@ xmlParserTests = testGroup "XML Parser Tests"
|
|||||||
, testCase "Test parseListPartsResponse" testParseListPartsResponse
|
, testCase "Test parseListPartsResponse" testParseListPartsResponse
|
||||||
]
|
]
|
||||||
|
|
||||||
|
tryMError :: (MC.MonadCatch m) => m a -> m (Either MError a)
|
||||||
|
tryMError act = MC.try act
|
||||||
|
|
||||||
|
assertMError :: MError -> Assertion
|
||||||
|
assertMError e = assertFailure $ "Failed due to exception => " ++ show e
|
||||||
|
|
||||||
|
eitherMError :: Either MError a -> (a -> Assertion) -> Assertion
|
||||||
|
eitherMError (Left e) _ = assertMError e
|
||||||
|
eitherMError (Right a) f = f a
|
||||||
|
|
||||||
testParseLocation :: Assertion
|
testParseLocation :: Assertion
|
||||||
testParseLocation = do
|
testParseLocation = do
|
||||||
-- 1. Test parsing of an invalid location constraint xml.
|
-- 1. Test parsing of an invalid location constraint xml.
|
||||||
parsedLocationE <- runExceptT $ parseLocation "ClearlyInvalidXml"
|
parseResE <- tryMError $ parseLocation "ClearlyInvalidXml"
|
||||||
case parsedLocationE of
|
when (isRight parseResE) $
|
||||||
Right _ -> assertFailure $ "Parsing should have failed => " ++ show parsedLocationE
|
assertFailure $ "Parsing should have failed => " ++ show parseResE
|
||||||
Left _ -> return ()
|
|
||||||
|
|
||||||
forM_ cases $ \(xmldata, expectedLocation) -> do
|
forM_ cases $ \(xmldata, expectedLocation) -> do
|
||||||
parsedLocationE1 <- runExceptT $ parseLocation xmldata
|
parseLocE <- tryMError $ parseLocation xmldata
|
||||||
case parsedLocationE1 of
|
either assertMError (@?= expectedLocation) parseLocE
|
||||||
Right parsedLocation -> parsedLocation @?= expectedLocation
|
|
||||||
_ -> assertFailure $ "Parsing failed => " ++ show parsedLocationE1
|
|
||||||
where
|
where
|
||||||
cases = [
|
cases = [
|
||||||
-- 2. Test parsing of a valid location xml.
|
-- 2. Test parsing of a valid location xml.
|
||||||
@ -53,10 +61,8 @@ testParseLocation = do
|
|||||||
testParseNewMultipartUpload :: Assertion
|
testParseNewMultipartUpload :: Assertion
|
||||||
testParseNewMultipartUpload = do
|
testParseNewMultipartUpload = do
|
||||||
forM_ cases $ \(xmldata, expectedUploadId) -> do
|
forM_ cases $ \(xmldata, expectedUploadId) -> do
|
||||||
parsedUploadIdE <- runExceptT $ parseNewMultipartUpload xmldata
|
parsedUploadIdE <- tryMError $ parseNewMultipartUpload xmldata
|
||||||
case parsedUploadIdE of
|
eitherMError parsedUploadIdE (@?= expectedUploadId)
|
||||||
Right upId -> upId @?= expectedUploadId
|
|
||||||
_ -> assertFailure $ "Parsing failed => " ++ show parsedUploadIdE
|
|
||||||
where
|
where
|
||||||
cases = [
|
cases = [
|
||||||
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
|
("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\
|
||||||
@ -100,10 +106,8 @@ testParseListObjectsResult = do
|
|||||||
object1 = ObjectInfo "my-image.jpg" modifiedTime1 "\"fba9dede5f27731c9771645a39863328\"" 434234
|
object1 = ObjectInfo "my-image.jpg" modifiedTime1 "\"fba9dede5f27731c9771645a39863328\"" 434234
|
||||||
modifiedTime1 = flip UTCTime 64230 $ fromGregorian 2009 10 12
|
modifiedTime1 = flip UTCTime 64230 $ fromGregorian 2009 10 12
|
||||||
|
|
||||||
parsedListObjectsResult <- runExceptT $ parseListObjectsResponse xmldata
|
parsedListObjectsResult <- tryMError $ parseListObjectsResponse xmldata
|
||||||
case parsedListObjectsResult of
|
eitherMError parsedListObjectsResult (@?= expectedListResult)
|
||||||
Right listObjectsResult -> listObjectsResult @?= expectedListResult
|
|
||||||
_ -> assertFailure $ "Parsing failed => " ++ show parsedListObjectsResult
|
|
||||||
|
|
||||||
testParseListIncompleteUploads :: Assertion
|
testParseListIncompleteUploads :: Assertion
|
||||||
testParseListIncompleteUploads = do
|
testParseListIncompleteUploads = do
|
||||||
@ -144,10 +148,8 @@ testParseListIncompleteUploads = do
|
|||||||
initTime = UTCTime (fromGregorian 2010 11 26) 69857
|
initTime = UTCTime (fromGregorian 2010 11 26) 69857
|
||||||
prefixes = ["photos/", "videos/"]
|
prefixes = ["photos/", "videos/"]
|
||||||
|
|
||||||
parsedListUploadsResult <- runExceptT $ parseListUploadsResponse xmldata
|
parsedListUploadsResult <- tryMError $ parseListUploadsResponse xmldata
|
||||||
case parsedListUploadsResult of
|
eitherMError parsedListUploadsResult (@?= expectedListResult)
|
||||||
Right listUploadsResult -> listUploadsResult @?= expectedListResult
|
|
||||||
_ -> assertFailure $ "Parsing failed => " ++ show parsedListUploadsResult
|
|
||||||
|
|
||||||
|
|
||||||
testParseCompleteMultipartUploadResponse :: Assertion
|
testParseCompleteMultipartUploadResponse :: Assertion
|
||||||
@ -163,9 +165,7 @@ testParseCompleteMultipartUploadResponse = do
|
|||||||
expectedETag = "\"3858f62230ac3c915f300c664312c11f-9\""
|
expectedETag = "\"3858f62230ac3c915f300c664312c11f-9\""
|
||||||
|
|
||||||
parsedETagE <- runExceptT $ parseCompleteMultipartUploadResponse xmldata
|
parsedETagE <- runExceptT $ parseCompleteMultipartUploadResponse xmldata
|
||||||
case parsedETagE of
|
eitherMError parsedETagE (@?= expectedETag)
|
||||||
Right actualETag -> actualETag @?= expectedETag
|
|
||||||
_ -> assertFailure $ "Parsing failed => " ++ show parsedETagE
|
|
||||||
|
|
||||||
testParseListPartsResponse :: Assertion
|
testParseListPartsResponse :: Assertion
|
||||||
testParseListPartsResponse = do
|
testParseListPartsResponse = do
|
||||||
@ -209,6 +209,4 @@ testParseListPartsResponse = do
|
|||||||
modifiedTime2 = flip UTCTime 74913 $ fromGregorian 2010 11 10
|
modifiedTime2 = flip UTCTime 74913 $ fromGregorian 2010 11 10
|
||||||
|
|
||||||
parsedListPartsResult <- runExceptT $ parseListPartsResponse xmldata
|
parsedListPartsResult <- runExceptT $ parseListPartsResponse xmldata
|
||||||
case parsedListPartsResult of
|
eitherMError parsedListPartsResult (@?= expectedListResult)
|
||||||
Right listPartsResult -> listPartsResult @?= expectedListResult
|
|
||||||
_ -> assertFailure $ "Parsing failed => " ++ show parsedListPartsResult
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user