{-# LANGUAGE OverloadedStrings #-} module Network.WebexTeamsSpec where import Control.Concurrent.Async (withAsync) import Control.Concurrent.MVar (MVar, newEmptyMVar, putMVar, takeMVar) import Control.Monad (void) import Data.Aeson (decode, encode) import Data.Attoparsec.ByteString (parseOnly) import qualified Data.ByteString as S (ByteString) import qualified Data.ByteString.Char8 as C8 (pack, unpack) import qualified Data.ByteString.Lazy as L (ByteString) import Data.Default (def) import Data.List (sort) import Data.Maybe (fromJust) import Data.Monoid ((<>)) import Data.Text (pack) import Network.HTTP.Simple as C (addRequestHeader, defaultRequest, getResponseBody, httpJSON, parseRequest, setRequestHost, setRequestMethod, setRequestPath, setRequestPort, setRequestSecure) import Network.HTTP.Types (Header, status200) import Network.URI (URIAuth (..)) import Network.Wai (Application, queryString, rawPathInfo, requestHeaders, requestMethod, responseLBS, strictRequestBody) import Network.Wai.Handler.Warp (defaultSettings, runSettings, setBeforeMainLoop, setPort) import Test.Hspec import Network.WebexTeams import Network.WebexTeams.Internal (LinkHeader (..), LinkParam (..), getNextUrl, linkHeader) import Data.Typeable (typeOf) listenPort = 3000 listenPortBS = (C8.pack . show) listenPort mockBaseRequestRequest = C.addRequestHeader "Content-Type" "application/json; charset=utf-8" $ C.setRequestPort listenPort $ C.setRequestHost "127.0.0.1" $ C.setRequestSecure False $ C.defaultRequest mockBaseRequest :: WebexTeamsRequest mockBaseRequest = WebexTeamsRequest mockBaseRequestRequest "http:" $ URIAuth "" "127.0.0.1" (":" <> show listenPort) dummyAuth :: Authorization dummyAuth = Authorization "dummyAuth" extractRight :: Show err => Either err r -> r extractRight (Right r) = r extractRight (Left err) = error $ show err withMockServer :: Application -> IO () -> IO () withMockServer app inner = do readyToConnect <- newEmptyMVar let set = setBeforeMainLoop (putMVar readyToConnect ()) $ setPort listenPort defaultSettings withAsync (runSettings set app) (\_ -> takeMVar readyToConnect >> inner) helloApp :: Application helloApp _ respond = respond $ responseLBS status200 [] "hello, world" contentType :: Header contentType = ("Content-Type", "application/json; charset=utf-8") simpleApp :: L.ByteString -> Application simpleApp res _ respond = respond $ responseLBS status200 [contentType] res paginationApp :: [L.ByteString] -> Application paginationApp ress req respond = do let (cTypes, body) = dispatch $ rawPathInfo req respond $ responseLBS status200 cTypes body where dispatch "/1" = ([contentType, ("Link", " listenPortBS <> "/2>; rel=\"next\"")], ress !! 1) dispatch "/2" = ([contentType, ("Link", " listenPortBS <> "/3>; rel=\"next\"")], ress !! 2) dispatch "/3" = ([contentType], ress !! 3) dispatch _ = ([contentType, ("Link", " listenPortBS <> "/1>; rel=\"next\"")], ress !! 0) invalidPaginationApp :: [L.ByteString] -> Application invalidPaginationApp ress req respond = do let (cTypes, body) = dispatch $ rawPathInfo req respond $ responseLBS status200 cTypes body where dispatch "/1" = ([contentType, ("Link", "; rel=\"next\"")], ress !! 1) dispatch "/2" = ([contentType, ("Link", " listenPortBS <> "/3>; rel=\"next\"")], ress !! 2) dispatch "/3" = ([contentType], ress !! 3) dispatch _ = ([contentType, ("Link", " listenPortBS <> "/1>; rel=\"next\"")], ress !! 0) teamGen :: String -> Team teamGen i = Team { teamId = TeamId . pack $ "teamId" <> i , teamErrors = Nothing , teamName = Just . TeamName . pack $ "teamName" <> i , teamCreatorId = Just . PersonId . pack $ "teamCreatorId" <> i , teamCreated = Just . Timestamp . pack $ "teamCreated" <> i } teamList :: String -> [Team] teamList j = [ teamGen $ j <> show i | i <- [1..3] ] teamListList :: [[Team]] teamListList = [ teamList [c] | c <- ['a'..'d'] ] readAllList :: ListReader i -> IO [i] readAllList reader = go [] where go xs = reader >>= \chunk -> case chunk of [] -> pure xs ys -> go (xs <> ys) spec :: Spec spec = do describe "Mock Applications" $ do it "simple mock app returns list of team" $ do receivedReqMVar <- newEmptyMVar let (WebexTeamsRequest baseReq _ _) = mockBaseRequest req = setRequestPath "/v1/teams" $ setRequestMethod "GET" $ baseReq testData = TeamList $ teamList ['Z'] withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode testData) req respond ) $ do res <- getResponseBody <$> httpJSON req res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/teams" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "pagenation mock app returns list of team and Link header" $ do receivedReqMVar <- newEmptyMVar let (WebexTeamsRequest baseReq _ _) = mockBaseRequest req = setRequestPath "/v1/teams" $ setRequestMethod "GET" $ baseReq testData = encode . TeamList <$> teamListList withMockServer (\req respond -> do putMVar receivedReqMVar req paginationApp testData req respond ) $ do res1 <- httpJSON req getResponseBody res1 `shouldBe` TeamList (teamListList !! 0) receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/teams" let path = getNextUrl res1 path `shouldBe` (Just $ "http://127.0.0.1:" <> listenPortBS <> "/1") req2 <- parseRequest $ "GET " <> C8.unpack (fromJust path) res2 <- httpJSON req2 getResponseBody res2 `shouldBe` TeamList (teamListList !! 1) describe "People" $ do let personJson1 = "{\ \ \"id\" : \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY\",\ \ \"emails\" : [ \"johnny.chang@foomail.com\", \"jchang@barmail.com\" ],\ \ \"displayName\" : \"John Andersen\",\ \ \"firstName\" : \"John\",\ \ \"lastName\" : \"Andersen\",\ \ \"avatar\" : \"https://1efa7a94ed21783e352-c62266528714497a17239ececf39e9e2.ssl.cf1.rackcdn.com/V1~54c844c89e678e5a7b16a306bc2897b9~wx29yGtlTpilEFlYzqPKag==~1600\",\ \ \"orgId\" : \"Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE\",\ \ \"roles\" : [ \"Y2lzY29zcGFyazovL3VzL1JPT00vOGNkYzQwYzQtZjA5ZS0zY2JhLThjMjYtZGQwZTcwYWRlY2Iy\", \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX\" ],\ \ \"licenses\" : [ \"Y2lzY29zcGFyazovL3VzL1JPT00vOGNkYzQwYzQtZjA5ZS0zY2JhLThjMjYtZGQwZTcwYWRlY2Iy\", \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX\" ],\ \ \"created\" : \"2015-10-18T14:26:16.000Z\",\ \ \"timezone\" : \"America/Denver\",\ \ \"lastActivity\" : \"2015-10-18T14:26:16.028Z\",\ \ \"status\" : \"active\",\ \ \"invitePending\" : false,\ \ \"loginEnabled\" : true\ \}" person1 = Person { personId = PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , personErrors = Nothing , personEmails = Just [Email "johnny.chang@foomail.com", Email "jchang@barmail.com"] , personDisplayName = Just $ DisplayName "John Andersen" , personNickName = Nothing , personFirstName = Just $ FirstName "John" , personLastName = Just $ LastName "Andersen" , personAvatar = Just $ AvatarUrl "https://1efa7a94ed21783e352-c62266528714497a17239ececf39e9e2.ssl.cf1.rackcdn.com/V1~54c844c89e678e5a7b16a306bc2897b9~wx29yGtlTpilEFlYzqPKag==~1600" , personOrgId = Just $ OrganizationId "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE" , personRoles = Just [ RoleId "Y2lzY29zcGFyazovL3VzL1JPT00vOGNkYzQwYzQtZjA5ZS0zY2JhLThjMjYtZGQwZTcwYWRlY2Iy" , RoleId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX"] , personLicenses = Just [ LicenseId "Y2lzY29zcGFyazovL3VzL1JPT00vOGNkYzQwYzQtZjA5ZS0zY2JhLThjMjYtZGQwZTcwYWRlY2Iy" , LicenseId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX"] , personCreated = Just $ Timestamp "2015-10-18T14:26:16.000Z" , personTimezone = Just $ Timezone "America/Denver" , personLastActivity = Just $ Timestamp "2015-10-18T14:26:16.028Z" , personStatus = Just PersonStatusActive , personInvitePending = Just False , personLoginEnabled = Just True , personType = Nothing } personGen i = Person { personId = PersonId . pack $ "PersonId" <> i , personErrors = Nothing , personEmails = Just [Email . pack $ "email" <> i <> "@foomail.com", Email . pack $ "email" <> i <> "@barmail.com"] , personDisplayName = Just . DisplayName . pack $ "John Andersen" <> i , personNickName = Nothing , personFirstName = Just $ FirstName . pack $ "John" <> i , personLastName = Just $ LastName . pack $ "Andersen" <> i , personAvatar = Just $ AvatarUrl . pack $ "https://AvatarUrl" <> i , personOrgId = Just . OrganizationId . pack $ "OrganizationId" <> i , personRoles = Just [ RoleId . pack $ "RoleIdA" <> i , RoleId . pack $ "RoleIdB" <> i] , personLicenses = Just [ LicenseId . pack $ "LicenseIdX" <> i , LicenseId . pack $ "LicenseIdY" <> i] , personCreated = Just . Timestamp . pack $ "Created" <> i , personTimezone = Just $ Timezone . pack $ "Timezone" <> i , personLastActivity = Just $ Timestamp . pack $ "LastActivity" <> i , personStatus = Just PersonStatusActive , personInvitePending = Just False , personLoginEnabled = Just True , personType = Nothing } personList j = [ personGen $ j <> show i | i <- [1..3] ] personListList = [ personList [c] | c <- ['a'..'d'] ] newPerson = CreatePerson { createPersonEmails = Just $ [Email "johnny.chang@foomail.com", Email "jchang@barmail.com"] , createPersonDisplayName = Just $ DisplayName "John Andersen" , createPersonFirstName = Just $ FirstName "John" , createPersonLastName = Just $ LastName "Andersen" , createPersonAvatar = Just $ AvatarUrl "https://1efa7a94ed21783e352-c62266528714497a17239ececf39e9e2.ssl.cf1.rackcdn.com/V1~54c844c89e678e5a7b16a306bc2897b9~wx29yGtlTpilEFlYzqPKag==~1600" , createPersonOrgId = Just $ OrganizationId "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE" , createPersonRoles = Just [ RoleId "Y2lzY29zcGFyazovL3VzL1JPT00vOGNkYzQwYzQtZjA5ZS0zY2JhLThjMjYtZGQwZTcwYWRlY2Iy" , RoleId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX"] , createPersonLicenses = Just [ LicenseId "Y2lzY29zcGFyazovL3VzL1JPT00vOGNkYzQwYzQtZjA5ZS0zY2JhLThjMjYtZGQwZTcwYWRlY2Iy" , LicenseId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX"] } updatePerson = UpdatePerson { updatePersonDisplayName = Just $ DisplayName "New John Andersen" , updatePersonFirstName = Just $ FirstName "New John" , updatePersonLastName = Just $ LastName "New Andersen" , updatePersonAvatar = Just $ AvatarUrl "https://example.com/newAvatarUrl" , updatePersonOrgId = Just $ OrganizationId "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE" , updatePersonRoles = Just $ [ RoleId "newRoleId1", RoleId "newRoleId2" ] , updatePersonLicenses = Just $ [ LicenseId "newLicenseId1", LicenseId "newLicenseId2" ] } it "getPersonList returns ListReader of Person" $ do let testData = personList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (PersonList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/people" queryString receivedReq `shouldBe` [] it "getPersonList passes query strings build from PersonFilter to server" $ do let testData = personList ['Z'] personFilter = PersonFilter (Just $ Email "person@filter.com") (Just $ DisplayName "DisplayNameFilter") (Just $ OrganizationId "OrgIdFilter") receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (PersonList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest personFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/people" (sort . queryString) receivedReq `shouldBe` sort [ ("orgId", Just "OrgIdFilter") , ("displayName", Just "DisplayNameFilter") , ("email", Just "person@filter.com") ] it "getPersonList returns ListReader of Person performing automatic pagination" $ do withMockServer (paginationApp $ encode . PersonList <$> personListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) >>= readAllList res `shouldBe` concat personListList it "getPersonList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . PersonList <$> personListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) >>= readAllList res `shouldBe` concat (take 2 personListList) it "getDetail for a person returns a Person" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp personJson1 req respond ) $ do resPerson <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (PersonId "testPersonId") resPerson `shouldBe` person1 receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/people/testPersonId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a person returns a (Right Person)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp personJson1 req respond ) $ do (Right resPerson) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (PersonId "testPersonId") resPerson `shouldBe` person1 it "createEntity for a person sends JSON encoded CreatePerson as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp personJson1 req respond ) $ do resPerson <- getResponseBody <$> createEntity dummyAuth mockBaseRequest newPerson resPerson `shouldBe` person1 receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/people" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newPerson it "createEntityEither for a person sends JSON encoded CreatePerson as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp personJson1 req respond ) $ do (Right resPerson) <- getResponseBody <$> createEntityEither dummyAuth mockBaseRequest newPerson resPerson `shouldBe` person1 receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/people" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newPerson it "updateEntity for a person sends JSON encoded UpdatePerson as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp personJson1 req respond ) $ do resPerson <- getResponseBody <$> updateEntity dummyAuth mockBaseRequest updatePerson resPerson `shouldBe` person1 receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/people" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updatePerson it "updateEntityEither for a person sends JSON encoded UpdatePerson as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp personJson1 req respond ) $ do (Right resPerson) <- getResponseBody <$> updateEntityEither dummyAuth mockBaseRequest updatePerson resPerson `shouldBe` person1 receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/people" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updatePerson describe "Team" $ do let teamJson = "{\ \ \"id\" : \"Y2lzY29zcGFyazovL3VzL1RFQU0vMTNlMThmNDAtNDJmYy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5\",\ \ \"name\" : \"Build Squad\",\ \ \"creatorId\" : \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY\",\ \ \"created\" : \"2015-10-18T14:26:16+00:00\"\ \}" team = Team { teamId = TeamId "Y2lzY29zcGFyazovL3VzL1RFQU0vMTNlMThmNDAtNDJmYy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5" , teamErrors = Nothing , teamName = Just $ TeamName "Build Squad" , teamCreatorId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , teamCreated = Just $ Timestamp "2015-10-18T14:26:16+00:00" } newTeam = CreateTeam $ TeamName "Build Squad" updateTeam = UpdateTeam $ TeamName "updatedTeamName" it "getTeamList returns ListReader of Team" $ do let testData = teamList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (TeamList testData)) req respond ) $ do res <- getTeamList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/teams" queryString receivedReq `shouldBe` [] it "getTeamList returns ListReader of Team performing automatic pagination" $ do withMockServer (paginationApp $ encode . TeamList <$> teamListList) $ do res <- getTeamList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` concat teamListList it "getTeamList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . TeamList <$> teamListList) $ do res <- getTeamList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` concat (take 2 teamListList) it "getDetail for a team returns a Team" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp teamJson req respond ) $ do resTeam <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (TeamId "testTeamId") resTeam `shouldBe` team receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/teams/testTeamId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a team returns a (Right Team)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp teamJson req respond ) $ do (Right resTeam) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (TeamId "testTeamId") resTeam `shouldBe` team it "createEntity for a team sends JSON encoded CreateTeam as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamJson req respond ) $ do resTeam <- getResponseBody <$> createEntity dummyAuth mockBaseRequest newTeam resTeam `shouldBe` team receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/teams" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newTeam it "createEntityEither for a team sends JSON encoded CreateTeam as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamJson req respond ) $ do (Right resTeam) <- getResponseBody <$> createEntityEither dummyAuth mockBaseRequest newTeam resTeam `shouldBe` team receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/teams" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newTeam it "updateEntity for a team sends JSON encoded UpdateTeam as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamJson req respond ) $ do resTeam <- getResponseBody <$> updateEntity dummyAuth mockBaseRequest updateTeam resTeam `shouldBe` team receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/teams" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateTeam it "updateEntityEither for a team sends JSON encoded UpdateTeam as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamJson req respond ) $ do (Right resTeam) <- getResponseBody <$> updateEntityEither dummyAuth mockBaseRequest updateTeam resTeam `shouldBe` team receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/teams" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateTeam it "deleteTeam sends DELETE request with teamId on URL path" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp "" req respond ) $ do deleteTeam dummyAuth mockBaseRequest (TeamId "testTeamId") receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "DELETE" rawPathInfo receivedReq `shouldBe` "/v1/teams/testTeamId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" describe "TeamMemberShip" $ do let teamMembershipJson = "{\ \ \"id\" : \"Y2lzY29zcGFyazovL3VzL1RFQU1fTUVNQkVSU0hJUC8wZmNmYTJiOC1hZGNjLTQ1ZWEtYTc4Mi1lNDYwNTkyZjgxZWY6MTNlMThmNDAtNDJmYy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5\",\ \ \"teamId\" : \"Y2lzY29zcGFyazovL3VzL1RFQU0vMTNlMThmNDAtNDJmYy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5\",\ \ \"personId\" : \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY\",\ \ \"personEmail\" : \"john.andersen@example.com\",\ \ \"personDisplayName\" : \"John Andersen\",\ \ \"personOrgId\" : \"Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE\",\ \ \"isModerator\" : true,\ \ \"created\" : \"2015-10-18T14:26:16.057Z\"\ \}" teamMembership = TeamMembership { teamMembershipId = TeamMembershipId "Y2lzY29zcGFyazovL3VzL1RFQU1fTUVNQkVSU0hJUC8wZmNmYTJiOC1hZGNjLTQ1ZWEtYTc4Mi1lNDYwNTkyZjgxZWY6MTNlMThmNDAtNDJmYy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5" , teamMembershipErrors = Nothing , teamMembershipTeamId = Just $ TeamId "Y2lzY29zcGFyazovL3VzL1RFQU0vMTNlMThmNDAtNDJmYy0xMWU2LWE5ZDgtMjExYTBkYzc5NzY5" , teamMembershipPersonId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , teamMembershipPersonEmail = Just $ Email "john.andersen@example.com" , teamMembershipPersonDisplayName = Just $ DisplayName "John Andersen" , teamMembershipPersonOrgId = Just $ OrganizationId "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE" , teamMembershipIsModerator = Just True , teamMembershipCreated = Just $ Timestamp "2015-10-18T14:26:16.057Z" } teamMembershipGen i = TeamMembership { teamMembershipId = TeamMembershipId . pack $ "teamMembershipId" <> i , teamMembershipErrors = Nothing , teamMembershipTeamId = Just . TeamId . pack $ "teamId" <> i , teamMembershipPersonId = Just . PersonId . pack $ "personId" <> i , teamMembershipPersonEmail = Just . Email . pack $ "email" <> i <> "@example.com" , teamMembershipPersonDisplayName = Just . DisplayName . pack $ "DisplayName" <> i , teamMembershipPersonOrgId = Just . OrganizationId . pack $ "OrganizationId" <> i , teamMembershipIsModerator = Just True , teamMembershipCreated = Just . Timestamp . pack $ "Timestamp" <> i } teamMembershipList j = [ teamMembershipGen $ j <> show i | i <- [1..3] ] teamMembershipListList = [ teamMembershipList [c] | c <- ['a'..'d'] ] defFilter = defaultTeamMembershipFilter $ TeamId "dummyTeamId" newTeamMembership = CreateTeamMembership { createTeamMembershipTeamId = TeamId "targetTeam" , createTeamMembershipPersonId = Just $ PersonId "addedPerson" , createTeamMembershipPersonEmail = Just $ Email "added@example.com" , createTeamMembershipIsModerator = Just True } updateTeamMembership = UpdateTeamMembership False it "getTeamMembershipList returns ListReader of TeamMembership" $ do let testData = teamMembershipList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (TeamMembershipList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest defFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/team/memberships" queryString receivedReq `shouldBe` [ ("teamId", Just "dummyTeamId") ] it "getTeamMembershipList passes query strings build from TeamMembershipFilter to server" $ do let testData = teamMembershipList ['Z'] teamMembershipFilter = TeamMembershipFilter $ TeamId "DummyTeamId" receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (TeamMembershipList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest teamMembershipFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/team/memberships" queryString receivedReq `shouldBe` [ ("teamId", Just "DummyTeamId") ] it "getTeamMembershipList returns ListReader of TeamMembership performing automatic pagination" $ do withMockServer (paginationApp $ encode . TeamMembershipList <$> teamMembershipListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest defFilter >>= readAllList res `shouldBe` concat teamMembershipListList it "getTeamMembershipList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . TeamMembershipList <$> teamMembershipListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest defFilter >>= readAllList res `shouldBe` concat (take 2 teamMembershipListList) it "getDetail for a team membership returns a TeamMembership" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp teamMembershipJson req respond ) $ do resTeamMembership <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (TeamMembershipId "testTeamMembershipId") resTeamMembership `shouldBe` teamMembership receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/team/memberships/testTeamMembershipId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a team membership returns a (Right TeamMembership)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp teamMembershipJson req respond ) $ do (Right resTeamMembership) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (TeamMembershipId "testTeamMembershipId") resTeamMembership `shouldBe` teamMembership it "createEntity for a team membership sends JSON encoded CreateTeamMembership as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamMembershipJson req respond ) $ do resTeamMembership <- getResponseBody <$> createEntity dummyAuth mockBaseRequest newTeamMembership resTeamMembership `shouldBe` teamMembership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/team/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newTeamMembership it "createEntityEither for a team membership sends JSON encoded CreateTeamMembership as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamMembershipJson req respond ) $ do (Right resTeamMembership) <- getResponseBody <$> createEntityEither dummyAuth mockBaseRequest newTeamMembership resTeamMembership `shouldBe` teamMembership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/team/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newTeamMembership it "updateEntity for a teamMembership sends JSON encoded UpdateTeamMembership as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamMembershipJson req respond ) $ do resTeamMembership <- getResponseBody <$> updateEntity dummyAuth mockBaseRequest updateTeamMembership resTeamMembership `shouldBe` teamMembership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/team/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateTeamMembership it "updateEntityEither for a teamMembership sends JSON encoded UpdateTeamMembership as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp teamMembershipJson req respond ) $ do (Right resTeamMembership) <- getResponseBody <$> updateEntityEither dummyAuth mockBaseRequest updateTeamMembership resTeamMembership `shouldBe` teamMembership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/team/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateTeamMembership it "deleteTeamMembership sends DELETE request with teamMembershipId on URL path" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp "" req respond ) $ do deleteTeamMembership dummyAuth mockBaseRequest (TeamMembershipId "testTeamMembershipId") receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "DELETE" rawPathInfo receivedReq `shouldBe` "/v1/team/memberships/testTeamMembershipId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" describe "Room" $ do let roomJson = "{\ \ \"id\" : \"Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0\",\ \ \"title\" : \"Project Unicorn - Sprint 0\",\ \ \"type\" : \"group\",\ \ \"isLocked\" : true,\ \ \"sipAddress\" : \"01234567890@meet.ciscospark.com\",\ \ \"teamId\" : \"Y2lzY29zcGFyazovL3VzL1JPT00vNjRlNDVhZTAtYzQ2Yi0xMWU1LTlkZjktMGQ0MWUzNDIxOTcz\",\ \ \"lastActivity\" : \"2016-04-21T19:12:48.920Z\",\ \ \"creatorId\": \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY\",\ \ \"created\" : \"2016-04-21T19:01:55.966Z\"\ \}" room = Room { roomId = RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0" , roomErrors = Nothing , roomTitle = Just $ RoomTitle "Project Unicorn - Sprint 0" , roomType = Just RoomTypeGroup , roomIsLocked = Just True , roomSipAddress = Just $ SipAddr "01234567890@meet.ciscospark.com" , roomLastActivity = Just $ Timestamp "2016-04-21T19:12:48.920Z" , roomTeamId = Just $ TeamId "Y2lzY29zcGFyazovL3VzL1JPT00vNjRlNDVhZTAtYzQ2Yi0xMWU1LTlkZjktMGQ0MWUzNDIxOTcz" , roomCreatorId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , roomCreated = Just $ Timestamp "2016-04-21T19:01:55.966Z" } roomGen i = Room { roomId = RoomId . pack $ "roomId" <> i , roomErrors = Nothing , roomTitle = Just . RoomTitle . pack $ "roomTitle" <> i , roomType = Just RoomTypeGroup , roomIsLocked = Just True , roomSipAddress = Just $ SipAddr . pack $ "rooomSipAddress" <> i <> "@meet.ciscospark.com" , roomLastActivity = Just . Timestamp . pack $ "roomLastActivity" <> i , roomTeamId = Just $ TeamId . pack $ "roomTeamId" <> i , roomCreatorId = Just . PersonId . pack $ "personId" <> i , roomCreated = Just .Timestamp .pack $ "roomCreated" <> i } roomList j = [ roomGen $ j <> show i | i <- [1..3] ] roomListList = [ roomList [c] | c <- ['a'..'d'] ] newRoom = CreateRoom (RoomTitle "New Room") (Just $ TeamId "belongingTeam") updateRoom = UpdateRoom $ RoomTitle "updatedRoomTitle" it "getRoomList returns ListReader of Room" $ do let testData = roomList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (RoomList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/rooms" queryString receivedReq `shouldBe` [] it "getRoomList passes query strings build from RoomFilter to server" $ do let testData = roomList ['Z'] roomFilter = RoomFilter (Just $ TeamId "dummyTeamId") (Just RoomTypeGroup) (Just RoomFilterSortByLastActivity) receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (RoomList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest roomFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/rooms" (sort . queryString) receivedReq `shouldBe` sort [ ("type", Just "group") , ("sortBy", Just "lastactivity") , ("teamId", Just "dummyTeamId") ] it "getRoomList returns ListReader of Room performing automatic pagination" $ do withMockServer (paginationApp $ encode . RoomList <$> roomListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) >>= readAllList res `shouldBe` concat roomListList it "getRoomList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . RoomList <$> roomListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) >>= readAllList res `shouldBe` concat (take 2 roomListList) it "getDetail for a room returns a Room" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp roomJson req respond ) $ do resRoom <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (RoomId "testRoomId") resRoom `shouldBe` room receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/rooms/testRoomId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a room returns a (Right Room)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp roomJson req respond ) $ do (Right resRoom) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (RoomId "testRoomId") resRoom `shouldBe` room it "createEntity for a room sends JSON encoded CreateRoom as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp roomJson req respond ) $ do resRoom <- getResponseBody <$> createEntity dummyAuth mockBaseRequest newRoom resRoom `shouldBe` room receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/rooms" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newRoom it "createEntithEither for a room sends JSON encoded CreateRoom as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp roomJson req respond ) $ do (Right resRoom) <- getResponseBody <$> createEntityEither dummyAuth mockBaseRequest newRoom resRoom `shouldBe` room receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/rooms" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newRoom it "updateEntity for a room sends JSON encoded UpdateRoom as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp roomJson req respond ) $ do resRoom <- getResponseBody <$> updateEntity dummyAuth mockBaseRequest updateRoom resRoom `shouldBe` room receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/rooms" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateRoom it "updateEntityEither for a room sends JSON encoded UpdateRoom as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp roomJson req respond ) $ do (Right resRoom) <- getResponseBody <$> updateEntityEither dummyAuth mockBaseRequest updateRoom resRoom `shouldBe` room receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/rooms" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateRoom it "deleteRoom sends DELETE request with roomId on URL path" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp "" req respond ) $ do deleteRoom dummyAuth mockBaseRequest (RoomId "testRoomId") receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "DELETE" rawPathInfo receivedReq `shouldBe` "/v1/rooms/testRoomId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" describe "Membership" $ do let membershipJson = "{\ \ \"id\" : \"Y2lzY29zcGFyazovL3VzL01FTUJFUlNISVAvMGQwYzkxYjYtY2U2MC00NzI1LWI2ZDAtMzQ1NWQ1ZDExZWYzOmNkZTFkZDQwLTJmMGQtMTFlNS1iYTljLTdiNjU1NmQyMjA3Yg\",\ \ \"roomId\" : \"Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0\",\ \ \"personId\" : \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY\",\ \ \"personEmail\" : \"john.andersen@example.com\",\ \ \"personDisplayName\" : \"John Andersen\",\ \ \"personOrgId\" : \"Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE\",\ \ \"isModerator\" : true,\ \ \"isMonitor\" : true,\ \ \"created\" : \"2015-10-18T14:26:16.203Z\"\ \}" membership = Membership { membershipId = MembershipId "Y2lzY29zcGFyazovL3VzL01FTUJFUlNISVAvMGQwYzkxYjYtY2U2MC00NzI1LWI2ZDAtMzQ1NWQ1ZDExZWYzOmNkZTFkZDQwLTJmMGQtMTFlNS1iYTljLTdiNjU1NmQyMjA3Yg" , membershipErrors = Nothing , membershipRoomId = Just $ RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0" , membershipPersonId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , membershipPersonEmail = Just $ Email "john.andersen@example.com" , membershipPersonDisplayName = Just $ DisplayName "John Andersen" , membershipPersonOrgId = Just $ OrganizationId "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi85NmFiYzJhYS0zZGNjLTExZTUtYTE1Mi1mZTM0ODE5Y2RjOWE" , membershipIsModerator = Just True , membershipIsMonitor = Just True , membershipCreated = Just $ Timestamp "2015-10-18T14:26:16.203Z" } membershipGen i = Membership { membershipId = MembershipId . pack $ "membershipId" <> i , membershipErrors = Nothing , membershipRoomId = Just . RoomId . pack $ "roomId" <> i , membershipPersonId = Just . PersonId . pack $ "personId" <> i , membershipPersonEmail = Just . Email . pack $ "email" <> i <> "@example.com" , membershipPersonDisplayName = Just . DisplayName . pack $ "displayName" <> i , membershipPersonOrgId = Just . OrganizationId . pack $ "orgId" <> i , membershipIsModerator = Just True , membershipIsMonitor = Just True , membershipCreated = Just . Timestamp . pack $ "timestamp" <> i } membershipList j = [ membershipGen $ j <> show i | i <- [1..3] ] membershipListList = [ membershipList [c] | c <- ['a'..'d'] ] newMembership = CreateMembership { createMembershipRoomId = RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0" , createMembershipPersonId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , createMembershipPersonEmail = Just $ Email "john.andersen@example.com" , createMembershipIsModerator = Just $ True } updateMembership = UpdateMembership False it "getMembershipList returns ListReader of Membership" $ do let testData = membershipList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (MembershipList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/memberships" queryString receivedReq `shouldBe` [] it "getMembershipList passes query strings build from MembershipFilter to server" $ do let testData = membershipList ['Z'] membershipFilter = MembershipFilter (Just $ RoomId "dummyRoomId") (Just $ PersonId "personIdFilter") (Just $ Email "personEmailFilter") receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (MembershipList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest membershipFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/memberships" (sort . queryString) receivedReq `shouldBe` sort [ ("personId", Just "personIdFilter") , ("personEmail", Just "personEmailFilter") , ("roomId", Just "dummyRoomId") ] it "getMembershipList returns ListReader of Membership performing automatic pagination" $ do withMockServer (paginationApp $ encode . MembershipList <$> membershipListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) >>= readAllList res `shouldBe` concat membershipListList it "getMembershipList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . MembershipList <$> membershipListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) >>= readAllList res `shouldBe` concat (take 2 membershipListList) it "getDetail for a menbership returns a Membership" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp membershipJson req respond ) $ do resMembership <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (MembershipId "testMembershipId") resMembership `shouldBe` membership receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/memberships/testMembershipId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a membership returns a (Right Membership)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp membershipJson req respond ) $ do (Right resMembership) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (MembershipId "testMembershipId") resMembership `shouldBe` membership it "createEntity for a membership sends JSON encoded CreateMembership as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp membershipJson req respond ) $ do resMembership <- getResponseBody <$> createEntity dummyAuth mockBaseRequest newMembership resMembership `shouldBe` membership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newMembership it "createEntithEither for a membership sends JSON encoded CreateMembership as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp membershipJson req respond ) $ do (Right resMembership) <- getResponseBody <$> createEntityEither dummyAuth mockBaseRequest newMembership resMembership `shouldBe` membership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newMembership it "updateEntity for a membership sends JSON encoded UpdateMembership as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp membershipJson req respond ) $ do resMembership <- getResponseBody <$> updateEntity dummyAuth mockBaseRequest updateMembership resMembership `shouldBe` membership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateMembership it "updateEntityEither for a membership sends JSON encoded UpdateMembership as its body of PUT request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp membershipJson req respond ) $ do (Right resMembership) <- getResponseBody <$> updateEntityEither dummyAuth mockBaseRequest updateMembership resMembership `shouldBe` membership receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "PUT" rawPathInfo receivedReq `shouldBe` "/v1/memberships" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just updateMembership it "deleteMembership sends DELETE request with membershipId on URL path" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp "" req respond ) $ do deleteMembership dummyAuth mockBaseRequest (MembershipId "testMembershipId") receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "DELETE" rawPathInfo receivedReq `shouldBe` "/v1/memberships/testMembershipId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" describe "Message" $ do let messageJson = "{\ \ \"id\" : \"Y2lzY29zcGFyazovL3VzL01FU1NBR0UvOTJkYjNiZTAtNDNiZC0xMWU2LThhZTktZGQ1YjNkZmM1NjVk\",\ \ \"roomId\" : \"Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0\",\ \ \"roomType\" : \"group\",\ \ \"toPersonId\" : \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX\",\ \ \"toPersonEmail\" : \"julie@example.com\",\ \ \"text\" : \"PROJECT UPDATE - A new project plan has been published on Box: http://box.com/s/lf5vj. The PM for this project is Mike C. and the Engineering Manager is Jane W.\",\ \ \"html\" : \"

HTML formatted message goes here

when the message was posted in markdown format.

\",\ \ \"files\" : [ \"http://www.example.com/images/media.png\" ],\ \ \"personId\" : \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY\",\ \ \"personEmail\" : \"matt@example.com\",\ \ \"created\" : \"2015-10-18T14:26:16+00:00\",\ \ \"mentionedPeople\" : [ \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS8yNDlmNzRkOS1kYjhhLTQzY2EtODk2Yi04NzllZDI0MGFjNTM\", \"Y2lzY29zcGFyazovL3VzL1BFT1BMRS83YWYyZjcyYy0xZDk1LTQxZjAtYTcxNi00MjlmZmNmYmM0ZDg\" ]\ \}" message = Message { messageId = MessageId "Y2lzY29zcGFyazovL3VzL01FU1NBR0UvOTJkYjNiZTAtNDNiZC0xMWU2LThhZTktZGQ1YjNkZmM1NjVk" , messageErrors = Nothing , messageRoomId = Just $ RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0" , messageRoomType = Just $ RoomTypeGroup , messageToPersonId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX" , messageToPersonEmail = Just $ Email "julie@example.com" , messageText = Just $ MessageText "PROJECT UPDATE - A new project plan has been published on Box: http://box.com/s/lf5vj. The PM for this project is Mike C. and the Engineering Manager is Jane W." , messageHtml = Just $ MessageHtml "

HTML formatted message goes here

when the message was posted in markdown format.

" , messageFiles = Just [ FileUrl "http://www.example.com/images/media.png" ] , messagePersonId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mNWIzNjE4Ny1jOGRkLTQ3MjctOGIyZi1mOWM0NDdmMjkwNDY" , messagePersonEmail = Just $ Email "matt@example.com" , messageCreated = Just $ Timestamp "2015-10-18T14:26:16+00:00" , messageMentionedPeople = Just [ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS8yNDlmNzRkOS1kYjhhLTQzY2EtODk2Yi04NzllZDI0MGFjNTM" , PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS83YWYyZjcyYy0xZDk1LTQxZjAtYTcxNi00MjlmZmNmYmM0ZDg" ] } messageGen i = Message { messageId = MessageId . pack $ "messageId" <> i , messageErrors = Nothing , messageRoomId = Just . RoomId . pack $ "roomId" <> i , messageRoomType = Just RoomTypeGroup , messageToPersonId = Just . PersonId . pack $ "toPersonId" <> i , messageToPersonEmail = Just . Email . pack $ "julie" <> i <> "@example.com" , messageText = Just . MessageText . pack $ "messageText" <> i , messageHtml = Just . MessageHtml . pack $ "messageHtml" <> i , messageFiles = Just [ FileUrl . pack $ "http://www.example.com/images/media" <> i <> ".png" ] , messagePersonId = Just . PersonId . pack $ "personId" <> i , messagePersonEmail = Just . Email . pack $ "matt" <> i <> "@example.com" , messageCreated = Just . Timestamp . pack $ "created" <> i , messageMentionedPeople = Just [ PersonId . pack $ "memtionedPeople1-" <> i , PersonId . pack $ "memtionedPeople2-" <> i ] } messageList j = [ messageGen $ j <> show i | i <- [1..3] ] messageListList = [ messageList [c] | c <- ['a'..'d'] ] defFilter = defaultMessageFilter $ RoomId "dummyRoomId" newMessage = CreateMessage { createMessageRoomId = Just $ RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0" , createMessageToPersonId = Just $ PersonId "Y2lzY29zcGFyazovL3VzL1BFT1BMRS9mMDZkNzFhNS0wODMzLTRmYTUtYTcyYS1jYzg5YjI1ZWVlMmX" , createMessageToPersonEmail = Just $ Email "julie@example.com" , createMessageText = Just $ MessageText "PROJECT UPDATE - A new project plan has been published on Box: http://box.com/s/lf5vj. The PM for this project is Mike C. and the Engineering Manager is Jane W." , createMessageMarkdown = Just $ MessageMarkdown "**PROJECT UPDATE** A new project plan has been published [on Box](http://box.com/s/lf5vj). The PM for this project is <@personEmail:mike@example.com> and the Engineering Manager is <@personEmail:jane@example.com>." , createMessageFiles = Just $ [ FileUrl "http://www.example.com/images/media.png" ] } it "getMessageList returns ListReader of Message" $ do let testData = messageList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (MessageList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest defFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/messages" queryString receivedReq `shouldBe` [ ("roomId", Just "dummyRoomId") ] it "getMessageList passes query strings build from MessageFilter to server" $ do let testData = messageList ['Z'] messageFilter = MessageFilter (RoomId "dummyRoomId") (Just $ MentionedPeopleMe) (Just $ Timestamp "beforeFilter") (Just $ MessageId "beforeMessageFilter") receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (MessageList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest messageFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/messages" (sort . queryString) receivedReq `shouldBe` sort [ ("roomId", Just "dummyRoomId") , ("mentionedPeople", Just "me") , ("beforeMessage", Just "beforeMessageFilter") , ("before", Just "beforeFilter") ] it "getMessageList returns ListReader of Message with automatic pagination" $ do withMockServer (paginationApp $ encode . MessageList <$> messageListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest defFilter >>= readAllList res `shouldBe` concat messageListList it "getMessageList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . MessageList <$> messageListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest defFilter >>= readAllList res `shouldBe` concat (take 2 messageListList) it "getDetail for a message returns a Message" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp messageJson req respond ) $ do resMessage <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (MessageId "testMessageId") resMessage `shouldBe` message receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/messages/testMessageId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a message returns a (Right Message)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp messageJson req respond ) $ do (Right resMessage) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (MessageId "testMessageId") resMessage `shouldBe` message it "createEntity for a message sends JSON encoded CreateMessage as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp messageJson req respond ) $ do resMessage <- getResponseBody <$> createEntity dummyAuth mockBaseRequest newMessage resMessage `shouldBe` message receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/messages" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newMessage it "createEntithEither for a message sends JSON encoded CreateMessage as its body of POST request" $ do receivedReqMVar <- newEmptyMVar receivedBodyMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req strictRequestBody req >>= putMVar receivedBodyMVar simpleApp messageJson req respond ) $ do (Right resMessage) <- getResponseBody <$> createEntityEither dummyAuth mockBaseRequest newMessage resMessage `shouldBe` message receivedReq <- takeMVar receivedReqMVar receivedBody <- takeMVar receivedBodyMVar requestMethod receivedReq `shouldBe` "POST" rawPathInfo receivedReq `shouldBe` "/v1/messages" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" decode receivedBody `shouldBe` Just newMessage it "deleteMessage sends DELETE request with messageId on URL path" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp "" req respond ) $ do deleteMessage dummyAuth mockBaseRequest (MessageId "testMessageId") receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "DELETE" rawPathInfo receivedReq `shouldBe` "/v1/messages/testMessageId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" describe "Organization" $ do let organizationJson = "{\ \ \"id\" : \"OTZhYmMyYWEtM2RjYy0xMWU1LWExNTItZmUzNDgxOWNkYzlh\",\ \ \"displayName\" : \"Cisco, Inc.\",\ \ \"created\" : \"2015-10-18T14:26:16+00:00\"\ \}" organization = Organization { organizationId = OrganizationId "OTZhYmMyYWEtM2RjYy0xMWU1LWExNTItZmUzNDgxOWNkYzlh" , organizationErrors = Nothing , organizationDisplayName = Just $ OrganizationDisplayName "Cisco, Inc." , organizationCreated = Just $ Timestamp "2015-10-18T14:26:16+00:00" } organizationGen i = Organization { organizationId = OrganizationId . pack $ "organizationId" <> i , organizationErrors = Nothing , organizationDisplayName = Just $ OrganizationDisplayName . pack $ "displayName" <> i , organizationCreated = Just $ Timestamp . pack $ "timestamp" <> i } organizationList j = [ organizationGen $ j <> show i | i <- [1..3] ] organizationListList = [ organizationList [c] | c <- ['a'..'d'] ] it "getOrganizationList returns ListReader of Organization" $ do let testData = organizationList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (OrganizationList testData)) req respond ) $ do res <- getOrganizationList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/organizations" queryString receivedReq `shouldBe` [] it "getOrganizationList returns ListReader of Organization performing automatic pagination" $ do withMockServer (paginationApp $ encode . OrganizationList <$> organizationListList) $ do res <- getOrganizationList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` concat organizationListList it "getOrganizationList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . OrganizationList <$> organizationListList) $ do res <- getOrganizationList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` concat (take 2 organizationListList) it "getDetail for an organization returns a Organization" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp organizationJson req respond ) $ do resOrganization <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (OrganizationId "testOrganizationId") resOrganization `shouldBe` organization receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/organizations/testOrganizationId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for an organization returns a (Right Organization)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp organizationJson req respond ) $ do (Right resOrganization) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (OrganizationId "testOrganizationId") resOrganization `shouldBe` organization describe "License" $ do let licenseJson = "{\ \ \"id\" : \"OTZhYmMyYWEtM2RjYy0xMWU1LWExNTItZmUzNDgxOWNkYzlh\",\ \ \"name\" : \"Spark Calling\",\ \ \"totalUnits\" : 42,\ \ \"consumedUnits\" : 8\ \}" license = License { licenseId = LicenseId "OTZhYmMyYWEtM2RjYy0xMWU1LWExNTItZmUzNDgxOWNkYzlh" , licenseErrors = Nothing , licenseName = Just $ LicenseName "Spark Calling" , licenseTotalUnits = Just $ LicenseUnit 42 , licenseConsumedUnits = Just $ LicenseUnit 8 } licenseGen i = License { licenseId = LicenseId . pack $ "licenseId" <> i , licenseErrors = Nothing , licenseName = Just $ LicenseName . pack $ "licenseName" <> i , licenseTotalUnits = Just $ LicenseUnit 42 , licenseConsumedUnits = Just $ LicenseUnit 8 } licenseList j = [ licenseGen $ j <> show i | i <- [1..3] ] licenseListList = [ licenseList [c] | c <- ['a'..'d'] ] it "getLicenseList returns ListReader of License" $ do let testData = licenseList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (LicenseList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/licenses" queryString receivedReq `shouldBe` [] it "getLicenseList passes query strings build from LicenseFilter to server" $ do let testData = licenseList ['Z'] licenseFilter = LicenseFilter (Just $ OrganizationId "orgIdFilter") receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (LicenseList testData)) req respond ) $ do res <- getListWithFilter dummyAuth mockBaseRequest licenseFilter >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/licenses" queryString receivedReq `shouldBe` [ ("orgId", Just "orgIdFilter") ] it "getLicenseList returns ListReader of License with automatic pagination" $ do withMockServer (paginationApp $ encode . LicenseList <$> licenseListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) >>= readAllList res `shouldBe` concat licenseListList it "getLicenseList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . LicenseList <$> licenseListList) $ do res <- getListWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) >>= readAllList res `shouldBe` concat (take 2 licenseListList) it "getDetail for a license returns a License" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp licenseJson req respond ) $ do resLicense <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (LicenseId "testLicenseId") resLicense `shouldBe` license receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/licenses/testLicenseId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a license returns a (Right License)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp licenseJson req respond ) $ do (Right resLicense) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (LicenseId "testLicenseId") resLicense `shouldBe` license describe "Role" $ do let roleJson = "{\ \ \"id\" : \"OTZhYmMyYWEtM2RjYy0xMWU1LWExNTItZmUzNDgxOWNkYzlh\",\ \ \"name\" : \"Full Administrator\"\ \}" role = Role { roleId = RoleId "OTZhYmMyYWEtM2RjYy0xMWU1LWExNTItZmUzNDgxOWNkYzlh" , roleErrors = Nothing , roleName = Just $ RoleName "Full Administrator" } roleGen i = Role { roleId = RoleId . pack $ "roleId" <> i , roleErrors = Nothing , roleName = Just . RoleName . pack $ "roleName" <> i } roleList j = [ roleGen $ j <> show i | i <- [1..3] ] roleListList = [ roleList [c] | c <- ['a'..'d'] ] it "getRoleList returns ListReader of Role" $ do let testData = roleList ['Z'] receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp (encode (RoleList testData)) req respond ) $ do res <- getRoleList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` testData receivedReq <- takeMVar receivedReqMVar rawPathInfo receivedReq `shouldBe` "/v1/roles" queryString receivedReq `shouldBe` [] it "getRoleList returns ListReader of Role performing automatic pagination" $ do withMockServer (paginationApp $ encode . RoleList <$> roleListList) $ do res <- getRoleList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` concat roleListList it "getRoleList stops pagination at invalid Link Header" $ do withMockServer (invalidPaginationApp $ encode . RoleList <$> roleListList) $ do res <- getRoleList dummyAuth mockBaseRequest >>= readAllList res `shouldBe` concat (take 2 roleListList) it "getDetail for a role returns a Role" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp roleJson req respond ) $ do resRole <- getResponseBody <$> getDetail dummyAuth mockBaseRequest (RoleId "testRoleId") resRole `shouldBe` role receivedReq <- takeMVar receivedReqMVar requestMethod receivedReq `shouldBe` "GET" rawPathInfo receivedReq `shouldBe` "/v1/roles/testRoleId" (lookup "Authorization" . requestHeaders) receivedReq `shouldBe` Just "Bearer dummyAuth" (lookup "Content-Type" . requestHeaders) receivedReq `shouldBe` Just "application/json; charset=utf-8" it "getDetailEither for a role returns a (Right Role)" $ do receivedReqMVar <- newEmptyMVar withMockServer (\req respond -> do putMVar receivedReqMVar req simpleApp roleJson req respond ) $ do (Right resRole) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (RoleId "testRoleId") resRole `shouldBe` role