packages feed

cisco-spark-api 0.1.0.0 → 0.1.0.1

raw patch · 6 files changed

+2048/−1890 lines, 6 filesdep +asyncdep −thread-hierarchydep ~conduit-combinators

Dependencies added: async

Dependencies removed: thread-hierarchy

Dependency ranges changed: conduit-combinators

Files

CHANGELOG.md view
@@ -1,3 +1,7 @@+## Cisco-spark-api 0.1.0.1++* Put explicit upper bound for conduit.+ ## Cisco-spark-api 0.1.0.0  * Initial release.
cisco-spark-api.cabal view
@@ -1,5 +1,5 @@ name:                cisco-spark-api-version:             0.1.0.0+version:             0.1.0.1 synopsis:            A Haskell bindings for Cisco Spark API description:         Cisco-spark-api package provides types and functions for accessing Cisco Spark REST API. @@ -34,7 +34,7 @@                      , aeson                      , attoparsec                      , bytestring-                     , conduit-combinators+                     , conduit-combinators < 1.3                      , data-default                      , http-conduit                      , network-uri@@ -49,7 +49,7 @@   build-depends:       base                      , aeson                      , bytestring-                     , conduit-combinators+                     , conduit-combinators < 1.3                      , data-default                      , http-conduit                      , optparse-applicative@@ -68,8 +68,9 @@   build-depends:       base                      , aeson                      , attoparsec+                     , async                      , bytestring-                     , conduit-combinators+                     , conduit-combinators < 1.3                      , data-default                      , http-conduit                      , http-types@@ -79,7 +80,6 @@                      , warp                      , hspec                      , cisco-spark-api-                     , thread-hierarchy   ghc-options:         -rtsopts   default-language:    Haskell2010 
src/Network/CiscoSpark.hs view
@@ -1,4 +1,3 @@-{-# LANGUAGE DataKinds         #-} {-# LANGUAGE FlexibleContexts  #-} {-# LANGUAGE OverloadedStrings #-} @@ -233,7 +232,7 @@     :: CiscoSparkRequest    -- ^ Common request components     -> ByteString           -- ^ API category part of REST URL path     -> CiscoSparkRequest-makeCommonListReq base@(CiscoSparkRequest { ciscoSparkRequestRequest = req }) path+makeCommonListReq base@CiscoSparkRequest { ciscoSparkRequestRequest = req } path     = base { ciscoSparkRequestRequest = setRequestPath ("/v1/" <> path) $ setRequestMethod "GET" req }  {-|@@ -250,7 +249,7 @@ -- | Processing pagination by HTTP Link header. streamListLoop :: (MonadIO m, FromJSON a, SparkListItem i) => Authorization -> Response a -> String -> URIAuth -> Source m i streamListLoop auth res scheme uriAuth-    = case getNextUrl res >>= validateUrl scheme uriAuth >>= (\url -> parseRequest $ "GET " <> (C8.unpack url)) of+    = case getNextUrl res >>= validateUrl scheme uriAuth >>= (\url -> parseRequest $ "GET " <> C8.unpack url) of     Nothing         -> pure ()     Just nextReq    -> do         nextRes <- httpJSON $ addAuthorizationHeader auth nextReq@@ -266,7 +265,7 @@ streamEntityWithFilter auth base param =     streamList auth $ setQeuryString $ makeCommonListReq base (apiPath param)       where-        setQeuryString comm@(CiscoSparkRequest { ciscoSparkRequestRequest = req })+        setQeuryString comm@CiscoSparkRequest { ciscoSparkRequestRequest = req }             = comm { ciscoSparkRequestRequest = setRequestQueryString (toFilterList param) req }  -- | List of 'Team' and stream it into Conduit pipe.  It automatically performs pagination.
src/Network/CiscoSpark/Types.hs view
@@ -2,7 +2,6 @@ {-# LANGUAGE DeriveGeneric       #-} {-# LANGUAGE FlexibleContexts    #-} {-# LANGUAGE OverloadedStrings   #-}-{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell     #-} {-# LANGUAGE TypeFamilies        #-} @@ -94,7 +93,11 @@ rolesPath :: ByteString rolesPath = "roles" +-- | URL path for webhooks API.+webhooksPath :: ByteString+webhooksPath = "webhooks" + {-|     SparkListItem is a type class grouping types with following common usage. @@ -199,7 +202,7 @@                     | PersonStatusOutOfOffice   -- ^ Email system of the 'Person' currently sets vacation.  Decoded from \"OutOfOffice\".                     | PersonStatusDoNotDisturb  -- ^ The 'Person' is explicitly indicated do-not-disturb.  Decoded from \"DoNotDisturb\".                     | PersonStatusUnknown       -- ^ The status of the 'Person' is unknown.  Decoded from \"unknown\".-                    deriving (Eq, Show, Generic)+                    deriving (Eq, Generic, Show)  -- | 'PersonStatus' implements 'toEncoding' to encode each constructor into JSON enum value. instance ToJSON PersonStatus where@@ -1011,7 +1014,7 @@     toFilterList filter = maybeToList $ (\(OrganizationId o) -> ("orgId", Just $ encodeUtf8 o)) <$> licenseFilterOrgId filter  --- | Name of 'Role'+-- | Name of 'Role'. newtype RoleName    = RoleName Text deriving (Eq, Show, Generic, ToJSON, FromJSON)  {-|@@ -1026,7 +1029,7 @@     } deriving (Eq, Show)  $(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 4, omitNothingFields = True } ''Role)--- ^ 'RoleName' derives ToJSON and FromJSON via deriveJSON template haskell function.+-- ^ 'Role' derives ToJSON and FromJSON via deriveJSON template haskell function.  -- | Get detail for role API uses 'RoleId' and path "roles". instance SparkApiPath RoleId where@@ -1049,3 +1052,249 @@ instance SparkListItem Role where     type ToList Role = RoleList     unwrap = roleListItems+++-- | 'Webhook' identifier which can be assigned to user.  See 'Webhook' too.+newtype WebhookId       = WebhookId Text deriving (Eq, Show, Generic, ToJSON, FromJSON)+-- | Name of 'Webhook'.+newtype WebhookName     = WebhookName Text deriving (Eq, Show, Generic, ToJSON, FromJSON)+-- | URL pointing to webhook target.+newtype WebhookUrl      = WebhookUrl Text deriving (Eq, Show, Generic, ToJSON, FromJSON)+-- | URL-encoded set of webhook filtering criteria.+newtype WebhookFilter   = WebhookFilter Text deriving (Eq, Show, Generic, ToJSON, FromJSON)+-- | Shared secret supplied by user to authenticate Spark Cloud by webhook receiver.+newtype WebhookSecret   = WebhookSecret Text deriving (Eq, Show, Generic, ToJSON, FromJSON)++-- | 'WebhookResource' indicates source of event which triggered webhook access.+data WebhookResource = WebhookResourceAll+                     | WebhookResourceTeams+                     | WebhookResourceMemberships+                     | WebhookResourceMessages+                     | WebhookResourceRooms+                     deriving (Eq, Show)++$(deriveJSON defaultOptions { constructorTagModifier = dropAndLow 15 } ''WebhookResource)+-- ^ 'WebhookResource' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | WebhookEvent indicates which event triggered Webhook access.+data WebhookEvent = WebhookEventAll+                  | WebhookEventCreated+                  | WebhookEventUpdated+                  | WebhookEventDeleted+                  deriving (Eq, Show)++$(deriveJSON defaultOptions { constructorTagModifier = dropAndLow 12 } ''WebhookEvent)+-- ^ 'WebhookEvent' derives ToJSON and FromJSON via deriveJSON template haskell function.++{-|+    'Webhook' allow your app to be notified via HTTP when a specific event occurs on Spark. For example,+    your app can register a webhook to be notified when a new message is posted into a specific room.+-}+data Webhook = Webhook+    { webhookId        :: WebhookId             -- ^ Identifier of the Webhook.+    , webhookErrors    :: Maybe Errors          -- ^ Element level error possibly contained in List API response.+    , webhookName      :: Maybe WebhookName     -- ^ Name of the Webhook.+    , webhookTargetUrl :: Maybe WebhookUrl      -- ^ URL pointing to webhook target.+    , webhookResource  :: Maybe WebhookResource -- ^ Resource type where events are monitored.+    , webhookEvent     :: Maybe WebhookEvent    -- ^ Event type which will be monitored.+    , webhookFilter    :: Maybe WebhookFilter   -- ^ URL-encoded set of webhook filtering criteria.+    , webhookSecret    :: Maybe WebhookSecret   -- ^ User supplied shared secret for authentication.+    , webhookCreated   :: Maybe Timestamp       -- ^ Timestamp when the Webhook was created.+    } deriving (Eq, Show)++$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 7, omitNothingFields = True } ''Webhook)+-- ^ 'Webhook' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | Get detail for webhook API uses 'WebhookId' and path "webhooks".+instance SparkApiPath WebhookId where+    apiPath _ = webhooksPath++-- | Get detail for a webhook API uses "WebhookId' and responses 'Webhook'.+instance SparkResponse WebhookId where+    type ToResponse WebhookId = Webhook++-- | User can get detail of a webhook.+instance SparkDetail WebhookId where+    toIdStr (WebhookId s) = s++-- | 'WebhookList' is decoded from response JSON of List Webhook REST call.  It is list of 'Webhook'.+newtype WebhookList = WebhookList { webhookListItems :: [Webhook] } deriving (Eq, Show)+$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 11, omitNothingFields = True } ''WebhookList)+-- ^ 'WebhookList' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | 'WebhookList' wraps 'Webhook'+instance SparkListItem Webhook where+    type ToList Webhook = WebhookList+    unwrap = webhookListItems++-- | 'CreateWebhook' is encoded to request body JSON of Create a Webhook REST call.+data CreateWebhook = CreateWebhook+    { createWebhookName      :: WebhookName         -- ^ Name of Webhook to be created.+    , createWebhookTargetUrl :: WebhookUrl          -- ^ URL pointing to webhook target.+    , createWebhookResource  :: WebhookResource     -- ^ Resource type where events will be monitored.+    , createWebhookEvent     :: WebhookEvent        -- ^ Event type which will be monitored.+    , createWebhookFilter    :: Maybe WebhookFilter -- ^ URL-encoded set of webhook filtering criteria.+    , createWebhookSecret    :: Maybe WebhookSecret -- ^ User supplied shared secret for authentication.+    } deriving (Eq, Show)++$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 13, omitNothingFields = True } ''CreateWebhook)+-- ^ 'CreateWebhook' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | Create webhook API uses 'CreateWebhook' and path "webhooks".+instance SparkApiPath CreateWebhook where+    apiPath _ = webhooksPath++-- | Create webhook API uses "CreateWebhook' and responses 'Webhook'.+instance SparkResponse CreateWebhook where+    type ToResponse CreateWebhook = Webhook++-- | User can create a webhook.+instance SparkCreate CreateWebhook where++-- | 'UpdateWebhook' is encoded to request body JSON of Update a Webhook REST call.+data UpdateWebhook = UpdateWebhook+    { updateWebhookName      :: WebhookName -- ^ Name of Webhook to be created.+    , updateWebhookTargetUrl :: WebhookUrl  -- ^ URL pointing to webhook target.+    } deriving (Eq, Show)++$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 13, omitNothingFields = True } ''UpdateWebhook)+-- ^ 'UpdateWebhook' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | Update webhook API uses 'UpdateWebhook' and path "webhooks".+instance SparkApiPath UpdateWebhook where+    apiPath _ = webhooksPath++-- | Update webhook API uses "UpdateWebhook' and responses 'Webhook'.+instance SparkResponse UpdateWebhook where+    type ToResponse UpdateWebhook = Webhook++-- | User can update a webhook.+instance SparkUpdate UpdateWebhook++-- | Optional query strings for membership event.+data WebhookMembershipFilter = WebhookMembershipFilter+    { webhookFilterMembershipRoomId      :: Maybe RoomId    -- ^ Feed events only for given room.+    , webhookFilterMembershipPersonId    :: Maybe PersonId  -- ^ Feed events only for given person.+    , webhookFilterMembershipPersonEmail :: Maybe Email     -- ^ Feed events only person who has given email.+    , webhookFilterMembershipIsModerator :: Maybe Bool      -- ^ Feed events only for moderator membership changes.+    } deriving (Eq, Show)++-- | Create webhook API accepts 'WebhookMembershipFilter' and uses path "webhooks".+instance SparkApiPath WebhookMembershipFilter where+    apiPath _ = webhooksPath++-- | List team memberships API accepts 'WebhookMembershipFilter' and responses 'Webhook'.+instance SparkResponse WebhookMembershipFilter where+    type ToResponse WebhookMembershipFilter = Webhook++-- | User can filter Webhook events from membership.+instance SparkFilter WebhookMembershipFilter where+    toFilterList filter = catMaybes+        [ (\(RoomId r) -> ("roomId", Just $ encodeUtf8 r)) <$> webhookFilterMembershipRoomId filter+        , (\(PersonId p) -> ("personId", Just (encodeUtf8 p))) <$> webhookFilterMembershipPersonId filter+        , (\(Email e) -> ("personEmail", Just (encodeUtf8 e))) <$> webhookFilterMembershipPersonEmail filter+        , (\b -> ("isModerator", Just (if b then "true" else "false"))) <$> webhookFilterMembershipIsModerator filter+        ]++-- | Optional query strings for message event.+data WebhookMessageFilter = WebhookMessageFilter+    { webhookFilterMessageRoomId          :: Maybe RoomId           -- ^ Feed events only for given room.+    , webhookFilterMessageRoomType        :: Maybe RoomType         -- ^ Feed events only for given room type.+    , webhookFilterMessagePersonId        :: Maybe PersonId         -- ^ Feed events only for given person.+    , webhookFilterMessagePersonEmail     :: Maybe Email            -- ^ Feed events only person who has given email.+    , webhookFilterMessagememtionedPeople :: Maybe MentionedPeople  -- ^ Feed events only mentioned for given person.+    , webhookFilterMessageHasFiles        :: Maybe Bool             -- ^ Feed events only messages with attached file.+     } deriving (Eq, Show)++-- | Create webhook API accepts 'WebhookMessageFilter' and uses path "webhooks".+instance SparkApiPath WebhookMessageFilter where+    apiPath _ = webhooksPath++-- | List team memberships API accepts 'WebhookMessageFilter' and responses 'Webhook'.+instance SparkResponse WebhookMessageFilter where+    type ToResponse WebhookMessageFilter = Webhook++-- | User can filter Webhook events from message.+instance SparkFilter WebhookMessageFilter where+    toFilterList filter = catMaybes+        [ (\(RoomId r) -> ("roomId", Just $ encodeUtf8 r)) <$> webhookFilterMessageRoomId filter+        , (\t -> ("roomType", Just $ roomTypeToFilterString t)) <$> webhookFilterMessageRoomType filter+        , (\(PersonId p) -> ("personId", Just (encodeUtf8 p))) <$> webhookFilterMessagePersonId filter+        , (\(Email e) -> ("personEmail", Just (encodeUtf8 e))) <$> webhookFilterMessagePersonEmail filter+        , (\p -> ("mentionedPeople", Just $ mentionedPeopleToFilterString p)) <$> webhookFilterMessagememtionedPeople filter+        , (\b -> ("hasFiles", Just (if b then "true" else "false"))) <$> webhookFilterMessageHasFiles filter+        ]++-- | Optional query strings for room event.+data WebhookRoomFilter = WebhookRoomFilter+    { webhookFilterRoomType     :: Maybe RoomType   -- ^ Feed events only for given room type.+    , webhookFilterRoomIsLocked :: Maybe Bool       -- ^ Feed events only locked unlocked rooms when true.+     } deriving (Eq, Show)++-- | Create webhook API accepts 'WebhookRoomFilter' and uses path "webhooks".+instance SparkApiPath WebhookRoomFilter where+    apiPath _ = webhooksPath++-- | List team memberships API accepts 'WebhookRoomFilter' and responses 'Webhook'.+instance SparkResponse WebhookRoomFilter where+    type ToResponse WebhookRoomFilter = Webhook++-- | User can filter Webhook events from room.+instance SparkFilter WebhookRoomFilter where+    toFilterList filter = catMaybes+        [ (\t -> ("type", Just $ roomTypeToFilterString t)) <$> webhookFilterRoomType filter+        , (\b -> ("isLocked", Just (if b then "true" else "false"))) <$> webhookFilterRoomIsLocked filter+        ]+++-- | Identifier of app.+newtype AppId = AppId Text deriving (Eq, Show, Generic, ToJSON, FromJSON)++-- | 'WebhookNotifyOwnedBy' indicates if the webhook is owned by the org or the creator.+data WebhookNotifyOwnedBy = WebhookNotifyOwnedByOrg | WebhookNotifyOwnedByCreator deriving (Eq, Show)++$(deriveJSON defaultOptions { constructorTagModifier = dropAndLow 18 } ''WebhookNotifyOwnedBy)+-- ^ 'WebhookNotifyOwnedBy' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | 'WebhookNotifyStatus' indicates if the webhook is active.+data WebhookNotifyStatus = WebhookNotifyStatusActive | WebhookNotifyStatusDesabled deriving (Eq, Show)++$(deriveJSON defaultOptions { constructorTagModifier = dropAndLow 19 } ''WebhookNotifyStatus)+-- ^ 'WebhookNotifyStatus' derives ToJSON and FromJSON via deriveJSON template haskell function.++{-|+    'Webhook' decodes webhook notification from Spark Cloud except data field.+    Data field can be one of 'Membership', 'Message' or 'Room'.  Type of data field is+    shown as value of resource field.+-}+data WebhookNotify = WebhookNotify+    { webhookNotifyId        :: WebhookId+    , webhookNotifyName      :: WebhookName+    , webhookNotifyResource  :: WebhookResource+    , webhookNotifyEvent     :: WebhookEvent+    , webhookNotifyFilter    :: WebhookFilter+    , webhookNotifyOrgId     :: Organization+    , webhookNotifyCreatedBy :: PersonId+    , webhookNotifyAppId     :: AppId+    , webhookNotifyOwnedBy   :: WebhookNotifyOwnedBy+    , webhookNotifyStatus    :: WebhookNotifyStatus+    , webhookNotifyActorId   :: PersonId+    } deriving (Eq, Show)++$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 13, omitNothingFields = True } ''WebhookNotify)+-- ^ 'WebhookNotify' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | Data part of webhook notification is decoded to 'Membership' when resource field value is "memberships".+newtype WebhookNotifyMembership = WebhookNotifyMembership { webhookNotifyMembershipData :: Membership } deriving (Eq, Show)+$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 23, omitNothingFields = True } ''WebhookNotifyMembership)+-- ^ 'WebhookNotifyMembership' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | Data part of webhook notification is decoded to 'Message' when resource field value is "messages".+newtype WebhookNotifyMessage = WebhookNotifyMessage { webhookNotifyMessageData :: Message } deriving (Eq, Show)+$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 20, omitNothingFields = True } ''WebhookNotifyMessage)+-- ^ 'WebhookNotifyMessage' derives ToJSON and FromJSON via deriveJSON template haskell function.++-- | Data part of webhook notification is decoded to 'Room' when resource field value is "rooms".+newtype WebhookNotifyRoom = WebhookNotifyRoom { webhookNotifyRoomData :: Room } deriving (Eq, Show)+$(deriveJSON defaultOptions { fieldLabelModifier = dropAndLow 17, omitNothingFields = True } ''WebhookNotifyRoom)+-- ^ 'WebhookNotifyRoom' derives ToJSON and FromJSON via deriveJSON template haskell function.
test/Network/CiscoSpark/TypesSpec.hs view
@@ -18,8 +18,8 @@                          \    \"reason\": \"Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html\"\                          \  }\                          \}"-            errors = Errors { errorsTitle = ErrorTitle { errorTitleCode = ErrorCode "kms_failure"-                                                       , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"+            errors = Errors { errorsTitle = ErrorTitle { errorTitleCode     = ErrorCode "kms_failure"+                                                       , errorTitleReason   = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                                        }                             } @@ -110,29 +110,29 @@                               \    }\                               \  }\                               \}"-            personError = Person { personId = PersonId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                                 , personErrors = Just $ Errors-                                     { errorsTitle = ErrorTitle-                                         { errorTitleCode = ErrorCode "kms_failure"+            personError = Person { personId                 = PersonId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                 , personErrors             = Just $ Errors+                                     { errorsTitle          = ErrorTitle+                                         { errorTitleCode   = ErrorCode "kms_failure"                                          , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                          }                                      }-                                 ,personEmails        = Nothing-                                 ,personDisplayName   = Nothing-                                 ,personNickName      = Nothing-                                 ,personFirstName     = Nothing-                                 ,personLastName      = Nothing-                                 ,personAvatar        = Nothing-                                 ,personOrgId         = Nothing-                                 ,personRoles         = Nothing-                                 ,personLicenses      = Nothing-                                 ,personCreated       = Nothing-                                 ,personTimezone      = Nothing-                                 ,personLastActivity  = Nothing-                                 ,personStatus        = Nothing-                                 ,personInvitePending = Nothing-                                 ,personLoginEnabled  = Nothing-                                 ,personType          = Nothing+                                 ,personEmails              = Nothing+                                 ,personDisplayName         = Nothing+                                 ,personNickName            = Nothing+                                 ,personFirstName           = Nothing+                                 ,personLastName            = Nothing+                                 ,personAvatar              = Nothing+                                 ,personOrgId               = Nothing+                                 ,personRoles               = Nothing+                                 ,personLicenses            = Nothing+                                 ,personCreated             = Nothing+                                 ,personTimezone            = Nothing+                                 ,personLastActivity        = Nothing+                                 ,personStatus              = Nothing+                                 ,personInvitePending       = Nothing+                                 ,personLoginEnabled        = Nothing+                                 ,personType                = Nothing                              }             personListJson = "{\"items\":[" <> personJson1 <> "," <> personJson2 <> "," <> personErrorJson <> "]}"             personList = PersonList [ person1, person2, personError ]@@ -200,16 +200,16 @@                             \    }\                             \  }\                             \}"-            teamError = Team { teamId = TeamId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                             , teamErrors = Just $ Errors-                                 { errorsTitle = ErrorTitle-                                     { errorTitleCode = ErrorCode "kms_failure"+            teamError = Team { teamId                   = TeamId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                             , teamErrors               = Just $ Errors+                                 { errorsTitle          = ErrorTitle+                                     { errorTitleCode   = ErrorCode "kms_failure"                                      , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                      }                                  }-                             , teamName      = Nothing-                             , teamCreatorId = Nothing-                             , teamCreated   = Nothing+                             , teamName                 = Nothing+                             , teamCreatorId            = Nothing+                             , teamCreated              = Nothing                              }             teamListJson = "{\"items\":[" <> teamJson <> "," <> teamErrorJson <> "]}"             teamList = TeamList [ team, teamError ]@@ -267,11 +267,11 @@                                       \    }\                                       \  }\                                       \}"-            teamMembershipError = TeamMembership { teamMembershipId = TeamMembershipId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                                                 , teamMembershipErrors = Just $ Errors-                                                     { errorsTitle = ErrorTitle-                                                         { errorTitleCode = ErrorCode "kms_failure"-                                                         , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"+            teamMembershipError = TeamMembership { teamMembershipId                 = TeamMembershipId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                                 , teamMembershipErrors             = Just $ Errors+                                                     { errorsTitle                  = ErrorTitle+                                                         { errorTitleCode           = ErrorCode "kms_failure"+                                                         , errorTitleReason         = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                                          }                                                      }                                                  , teamMembershipTeamId             = Nothing@@ -350,21 +350,21 @@                             \    }\                             \  }\                             \}"-            roomError = Room { roomId = RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                             , roomErrors = Just $ Errors-                                 { errorsTitle = ErrorTitle-                                     { errorTitleCode = ErrorCode "kms_failure"+            roomError = Room { roomId                   = RoomId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                             , roomErrors               = Just $ Errors+                                 { errorsTitle          = ErrorTitle+                                     { errorTitleCode   = ErrorCode "kms_failure"                                      , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                      }                                  }-                             , roomTitle = Nothing-                             , roomType = Nothing-                             , roomIsLocked = Nothing-                             , roomSipAddress = Nothing-                             , roomLastActivity = Nothing-                             , roomTeamId = Nothing-                             , roomCreatorId = Nothing-                             , roomCreated = Nothing+                             , roomTitle                = Nothing+                             , roomType                 = Nothing+                             , roomIsLocked             = Nothing+                             , roomSipAddress           = Nothing+                             , roomLastActivity         = Nothing+                             , roomTeamId               = Nothing+                             , roomCreatorId            = Nothing+                             , roomCreated              = Nothing                              }             roomListJson = "{\"items\":[" <> roomJson <> "," <> roomErrorJson <> "]}"             roomList = RoomList [ room, roomError ]@@ -381,7 +381,7 @@             (decode . encode) roomList `shouldBe` Just roomList          it "encodes CreateRoom to JSON" $ do-            let src = CreateRoom { createRoomTitle = RoomTitle "Project Unicorn - Sprint 0"+            let src = CreateRoom { createRoomTitle  = RoomTitle "Project Unicorn - Sprint 0"                                  , createRoomTeamId = Just $ TeamId "Y2lzY29zcGFyazovL3VzL1JPT00vNjRlNDVhZTAtYzQ2Yi0xMWU1LTlkZjktMGQ0MWUzNDIxOTcz"                                  }                 dst = "{\@@ -429,21 +429,21 @@                                   \    }\                                   \  }\                                   \}"-            membershipError = Membership { membershipId = MembershipId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                                         , membershipErrors = Just $ Errors-                                             { errorsTitle = ErrorTitle-                                                 { errorTitleCode = ErrorCode "kms_failure"-                                                 , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"+            membershipError = Membership { membershipId                 = MembershipId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                         , membershipErrors             = Just $ Errors+                                             { errorsTitle              = ErrorTitle+                                                 { errorTitleCode       = ErrorCode "kms_failure"+                                                 , errorTitleReason     = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                                  }                                              }-                                         , membershipRoomId              = Nothing-                                         , membershipPersonId            = Nothing-                                         , membershipPersonEmail         = Nothing-                                         , membershipPersonDisplayName   = Nothing-                                         , membershipPersonOrgId         = Nothing-                                         , membershipIsModerator         = Nothing-                                         , membershipIsMonitor           = Nothing-                                         , membershipCreated             = Nothing+                                         , membershipRoomId             = Nothing+                                         , membershipPersonId           = Nothing+                                         , membershipPersonEmail        = Nothing+                                         , membershipPersonDisplayName  = Nothing+                                         , membershipPersonOrgId        = Nothing+                                         , membershipIsModerator        = Nothing+                                         , membershipIsMonitor          = Nothing+                                         , membershipCreated            = Nothing                                          }             membershipListJson = "{\"items\":[" <> membershipJson <> "," <> membershipErrorJson <> "]}"             membershipList = MembershipList [ membership, membershipError ]@@ -520,24 +520,24 @@                                \    }\                                \  }\                                \}"-            messageError = Message { messageId = MessageId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                                   , messageErrors = Just $ Errors-                                       { errorsTitle = ErrorTitle-                                           { errorTitleCode = ErrorCode "kms_failure"-                                           , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"+            messageError = Message { messageId                  = MessageId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                   , messageErrors              = Just $ Errors+                                       { errorsTitle            = ErrorTitle+                                           { errorTitleCode     = ErrorCode "kms_failure"+                                           , errorTitleReason   = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                            }                                        }-                                   , messageRoomId           = Nothing-                                   , messageRoomType         = Nothing-                                   , messageToPersonId       = Nothing-                                   , messageToPersonEmail    = Nothing-                                   , messageText             = Nothing-                                   , messageHtml             = Nothing-                                   , messageFiles            = Nothing-                                   , messagePersonId         = Nothing-                                   , messagePersonEmail      = Nothing-                                   , messageCreated          = Nothing-                                   , messageMentionedPeople  = Nothing+                                   , messageRoomId              = Nothing+                                   , messageRoomType            = Nothing+                                   , messageToPersonId          = Nothing+                                   , messageToPersonEmail       = Nothing+                                   , messageText                = Nothing+                                   , messageHtml                = Nothing+                                   , messageFiles               = Nothing+                                   , messagePersonId            = Nothing+                                   , messagePersonEmail         = Nothing+                                   , messageCreated             = Nothing+                                   , messageMentionedPeople     = Nothing                                    }             messageListJson = "{\"items\":[" <> messageJson <> "," <> messageErrorJson <> "]}"             messageList = MessageList [ message, messageError ]@@ -545,11 +545,11 @@         it "can be unwrapped from MessageList" $ do             unwrap messageList `shouldBe` [ message, messageError ] -        it "decodes Team Message API response JSON" $ do+        it "decodes Message API response JSON" $ do             eitherDecode messageJson `shouldBe` Right message             (decode . encode) message `shouldBe` Just message -        it "decodes Team Message list" $ do+        it "decodes Message list" $ do             eitherDecode messageListJson `shouldBe` Right messageList             (decode . encode) messageList `shouldBe` Just messageList @@ -593,15 +593,15 @@                                     \    }\                                     \  }\                                     \}"-            organizationError = Organization { organizationId = OrganizationId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                                             , organizationErrors = Just $ Errors-                                                 { errorsTitle = ErrorTitle-                                                     { errorTitleCode = ErrorCode "kms_failure"+            organizationError = Organization { organizationId           = OrganizationId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                             , organizationErrors       = Just $ Errors+                                                 { errorsTitle          = ErrorTitle+                                                     { errorTitleCode   = ErrorCode "kms_failure"                                                      , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                                      }                                                  }-                                             , organizationDisplayName   = Nothing-                                             , organizationCreated       = Nothing+                                             , organizationDisplayName  = Nothing+                                             , organizationCreated      = Nothing                                              }             organizationListJson = "{\"items\":[" <> organizationJson <> "," <> organizationErrorJson <> "]}"             organizationList = OrganizationList [ organization, organizationError ]@@ -609,11 +609,11 @@         it "can be unwrapped from OrganizationList" $ do             unwrap organizationList `shouldBe` [ organization, organizationError ] -        it "decodes Team Organization API response JSON" $ do+        it "decodes Organization API response JSON" $ do             eitherDecode organizationJson `shouldBe` Right organization             (decode . encode) organization `shouldBe` Just organization -        it "decodes Team Organization list" $ do+        it "decodes Organization list" $ do             eitherDecode organizationListJson `shouldBe` Right organizationList             (decode . encode) organizationList `shouldBe` Just organizationList @@ -631,24 +631,24 @@                               , licenseConsumedUnits    = Just $ LicenseUnit 8                               }             licenseErrorJson = "{\-                                \  \"id\": \"Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5\",\-                                \  \"errors\": {\-                                \    \"title\": {\-                                \      \"code\": \"kms_failure\",\-                                \      \"reason\": \"Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html\"\-                                \    }\-                                \  }\-                                \}"-            licenseError = License { licenseId = LicenseId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                                   , licenseErrors = Just $ Errors-                                       { errorsTitle = ErrorTitle-                                           { errorTitleCode = ErrorCode "kms_failure"-                                           , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"+                               \  \"id\": \"Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5\",\+                               \  \"errors\": {\+                               \  \"title\": {\+                               \      \"code\": \"kms_failure\",\+                               \      \"reason\": \"Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html\"\+                               \    }\+                               \  }\+                               \}"+            licenseError = License { licenseId                  = LicenseId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                   , licenseErrors              = Just $ Errors+                                       { errorsTitle            = ErrorTitle+                                           { errorTitleCode     = ErrorCode "kms_failure"+                                           , errorTitleReason   = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                            }                                        }-                                   , licenseName             = Nothing-                                   , licenseTotalUnits       = Nothing-                                   , licenseConsumedUnits    = Nothing+                                   , licenseName                = Nothing+                                   , licenseTotalUnits          = Nothing+                                   , licenseConsumedUnits       = Nothing                                    }             licenseListJson = "{\"items\":[" <> licenseJson <> "," <> licenseErrorJson <> "]}"             licenseList = LicenseList [ license, licenseError ]@@ -656,11 +656,11 @@         it "can be unwrapped from LicenseList" $ do             unwrap licenseList `shouldBe` [ license, licenseError ] -        it "decodes Team License API response JSON" $ do+        it "decodes License API response JSON" $ do             eitherDecode licenseJson `shouldBe` Right license             (decode . encode) license `shouldBe` Just license -        it "decodes Team License list" $ do+        it "decodes License list" $ do             eitherDecode licenseListJson `shouldBe` Right licenseList             (decode . encode) licenseList `shouldBe` Just licenseList @@ -674,22 +674,22 @@                         , roleName   = Just $ RoleName "Full Administrator"                         }             roleErrorJson = "{\-                             \  \"id\": \"Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5\",\-                             \  \"errors\": {\-                             \    \"title\": {\-                             \      \"code\": \"kms_failure\",\-                             \      \"reason\": \"Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html\"\-                             \    }\-                             \  }\-                             \}"-            roleError = Role { roleId = RoleId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"-                             , roleErrors = Just $ Errors-                                 { errorsTitle = ErrorTitle-                                     { errorTitleCode = ErrorCode "kms_failure"+                            \  \"id\": \"Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5\",\+                            \  \"errors\": {\+                            \    \"title\": {\+                            \      \"code\": \"kms_failure\",\+                            \      \"reason\": \"Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html\"\+                            \    }\+                            \  }\+                            \}"+            roleError = Role { roleId                   = RoleId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                             , roleErrors               = Just $ Errors+                                 { errorsTitle          = ErrorTitle+                                     { errorTitleCode   = ErrorCode "kms_failure"                                      , errorTitleReason = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"                                      }                                  }-                             , roleName = Nothing+                             , roleName                 = Nothing                              }             roleListJson = "{\"items\":[" <> roleJson <> "]}"             roleList = RoleList [ role ]@@ -697,10 +697,96 @@         it "can be unwrapped from RoleList" $ do             unwrap roleList `shouldBe` [ role ] -        it "decodes Team Role API response JSON" $ do+        it "decodes Role API response JSON" $ do             eitherDecode roleJson `shouldBe` Right role             (decode . encode) role `shouldBe` Just role -        it "decodes Team Role list" $ do+        it "decodes Role list" $ do             eitherDecode roleListJson `shouldBe` Right roleList             (decode . encode) roleList `shouldBe` Just roleList++    describe "Webhook" $ do+        let webhookJson = "{\+                          \  \"id\" : \"96abc2aa-3dcc-11e5-a152-fe34819cdc9a\",\+                          \  \"name\" : \"My Awesome Webhook\",\+                          \  \"targetUrl\" : \"https://example.com/mywebhook\",\+                          \  \"resource\" : \"messages\",\+                          \  \"event\" : \"created\",\+                          \  \"filter\" : \"roomId=Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0\",\+                          \  \"secret\" : \"86dacc007724d8ea666f88fc77d918dad9537a15\",\+                          \  \"created\" : \"2015-10-18T14:26:16+00:00\"\+                          \}"+            webhook = Webhook { webhookId           = WebhookId "96abc2aa-3dcc-11e5-a152-fe34819cdc9a"+                              , webhookErrors       = Nothing+                              , webhookName         = Just $ WebhookName "My Awesome Webhook"+                              , webhookTargetUrl    = Just $ WebhookUrl "https://example.com/mywebhook"+                              , webhookResource     = Just $ WebhookResourceMessages+                              , webhookEvent        = Just $ WebhookEventCreated+                              , webhookFilter       = Just $ WebhookFilter "roomId=Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0"+                              , webhookSecret       = Just $ WebhookSecret "86dacc007724d8ea666f88fc77d918dad9537a15"+                              , webhookCreated      = Just $ Timestamp "2015-10-18T14:26:16+00:00"+                              }+            webhookErrorJson = "{\+                               \  \"id\": \"Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5\",\+                               \  \"errors\": {\+                               \    \"title\": {\+                               \      \"code\": \"kms_failure\",\+                               \      \"reason\": \"Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html\"\+                               \    }\+                               \  }\+                               \}"+            webhookError = Webhook { webhookId                  = WebhookId "Y2lzY29zcGFyazovL3VzL1JPT00vNTIxN0EyMzYtNDQzQi00NThELTkzNjAtRDRFOTMyMTBBNUU5"+                                   , webhookErrors              = Just $ Errors+                                       { errorsTitle            = ErrorTitle+                                           { errorTitleCode     = ErrorCode "kms_failure"+                                           , errorTitleReason   = "Key management server failed to respond appropriately. For more information: https://developer.ciscospark.com/errors.html"+                                           }+                                       }+                                   , webhookName                = Nothing+                                   , webhookTargetUrl           = Nothing+                                   , webhookResource            = Nothing+                                   , webhookEvent               = Nothing+                                   , webhookFilter              = Nothing+                                   , webhookSecret              = Nothing+                                   , webhookCreated             = Nothing+                                   }+            webhookListJson = "{\"items\":[" <> webhookJson <> "," <> webhookErrorJson <> "]}"+            webhookList = WebhookList [ webhook, webhookError ]++        it "can be unwrapped from WebhookList" $ do+            unwrap webhookList `shouldBe` [ webhook, webhookError ]++        it "decodes Webhook API response JSON" $ do+            eitherDecode webhookJson `shouldBe` Right webhook+            (decode . encode) webhook `shouldBe` Just webhook++        it "decodes Webhook list" $ do+            eitherDecode webhookListJson `shouldBe` Right webhookList+            (decode . encode) webhookList `shouldBe` Just webhookList++        it "encodes CreateWebhook to JSON" $ do+            let src = CreateWebhook { createWebhookName         = WebhookName "My Awesome Webhook"+                                    , createWebhookTargetUrl    = WebhookUrl "https://example.com/mywebhook"+                                    , createWebhookResource     = WebhookResourceMessages+                                    , createWebhookEvent        = WebhookEventCreated+                                    , createWebhookFilter       = Just $ WebhookFilter "roomId=Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0"+                                    , createWebhookSecret       = Just $ WebhookSecret "86dacc007724d8ea666f88fc77d918dad9537a15"+                                    }+                dst = "{\+                      \  \"name\" : \"My Awesome Webhook\",\+                      \  \"targetUrl\" : \"https://example.com/mywebhook\",\+                      \  \"resource\" : \"messages\",\+                      \  \"event\" : \"created\",\+                      \  \"filter\" : \"roomId=Y2lzY29zcGFyazovL3VzL1JPT00vYmJjZWIxYWQtNDNmMS0zYjU4LTkxNDctZjE0YmIwYzRkMTU0\",\+                      \  \"secret\" : \"86dacc007724d8ea666f88fc77d918dad9537a15\"\+                      \}"+            eitherDecode dst `shouldBe` Right src+            (decode . encode) src `shouldBe` (decode dst :: Maybe CreateWebhook)++        it "encodes UpdateWebhook to JSON" $ do+            let src = UpdateWebhook { updateWebhookName         = WebhookName "My Awesome Webhook"+                                    , updateWebhookTargetUrl    = WebhookUrl "https://example.com/mywebhook"+                                    }+                dst = "{\"name\":\"My Awesome Webhook\",\"targetUrl\":\"https://example.com/mywebhook\"}"+            encode src `shouldBe` dst+            (decode . encode) src `shouldBe` Just src
test/Network/CiscoSparkSpec.hs view
@@ -1,1758 +1,1578 @@-{-# LANGUAGE DataKinds         #-}-{-# LANGUAGE OverloadedStrings #-}--module Network.CiscoSparkSpec where--import           Conduit-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 (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--import           Network.HTTP.Types           (Header, status200)-import           Network.URI                  (URIAuth (..))-import           Network.Wai-import           Network.Wai.Handler.Warp     (Settings, defaultSettings,-                                               runSettings, setBeforeMainLoop)--import           Test.Hspec--import           Control.Concurrent.Hierarchy (ThreadMap, killThreadHierarchy,-                                               newChild, newThreadMap)-import           Network.CiscoSpark-import           Network.CiscoSpark.Internal  (LinkHeader (..), LinkParam (..),-                                               getNextUrl, linkHeader)---import           Data.Typeable                (typeOf)---newtype MockServer = MockServer ThreadMap--mockBaseRequestRequest-    = C.addRequestHeader "Content-Type" "application/json; charset=utf-8"-    $ C.setRequestPort 3000-    $ C.setRequestHost "localhost"-    $ C.setRequestSecure False-    $ C.defaultRequest--mockBaseRequest :: CiscoSparkRequest-mockBaseRequest = CiscoSparkRequest mockBaseRequestRequest "http:" $ URIAuth "" "localhost" ":3000"--dummyAuth :: Authorization-dummyAuth = Authorization "dummyAuth"--extractRight :: Show err => Either err r -> r-extractRight (Right r)  = r-extractRight (Left err) = error $ show err--startMockServer :: Application -> IO MockServer-startMockServer app = do-    readyToConnect <- newEmptyMVar-    rootThreadMap <- newThreadMap-    let set = setBeforeMainLoop (putMVar readyToConnect ()) defaultSettings-    newChild rootThreadMap $ \_ -> runSettings set app-    takeMVar readyToConnect-    return $ MockServer rootThreadMap--stopMockServer :: MockServer -> IO ()-stopMockServer (MockServer rootThreadMap) = killThreadHierarchy rootThreadMap--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", "<http://localhost:3000/2>; rel=\"next\"")], ress !! 1)-        dispatch "/2"   = ([contentType, ("Link", "<http://localhost:3000/3>; rel=\"next\"")], ress !! 2)-        dispatch "/3"   = ([contentType], ress !! 3)-        dispatch _      = ([contentType, ("Link", "<http://localhost:3000/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", "<http://localhost:8888/2>; rel=\"next\"")], ress !! 1)-        dispatch "/2"   = ([contentType, ("Link", "<http://localhost:3000/3>; rel=\"next\"")], ress !! 2)-        dispatch "/3"   = ([contentType], ress !! 3)-        dispatch _      = ([contentType, ("Link", "<http://localhost:3000/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'] ]--spec :: Spec-spec = do-    describe "Mock Applications" $ do-        it "simple mock app returns list of team" $ do-            receivedReqMVar <- newEmptyMVar-            let (CiscoSparkRequest baseReq _ _) = mockBaseRequest-                req = setRequestPath "/v1/teams"-                    $ setRequestMethod "GET"-                    $ baseReq-                testData = TeamList $ teamList ['Z']--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode testData) req respond--            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"--            stopMockServer svr--        it "pagenation mock app returns list of team and Link header" $ do-            receivedReqMVar <- newEmptyMVar-            let (CiscoSparkRequest baseReq _ _) = mockBaseRequest-                req = setRequestPath "/v1/teams"-                    $ setRequestMethod "GET"-                    $ baseReq-                testData = encode . TeamList <$> teamListList--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                paginationApp testData req respond--            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://localhost:3000/1"--            req2 <- parseRequest $ "GET " <> C8.unpack (fromJust path)-            res2 <- httpJSON req2-            getResponseBody res2 `shouldBe` TeamList (teamListList !! 1)--            stopMockServer svr--    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 "streamPersonList streams Team" $ do-            let testData = personList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (PersonList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/people"-            queryString receivedReq `shouldBe` []--            stopMockServer svr--        it "streamPersonList 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--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (PersonList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest personFilter .| sinkList-            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") ]--            stopMockServer svr--        it "streamPersonList streams Team with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . PersonList <$> personListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) .| sinkList-            res `shouldBe` concat personListList--            stopMockServer svr--        it "streamPersonList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . PersonList <$> personListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) .| sinkList-            res `shouldBe` concat (take 2 personListList)--            stopMockServer svr--        it "getDetail for a person returns a Person" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp personJson1 req respond--            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"--            stopMockServer svr--        it "getDetailEither for a person returns a (Right Person)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp personJson1 req respond--            (Right resPerson) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (PersonId "testPersonId")-            resPerson `shouldBe` person1--            stopMockServer svr--        it "createEntity for a person sends JSON encoded CreatePerson as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp personJson1 req respond--            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--            stopMockServer svr--        it "createEntityEither for a person sends JSON encoded CreatePerson as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp personJson1 req respond--            (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--            stopMockServer svr--        it "updateEntity for a person sends JSON encoded UpdatePerson as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp personJson1 req respond--            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--            stopMockServer svr--        it "updateEntityEither for a person sends JSON encoded UpdatePerson as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp personJson1 req respond--            (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--            stopMockServer svr--    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 "streamTeamList streams Team" $ do-            let testData = teamList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (TeamList testData)) req respond--            res <- runConduit $ streamTeamList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` testData-            path <- rawPathInfo <$> takeMVar receivedReqMVar-            path `shouldBe` "/v1/teams"--            stopMockServer svr--        it "streamTeamList streams Team with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . TeamList <$> teamListList--            res <- runConduit $ streamTeamList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` concat teamListList--            stopMockServer svr--        it "streamTeamList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . TeamList <$> teamListList--            res <- runConduit $ streamTeamList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` concat (take 2 teamListList)--            stopMockServer svr--        it "getDetail for a team returns a Team" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp teamJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a team returns a (Right Team)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp teamJson req respond-            (Right resTeam) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (TeamId "testTeamId")-            resTeam `shouldBe` team--            stopMockServer svr--        it "createEntity for a team sends JSON encoded CreateTeam as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamJson req respond--            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--            stopMockServer svr--        it "createEntityEither for a team sends JSON encoded CreateTeam as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamJson req respond--            (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--            stopMockServer svr--        it "updateEntity for a team sends JSON encoded UpdateTeam as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamJson req respond--            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--            stopMockServer svr--        it "updateEntityEither for a team sends JSON encoded UpdateTeam as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamJson req respond--            (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--            stopMockServer svr--        it "deleteTeam sends DELETE request with teamId on URL path" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp "" req respond--            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"--            stopMockServer svr--    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 "streamTeamMembershipList streams TeamMembership" $ do-            let testData = teamMembershipList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (TeamMembershipList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/team/memberships"-            queryString receivedReq `shouldBe` [ ("teamId", Just "dummyTeamId") ]--            stopMockServer svr--        it "streamMembershipList passes query strings build from TeamMembershipFilter to server" $ do-            let testData = teamMembershipList ['Z']-                teamMembershipFilter = TeamMembershipFilter $ TeamId "DummyTeamId"--            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (TeamMembershipList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest teamMembershipFilter .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/team/memberships"-            queryString receivedReq `shouldBe` [ ("teamId", Just "DummyTeamId") ]--            stopMockServer svr--        it "streamTeamMembershipList streams TeamMembership with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . TeamMembershipList <$> teamMembershipListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList-            res `shouldBe` concat teamMembershipListList--            stopMockServer svr--        it "streamTeamMembershipList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . TeamMembershipList <$> teamMembershipListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList-            res `shouldBe` concat (take 2 teamMembershipListList)--            stopMockServer svr--        it "getDetail for a team membership returns a TeamMembership" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp teamMembershipJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a team membership  returns a (Right TeamMembership)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp teamMembershipJson req respond-            (Right resTeamMembership) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (TeamMembershipId "testTeamMembershipId")-            resTeamMembership `shouldBe` teamMembership--            stopMockServer svr--        it "createEntity for a team membership sends JSON encoded CreateTeamMembership as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamMembershipJson req respond--            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--            stopMockServer svr--        it "createEntityEither for a team membership sends JSON encoded CreateTeamMembership as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamMembershipJson req respond--            (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--            stopMockServer svr--        it "updateEntity for a teamMembership sends JSON encoded UpdateTeamMembership as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamMembershipJson req respond--            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--            stopMockServer svr--        it "updateEntityEither for a teamMembership sends JSON encoded UpdateTeamMembership as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp teamMembershipJson req respond--            (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--            stopMockServer svr--        it "deleteTeamMembership sends DELETE request with teamMembershipId on URL path" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp "" req respond--            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"--            stopMockServer svr--    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 "streamRoomList streams Room" $ do-            let testData = roomList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (RoomList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/rooms"-            queryString receivedReq `shouldBe` []--            stopMockServer svr--        it "streamRoomList passes query strings build from RoomFilter to server" $ do-            let testData = roomList ['Z']-                roomFilter = RoomFilter (Just $ TeamId "dummyTeamId")-                                        (Just RoomTypeGroup)-                                        (Just RoomFilterSortByLastActivity)--            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (RoomList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest roomFilter .| sinkList-            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") ]--            stopMockServer svr--        it "streamRoomList streams Room with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . RoomList <$> roomListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) .| sinkList-            res `shouldBe` concat roomListList--            stopMockServer svr--        it "streamRoomList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . RoomList <$> roomListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) .| sinkList-            res `shouldBe` concat (take 2 roomListList)--            stopMockServer svr--        it "getDetail for a room returns a Room" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp roomJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a room returns a (Right Room)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp roomJson req respond-            (Right resRoom) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (RoomId "testRoomId")-            resRoom `shouldBe` room--            stopMockServer svr--        it "createEntity for a room sends JSON encoded CreateRoom as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp roomJson req respond--            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--            stopMockServer svr--        it "createEntithEither for a room sends JSON encoded CreateRoom as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp roomJson req respond--            (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--            stopMockServer svr--        it "updateEntity for a room sends JSON encoded UpdateRoom as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp roomJson req respond--            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--            stopMockServer svr--        it "updateEntityEither for a room sends JSON encoded UpdateRoom as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp roomJson req respond--            (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--            stopMockServer svr--        it "deleteRoom sends DELETE request with roomId on URL path" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp "" req respond--            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"--            stopMockServer svr--    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 "streamMembershipList streams Membership" $ do-            let testData = membershipList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (MembershipList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/memberships"-            queryString receivedReq `shouldBe` []--            stopMockServer svr--        it "streamMembershipList 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--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (MembershipList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest membershipFilter .| sinkList-            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") ]--            stopMockServer svr--        it "streamMembershipList streams Membership with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . MembershipList <$> membershipListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) .| sinkList-            res `shouldBe` concat membershipListList--            stopMockServer svr--        it "streamMembershipList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . MembershipList <$> membershipListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) .| sinkList-            res `shouldBe` concat (take 2 membershipListList)--            stopMockServer svr--        it "getDetail for a menbership returns a Membership" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp membershipJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a membership returns a (Right Membership)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp membershipJson req respond-            (Right resMembership) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (MembershipId "testMembershipId")-            resMembership `shouldBe` membership--            stopMockServer svr--        it "createEntity for a membership sends JSON encoded CreateMembership as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp membershipJson req respond--            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--            stopMockServer svr--        it "createEntithEither for a membership sends JSON encoded CreateMembership as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp membershipJson req respond--            (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--            stopMockServer svr--        it "updateEntity for a membership sends JSON encoded UpdateMembership as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp membershipJson req respond--            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--            stopMockServer svr--        it "updateEntityEither for a membership sends JSON encoded UpdateMembership as its body of PUT request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp membershipJson req respond--            (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--            stopMockServer svr--        it "deleteMembership sends DELETE request with membershipId on URL path" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp "" req respond--            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"--            stopMockServer svr--    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\" : \"<h1>HTML formatted message goes here</h1><p>when the message was posted in markdown format.</p>\",\-                          \  \"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 "<h1>HTML formatted message goes here</h1><p>when the message was posted in markdown format.</p>"-                              , 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 "streamMessageList streams Message" $ do-            let testData = messageList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (MessageList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/messages"-            queryString receivedReq `shouldBe` [ ("roomId", Just "dummyRoomId") ]--            stopMockServer svr--        it "streamMessageList 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--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (MessageList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest messageFilter .| sinkList-            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") ]--            stopMockServer svr--        it "streamMessageList streams Message with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . MessageList <$> messageListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList-            res `shouldBe` concat messageListList--            stopMockServer svr--        it "streamMessageList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . MessageList <$> messageListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList-            res `shouldBe` concat (take 2 messageListList)--            stopMockServer svr--        it "getDetail for a message returns a Message" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp messageJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a message returns a (Right Message)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp messageJson req respond-            (Right resMessage) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (MessageId "testMessageId")-            resMessage `shouldBe` message--            stopMockServer svr--        it "createEntity for a message sends JSON encoded CreateMessage as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp messageJson req respond--            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--            stopMockServer svr--        it "createEntithEither for a message sends JSON encoded CreateMessage as its body of POST request" $ do-            receivedReqMVar <- newEmptyMVar-            receivedBodyMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                strictRequestBody req >>= putMVar receivedBodyMVar-                simpleApp messageJson req respond--            (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--            stopMockServer svr--        it "deleteMessage sends DELETE request with messageId on URL path" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp "" req respond--            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"--            stopMockServer svr--    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 "streamOrganizationList streams Organization" $ do-            let testData = organizationList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (OrganizationList testData)) req respond--            res <- runConduit $ streamOrganizationList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/organizations"-            queryString receivedReq `shouldBe` []--            stopMockServer svr--        it "streamOrganizationList streams Organization with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . OrganizationList <$> organizationListList--            res <- runConduit $ streamOrganizationList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` concat organizationListList--            stopMockServer svr--        it "streamOrganizationList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . OrganizationList <$> organizationListList--            res <- runConduit $ streamOrganizationList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` concat (take 2 organizationListList)--            stopMockServer svr--        it "getDetail for an organization returns a Organization" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp organizationJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for an organization returns a (Right Organization)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp organizationJson req respond-            (Right resOrganization) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (OrganizationId "testOrganizationId")-            resOrganization `shouldBe` organization--            stopMockServer svr--    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 "streamLicenseList streams License" $ do-            let testData = licenseList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (LicenseList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/licenses"-            queryString receivedReq `shouldBe` []--            stopMockServer svr--        it "streamLicenseList passes query strings build from LicenseFilter to server" $ do-            let testData = licenseList ['Z']-                licenseFilter = LicenseFilter (Just $ OrganizationId "orgIdFilter")--            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (LicenseList testData)) req respond--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest licenseFilter .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/licenses"-            queryString receivedReq `shouldBe` [ ("orgId", Just "orgIdFilter") ]--            stopMockServer svr--        it "streamLicenseList streams License with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . LicenseList <$> licenseListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) .| sinkList-            res `shouldBe` concat licenseListList--            stopMockServer svr--        it "streamLicenseList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . LicenseList <$> licenseListList--            res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) .| sinkList-            res `shouldBe` concat (take 2 licenseListList)--            stopMockServer svr--        it "getDetail for a license returns a License" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp licenseJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a license returns a (Right License)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp licenseJson req respond-            (Right resLicense) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (LicenseId "testLicenseId")-            resLicense `shouldBe` license--            stopMockServer svr--    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 "streamRoleList streams Role" $ do-            let testData = roleList ['Z']-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp (encode (RoleList testData)) req respond--            res <- runConduit $ streamRoleList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` testData--            receivedReq <- takeMVar receivedReqMVar-            rawPathInfo receivedReq `shouldBe` "/v1/roles"-            queryString receivedReq `shouldBe` []--            stopMockServer svr--        it "streamRoleList streams Role with automatic pagination" $ do-            svr <- startMockServer . paginationApp $ encode . RoleList <$> roleListList--            res <- runConduit $ streamRoleList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` concat roleListList--            stopMockServer svr--        it "streamRoleList stops pagination at invalid Link Header" $ do-            svr <- startMockServer . invalidPaginationApp $ encode . RoleList <$> roleListList--            res <- runConduit $ streamRoleList dummyAuth mockBaseRequest .| sinkList-            res `shouldBe` concat (take 2 roleListList)--            stopMockServer svr--        it "getDetail for a role returns a Role" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp roleJson req respond--            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"--            stopMockServer svr--        it "getDetailEither for a role returns a (Right Role)" $ do-            receivedReqMVar <- newEmptyMVar--            svr <- startMockServer $ \req respond -> do-                putMVar receivedReqMVar req-                simpleApp roleJson req respond-            (Right resRole) <- getResponseBody <$> getDetailEither dummyAuth mockBaseRequest (RoleId "testRoleId")-            resRole `shouldBe` role--            stopMockServer svr+{-# LANGUAGE OverloadedStrings #-}++module Network.CiscoSparkSpec where++import           Conduit+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 (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++import           Network.HTTP.Types           (Header, status200)+import           Network.URI                  (URIAuth (..))+import           Network.Wai+import           Network.Wai.Handler.Warp     (Settings, defaultSettings,+                                               runSettings, setBeforeMainLoop)++import           Test.Hspec++import           Network.CiscoSpark+import           Network.CiscoSpark.Internal  (LinkHeader (..), LinkParam (..),+                                               getNextUrl, linkHeader)+++import           Data.Typeable                (typeOf)+++mockBaseRequestRequest+    = C.addRequestHeader "Content-Type" "application/json; charset=utf-8"+    $ C.setRequestPort 3000+    $ C.setRequestHost "127.0.0.1"+    $ C.setRequestSecure False+    $ C.defaultRequest++mockBaseRequest :: CiscoSparkRequest+mockBaseRequest = CiscoSparkRequest mockBaseRequestRequest "http:" $ URIAuth "" "127.0.0.1" ":3000"++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 ()) 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", "<http://127.0.0.1:3000/2>; rel=\"next\"")], ress !! 1)+        dispatch "/2"   = ([contentType, ("Link", "<http://127.0.0.1:3000/3>; rel=\"next\"")], ress !! 2)+        dispatch "/3"   = ([contentType], ress !! 3)+        dispatch _      = ([contentType, ("Link", "<http://127.0.0.1:3000/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", "<http://127.0.0.1:8888/2>; rel=\"next\"")], ress !! 1)+        dispatch "/2"   = ([contentType, ("Link", "<http://127.0.0.1:3000/3>; rel=\"next\"")], ress !! 2)+        dispatch "/3"   = ([contentType], ress !! 3)+        dispatch _      = ([contentType, ("Link", "<http://127.0.0.1:3000/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'] ]++spec :: Spec+spec = do+    describe "Mock Applications" $ do+        it "simple mock app returns list of team" $ do+            receivedReqMVar <- newEmptyMVar+            let (CiscoSparkRequest 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 (CiscoSparkRequest 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:3000/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 "streamPersonList streams Team" $ do+            let testData = personList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (PersonList testData)) req respond+                ) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/people"+                queryString receivedReq `shouldBe` []++        it "streamPersonList 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 <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest personFilter .| sinkList+                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 "streamPersonList streams Team with automatic pagination" $ do+            withMockServer (paginationApp $ encode . PersonList <$> personListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) .| sinkList+                res `shouldBe` concat personListList++        it "streamPersonList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . PersonList <$> personListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: PersonFilter) .| sinkList+                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 "streamTeamList streams Team" $ do+            let testData = teamList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (TeamList testData)) req respond+                ) $ do+                res <- runConduit $ streamTeamList dummyAuth mockBaseRequest .| sinkList+                res `shouldBe` testData+                path <- rawPathInfo <$> takeMVar receivedReqMVar+                path `shouldBe` "/v1/teams"++        it "streamTeamList streams Team with automatic pagination" $ do+            withMockServer (paginationApp $ encode . TeamList <$> teamListList) $ do+                res <- runConduit $ streamTeamList dummyAuth mockBaseRequest .| sinkList+                res `shouldBe` concat teamListList++        it "streamTeamList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . TeamList <$> teamListList) $ do+                res <- runConduit $ streamTeamList dummyAuth mockBaseRequest .| sinkList+                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 "streamTeamMembershipList streams TeamMembership" $ do+            let testData = teamMembershipList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (TeamMembershipList testData)) req respond+                ) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/team/memberships"+                queryString receivedReq `shouldBe` [ ("teamId", Just "dummyTeamId") ]++        it "streamMembershipList 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 <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest teamMembershipFilter .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/team/memberships"+                queryString receivedReq `shouldBe` [ ("teamId", Just "DummyTeamId") ]++        it "streamTeamMembershipList streams TeamMembership with automatic pagination" $ do+            withMockServer (paginationApp $ encode . TeamMembershipList <$> teamMembershipListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList+                res `shouldBe` concat teamMembershipListList++        it "streamTeamMembershipList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . TeamMembershipList <$> teamMembershipListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList+                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 "streamRoomList streams Room" $ do+            let testData = roomList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (RoomList testData)) req respond+                ) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/rooms"+                queryString receivedReq `shouldBe` []++        it "streamRoomList 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 <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest roomFilter .| sinkList+                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 "streamRoomList streams Room with automatic pagination" $ do+            withMockServer (paginationApp $ encode . RoomList <$> roomListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) .| sinkList+                res `shouldBe` concat roomListList++        it "streamRoomList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . RoomList <$> roomListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: RoomFilter) .| sinkList+                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 "streamMembershipList streams Membership" $ do+            let testData = membershipList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (MembershipList testData)) req respond+                ) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/memberships"+                queryString receivedReq `shouldBe` []++        it "streamMembershipList 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 <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest membershipFilter .| sinkList+                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 "streamMembershipList streams Membership with automatic pagination" $ do+            withMockServer (paginationApp $ encode . MembershipList <$> membershipListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) .| sinkList+                res `shouldBe` concat membershipListList++        it "streamMembershipList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . MembershipList <$> membershipListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: MembershipFilter) .| sinkList+                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\" : \"<h1>HTML formatted message goes here</h1><p>when the message was posted in markdown format.</p>\",\+                          \  \"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 "<h1>HTML formatted message goes here</h1><p>when the message was posted in markdown format.</p>"+                              , 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 "streamMessageList streams Message" $ do+            let testData = messageList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (MessageList testData)) req respond+                ) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/messages"+                queryString receivedReq `shouldBe` [ ("roomId", Just "dummyRoomId") ]++        it "streamMessageList 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 <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest messageFilter .| sinkList+                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 "streamMessageList streams Message with automatic pagination" $ do+            withMockServer (paginationApp $ encode . MessageList <$> messageListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList+                res `shouldBe` concat messageListList++        it "streamMessageList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . MessageList <$> messageListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest defFilter .| sinkList+                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 "streamOrganizationList streams Organization" $ do+            let testData = organizationList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (OrganizationList testData)) req respond+                ) $ do+                res <- runConduit $ streamOrganizationList dummyAuth mockBaseRequest .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/organizations"+                queryString receivedReq `shouldBe` []++        it "streamOrganizationList streams Organization with automatic pagination" $ do+            withMockServer (paginationApp $ encode . OrganizationList <$> organizationListList) $ do+                res <- runConduit $ streamOrganizationList dummyAuth mockBaseRequest .| sinkList+                res `shouldBe` concat organizationListList++        it "streamOrganizationList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . OrganizationList <$> organizationListList) $ do+                res <- runConduit $ streamOrganizationList dummyAuth mockBaseRequest .| sinkList+                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 "streamLicenseList streams License" $ do+            let testData = licenseList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (LicenseList testData)) req respond+                ) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/licenses"+                queryString receivedReq `shouldBe` []++        it "streamLicenseList 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 <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest licenseFilter .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/licenses"+                queryString receivedReq `shouldBe` [ ("orgId", Just "orgIdFilter") ]++        it "streamLicenseList streams License with automatic pagination" $ do+            withMockServer (paginationApp $ encode . LicenseList <$> licenseListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) .| sinkList+                res `shouldBe` concat licenseListList++        it "streamLicenseList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . LicenseList <$> licenseListList) $ do+                res <- runConduit $ streamEntityWithFilter dummyAuth mockBaseRequest (def :: LicenseFilter) .| sinkList+                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 "streamRoleList streams Role" $ do+            let testData = roleList ['Z']+            receivedReqMVar <- newEmptyMVar++            withMockServer (\req respond -> do+                    putMVar receivedReqMVar req+                    simpleApp (encode (RoleList testData)) req respond+                ) $ do+                res <- runConduit $ streamRoleList dummyAuth mockBaseRequest .| sinkList+                res `shouldBe` testData++                receivedReq <- takeMVar receivedReqMVar+                rawPathInfo receivedReq `shouldBe` "/v1/roles"+                queryString receivedReq `shouldBe` []++        it "streamRoleList streams Role with automatic pagination" $ do+            withMockServer (paginationApp $ encode . RoleList <$> roleListList) $ do+                res <- runConduit $ streamRoleList dummyAuth mockBaseRequest .| sinkList+                res `shouldBe` concat roleListList++        it "streamRoleList stops pagination at invalid Link Header" $ do+            withMockServer (invalidPaginationApp $ encode . RoleList <$> roleListList) $ do+                res <- runConduit $ streamRoleList dummyAuth mockBaseRequest .| sinkList+                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