packages feed

patrol-1.0.1.0: source/test-suite/Patrol/Type/EnvelopeSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Patrol.Type.EnvelopeSpec where

import qualified Data.Aeson as Aeson
import qualified Data.Aeson.KeyMap as KeyMap
import qualified Data.ByteString.Builder as Builder
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.Text.Encoding as Text
import qualified Network.HTTP.Client as Client
import qualified Network.HTTP.Types as Http
import qualified Patrol.Constant as Constant
import qualified Patrol.Extra.Aeson as Aeson
import qualified Patrol.Type.Dsn as Dsn
import qualified Patrol.Type.Envelope as Envelope
import qualified Patrol.Type.Event as Event
import qualified Patrol.Type.Headers as Headers
import qualified Patrol.Type.Item as Item
import qualified Patrol.Version as Version
import qualified Test.Hspec as Hspec

spec :: Hspec.Spec
spec = Hspec.describe "Patrol.Type.Envelope" $ do
  Hspec.describe "serialize" $ do
    Hspec.it "works with no items" $ do
      let actual =
            Builder.toLazyByteString $
              Envelope.serialize
                Envelope.Envelope
                  { Envelope.headers = Headers.empty,
                    Envelope.items = []
                  }
      actual `Hspec.shouldBe` "{}\n"

    Hspec.it "works with one item" $ do
      let actual =
            Builder.toLazyByteString $
              Envelope.serialize
                Envelope.Envelope
                  { Envelope.headers = Headers.fromObject . KeyMap.singleton "a" $ Aeson.toJSON False,
                    Envelope.items =
                      [ Item.Item
                          { Item.headers = Headers.fromObject . KeyMap.singleton "b" $ Aeson.toJSON True,
                            Item.payload = "c"
                          }
                      ]
                  }
      actual `Hspec.shouldBe` "{\"a\":false}\n{\"b\":true}\nc\n"

    Hspec.it "works with two items" $ do
      let actual =
            Builder.toLazyByteString $
              Envelope.serialize
                Envelope.Envelope
                  { Envelope.headers = Headers.fromObject . KeyMap.singleton "a" $ Aeson.toJSON (1 :: Int),
                    Envelope.items =
                      [ Item.Item
                          { Item.headers = Headers.fromObject . KeyMap.singleton "b" $ Aeson.toJSON (2 :: Int),
                            Item.payload = "c"
                          },
                        Item.Item
                          { Item.headers = Headers.fromObject . KeyMap.singleton "d" $ Aeson.toJSON (3 :: Int),
                            Item.payload = "e"
                          }
                      ]
                  }
      actual `Hspec.shouldBe` "{\"a\":1}\n{\"b\":2}\nc\n{\"d\":3}\ne\n"

  Hspec.describe "fromEvent" $ do
    Hspec.it "sets the header" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      event <- Event.fromException (const Nothing) $ userError ""
      let envelope = Envelope.fromEvent dsn event {Event.timestamp = Nothing}
      let expected =
            Headers.fromObject $
              KeyMap.fromList
                [ ("dsn", "http://key@sentry.test/1"),
                  ( "sdk",
                    Aeson.object
                      [ Aeson.pair "name" ("patrol" :: String),
                        Aeson.pair "version" Version.version
                      ]
                  )
                ]
      Envelope.headers envelope `Hspec.shouldBe` expected

    Hspec.it "sets the items" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      event <- Event.fromException (const Nothing) $ userError ""
      let envelope = Envelope.fromEvent dsn event
      Envelope.items envelope `Hspec.shouldNotSatisfy` null

  Hspec.describe "intoRequest" $ do
    Hspec.it "sets the method" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      Client.method request `Hspec.shouldBe` Http.methodPost

    Hspec.it "sets the host" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      Client.host request `Hspec.shouldBe` "sentry.test"

    Hspec.it "sets the port" $ do
      dsn <- Dsn.fromText "http://key@sentry.test:8080/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      Client.port request `Hspec.shouldBe` 8080

    Hspec.it "sets the path" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      Client.path request `Hspec.shouldBe` "/api/1/envelope/"

    Hspec.it "handles a custom path" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/custom/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      Client.path request `Hspec.shouldBe` "/custom/api/1/envelope/"

    Hspec.it "sets the body" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      actual <- case Client.requestBody request of
        Client.RequestBodyBS byteString -> pure byteString
        _ -> fail "unexpected request body"
      let expected = LazyByteString.toStrict . Builder.toLazyByteString $ Envelope.serialize envelope
      actual `Hspec.shouldBe` expected

    Hspec.it "sets the content type" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      lookup Http.hContentType (Client.requestHeaders request) `Hspec.shouldBe` Just Constant.applicationXSentryEnvelope

    Hspec.it "sets the user agent" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      lookup Http.hUserAgent (Client.requestHeaders request) `Hspec.shouldBe` Just (Text.encodeUtf8 Constant.userAgent)

    Hspec.it "sets the authorization" $ do
      dsn <- Dsn.fromText "http://key@sentry.test/1"
      envelope <- Envelope.fromException (const Nothing) dsn $ userError ""
      request <- Envelope.intoRequest dsn envelope
      lookup Constant.xSentryAuth (Client.requestHeaders request) `Hspec.shouldBe` Just (Dsn.intoAuthorization dsn)