packages feed

etcd-1.0.5: test/Test.hs

{-# LANGUAGE OverloadedStrings #-}

module Main where

import           Test.Hspec

import           Data.Char
import           Data.Maybe
import           Data.Text (Text)
import qualified Data.Text as T
import           Data.Monoid

import           Control.Applicative
import           Control.Concurrent
import qualified Control.Concurrent.Async as Async
import           Control.Monad
import           Control.Monad.Random (getRandomR, evalRandIO)
import           Control.Monad.Trans

import           Network.Etcd


main :: IO ()
main = hspec spec


randomKey :: IO Text
randomKey = do
    rnd <- evalRandIO (sequence $ repeat $ getRandomR (0, 61))
    return $ T.pack $ take 13 $ map alnum rnd
  where
    alnum :: Int -> Char
    alnum x
        | x < 26    = chr ((x     ) + 65)
        | x < 52    = chr ((x - 26) + 97)
        | x < 62    = chr ((x - 52) + 48)
        | otherwise = error $ "Out of range: " ++ show x


setup :: IO (Client, Text)
setup = do
    client <- createClient [ "http://127.0.0.1:4001" ]
    key    <- randomKey

    return (client, key)


expectNode :: Maybe Node -> IO Node
expectNode = maybe (error "Expected Node") return

shouldBeLeaf :: Node -> Value -> Expectation
shouldBeLeaf node value = _nodeValue node `shouldBe` (Just value)

shouldBeDirectory :: Node -> Expectation
shouldBeDirectory node = _nodeDir node `shouldBe` True


spec :: Spec
spec = parallel $ do

    describe "Key Space Operations" $ do
        it "Get the root directory node" $ do
            (client, key) <- setup
            node <- expectNode =<< get client "/"
            shouldBeDirectory node

        it "Setting the value of a key" $ do
            (client, key) <- setup
            node <- expectNode =<< set client key "value" Nothing
            node `shouldBeLeaf` "value"

        it "Using key TTL" $ do
            (client, key) <- setup
            set client key "value" (Just 5)
            node <- expectNode =<< get client key
            node `shouldBeLeaf` "value"

            threadDelay $ 6 * 1000 * 1000
            node <- get client key
            node `shouldSatisfy` isNothing

        it "Changing the value of a key" $ do
            (client, key) <- setup
            set client key "value" Nothing
            node <- expectNode =<< set client key "value2" Nothing
            node `shouldBeLeaf` "value2"

        it "Get the value of a key" $ do
            (client, _) <- setup
            void $ fromJust <$> get client "/_etcd/machines"

        it "Wait for any change on a key" $ do
            (client, key) <- setup
            a <- Async.async $ wait client key
            threadDelay $ 2 * 1000 * 1000
            Async.async $ set client key "value" Nothing
            node <- expectNode =<< Async.wait a
            node `shouldBeLeaf` "value"

        it "Wait for a change on a key at a given index" $ do
            (client, key) <- setup
            Just n <- set client key "value" Nothing
            let i = _nodeModifiedIndex n
            node <- expectNode =<< waitIndex client key i
            node `shouldBeLeaf` "value"

        it "Wait for any change on a key recursively" $ do
            (client, key) <- setup
            a <- Async.async $ waitRecursive client key
            threadDelay $ 2 * 1000 * 1000
            Async.async $ set client (key <> "/child") "value" Nothing
            node <- expectNode =<< Async.wait a
            node `shouldBeLeaf` "value"

        it "Wait for a change on a key at a given index recursively" $ do
            (client, key) <- setup
            Just n <- set client (key <> "/child") "value" Nothing
            let i = _nodeModifiedIndex n
            node <- expectNode =<< waitIndexRecursive client key i
            node `shouldBeLeaf` "value"

        it "Creating directories" $ do
            (client, key) <- setup
            createDirectory client key Nothing
            node <- expectNode =<< get client key
            shouldBeDirectory node

        it "Deleting a directory" $ do
            (client, key) <- setup
            createDirectory client key Nothing
            removeDirectory client key

        it "Listing a directory" $ do
            (client, key) <- setup
            createDirectory client key Nothing
            set client (key <> "/one") "value" Nothing
            nodes <- listDirectoryContents client key
            length nodes `shouldBe` 1
            _nodeValue (head nodes) `shouldBe` (Just "value")

        it "Listing a directory recursively" $ do
            (client, key) <- setup
            createDirectory client key Nothing
            createDirectory client (key <> "/one") Nothing
            set client (key <> "/one/two") "value" Nothing
            set client (key <> "/one/three") "value" Nothing
            nodes <- listDirectoryContentsRecursive client key
            length nodes `shouldBe` 3
            _nodeValue (head nodes) `shouldBe` Nothing
            _nodeValue (last nodes) `shouldBe` (Just "value")

        it "Deleting a directory recursively" $ do
            (client, key) <- setup
            createDirectory client key Nothing
            set client (key <> "/one") "value" Nothing
            removeDirectoryRecursive client key

        it "Atomically Creating In-Order Keys" $ do
            (client, key) <- setup
            createDirectory client key Nothing
            node <- create client key "value" Nothing
            node `shouldBeLeaf` "value"

            nodes <- listDirectoryContents client key
            length nodes `shouldBe` 1
            _nodeValue (head nodes) `shouldBe` (Just "value")