packages feed

greskell-websocket-0.1.0.0: test/Network/Greskell/WebSocket/Codec/JSONSpec.hs

{-# LANGUAGE OverloadedStrings, DuplicateRecordFields, NoMonomorphismRestriction #-}
module Network.Greskell.WebSocket.Codec.JSONSpec (main,spec) where

import Control.Applicative ((<$>))
import Control.Monad (forM_)
import Data.Aeson (Value(Null, Number), (.=))
import qualified Data.Aeson as A
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import Data.Greskell.GraphSON
  ( GValue, GValueBody(..),
    nonTypedGValue, typedGValue'
  )
import Data.Greskell.Greskell (unsafeGreskell, Greskell)
import qualified Data.HashMap.Strict as HM
import Data.Maybe (fromJust)
import Data.Monoid (mempty, (<>))
import qualified Data.UUID as UUID
import qualified Data.Vector as V
import Test.Hspec

import Network.Greskell.WebSocket.Request
  ( RequestMessage(..), toRequestMessage
  )
import Network.Greskell.WebSocket.Request.Common (SASLMechanism(..), Operation, Base64(..))
import Network.Greskell.WebSocket.Request.Standard
  ( OpAuthentication(..), OpEval(..)
  )
import qualified Network.Greskell.WebSocket.Request.Session as S
import Network.Greskell.WebSocket.Response
  (ResponseMessage(..), ResponseStatus(..), ResponseResult(..), ResponseCode(..))
import Network.Greskell.WebSocket.Codec (Codec(..))
import Network.Greskell.WebSocket.Codec.JSON (jsonCodec)

main :: IO ()
main = hspec spec

spec :: Spec
spec = do
  decode_spec
  encode_spec

loadSample :: FilePath -> IO BSL.ByteString
loadSample filename = BSL.readFile ("test/samples/" ++ filename)

loadSampleValue :: FilePath -> IO Value
loadSampleValue filename = do
  json_text <- loadSample filename
  case A.eitherDecode' json_text of
   Left e -> error e
   Right v -> return v

uuidFromString :: String -> UUID.UUID
uuidFromString = fromJust . UUID.fromString

decode_spec :: Spec
decode_spec = describe "decodeWith" $ do
  describe "authentication challenge" $ do
    let codec :: Codec Value
        codec = jsonCodec
        exp_msg = ResponseMessage { requestId = uuidFromString "41d2e28a-20a4-4ab0-b379-d810dede3786",
                                    status = exp_status,
                                    result = exp_result
                                  }
        exp_status = ResponseStatus { code = Authenticate,
                                      message = "",
                                      attributes = mempty
                                    }
        exp_result = ResponseResult { resultData = Null,
                                      meta = mempty
                                    }
    forM_ ["v1", "v2", "v3"] $ \graphson_ver -> specify graphson_ver $ do
      got <- decodeWith codec <$> loadSample ("response_auth_" ++ graphson_ver ++ ".json")
      got `shouldBe` Right exp_msg

  describe "standard response" $ do
    let codec :: Codec GValue
        codec = jsonCodec
        expMsg d = ResponseMessage { requestId = uuidFromString "41d2e28a-20a4-4ab0-b379-d810dede3786",
                                     status = exp_status,
                                     result = expResult d
                                   }
        exp_status = ResponseStatus { code = Success,
                                      message = "",
                                      attributes = mempty
                                    }
        expResult d = ResponseResult { resultData = d,
                                       meta = mempty
                                     }
        exp_v1 = nonTypedGValue $ GArray $ V.fromList
                 [ nonTypedGValue $ GObject $ HM.fromList
                   [ ("id", nonTypedGValue $ GNumber 1),
                     ("label", nonTypedGValue $ GString "person"),
                     ("type", nonTypedGValue $ GString "vertex")
                   ] 
                 ]
        exp_typed_vertex = typedGValue' "g:Vertex" $ GObject $ HM.fromList
                           [ ("id", typedGValue' "g:Int32" $ GNumber 1),
                             ("label", nonTypedGValue $ GString "person")
                           ]
        exp_v2 = nonTypedGValue $ GArray $ V.fromList [exp_typed_vertex]
        exp_v3 = typedGValue' "g:List" $ GArray $ V.fromList [exp_typed_vertex]
        sampleFile v = "response_standard_" ++ v ++ ".json"
    specify "v1" $ do
      got <- decodeWith codec <$> loadSample (sampleFile "v1")
      got `shouldBe` Right (expMsg exp_v1)
    specify "v2" $ do
      got <- decodeWith codec <$> loadSample (sampleFile "v2")
      got `shouldBe` Right (expMsg exp_v2)
    specify "v3" $ do
      got <- decodeWith codec <$> loadSample (sampleFile "v3")
      got `shouldBe` Right (expMsg exp_v3)

encodedValue :: Codec s -> RequestMessage -> Value
encodedValue c req = case A.eitherDecode $ encodeWith c req of
  Left e -> error e
  Right v -> v

encodeCase :: String -> RequestMessage -> Spec
encodeCase filename input = specify filename $ do
  expected <- loadSampleValue filename
  encodedValue codec input `shouldBe` expected
  where
    codec :: Codec Value
    codec = jsonCodec

encode_spec :: Spec
encode_spec = describe "encodeWith" $ do
  encodeCase "request_auth_v1.json" $ toRequestMessage (uuidFromString "cb682578-9d92-4499-9ebc-5c6aa73c5397")
    $ OpAuthentication
      { batchSize = Nothing,
        sasl = Base64 (BS.singleton 0 <> "stephphen" <> BS.singleton 0 <> "password"),
        saslMechanism = SASLPlain
      }
  encodeCase "request_sessionless_eval_v1.json" $ toRequestMessage (uuidFromString "cb682578-9d92-4499-9ebc-5c6aa73c5397")
    $ OpEval
      { batchSize = Nothing,
        gremlin = "g.V(x)",
        bindings = Just $ HM.fromList [("x", Number 1)],
        language = Just "gremlin-groovy",
        aliases = Nothing,
        scriptEvaluationTimeout = Nothing
      }
  encodeCase "request_sessionless_eval_aliased_v1.json" $ toRequestMessage (uuidFromString "cb682578-9d92-4499-9ebc-5c6aa73c5397")
    $ OpEval
      { batchSize = Nothing,
        gremlin = "social.V(x)",
        bindings = Just $ HM.fromList [("x", Number 1)],
        language = Just "gremlin-groovy",
        aliases = Just $ HM.fromList [("g", "social")],
        scriptEvaluationTimeout = Nothing
      }
  encodeCase "request_session_eval_v1.json" $ toRequestMessage (uuidFromString "cb682578-9d92-4499-9ebc-5c6aa73c5397")
    $ S.OpEval
      { S.batchSize = Nothing,
        S.gremlin = "g.V(x)",
        S.bindings = Just $ HM.fromList [("x", Number 1)],
        S.language = Just "gremlin-groovy",
        S.aliases = Nothing,
        S.scriptEvaluationTimeout = Nothing,
        S.session = uuidFromString "41d2e28a-20a4-4ab0-b379-d810dede3786",
        S.manageTransaction = Nothing
      }
  encodeCase "request_session_eval_aliased_v1.json" $ toRequestMessage (uuidFromString "cb682578-9d92-4499-9ebc-5c6aa73c5397")
    $ S.OpEval
      { S.batchSize = Nothing,
        S.gremlin = "social.V(x)",
        S.bindings = Just $ HM.fromList [("x", Number 1)],
        S.language = Just "gremlin-groovy",
        S.aliases = Just $ HM.fromList [("g", "social")],
        S.scriptEvaluationTimeout = Nothing,
        S.session = uuidFromString "41d2e28a-20a4-4ab0-b379-d810dede3786",
        S.manageTransaction = Nothing
      }
  encodeCase "request_session_close_v1.json" $ toRequestMessage (uuidFromString "cb682578-9d92-4499-9ebc-5c6aa73c5397")
    $ S.OpClose
      { S.batchSize = Nothing,
        S.session = uuidFromString "41d2e28a-20a4-4ab0-b379-d810dede3786",
        S.force = Nothing
      }