Skip to content

Commit

Permalink
Issue #26: reorganize test modules for better decoupling
Browse files Browse the repository at this point in the history
  • Loading branch information
Marko Dimjašević committed Nov 25, 2019
1 parent 2b5c8c0 commit f182af2
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 108 deletions.
2 changes: 2 additions & 0 deletions fencer.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ test-suite test-fencer
Fencer.Logic.Test
Fencer.Types.Test
Fencer.Rules.Test
Fencer.Rules.Test.Helpers
Fencer.Rules.Test.Types
Fencer.Server.Test
default-language:
Haskell2010
Expand Down
108 changes: 4 additions & 104 deletions test/Fencer/Rules/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,24 @@
-- | Tests for "Fencer.Rules".
module Fencer.Rules.Test
( tests
, writeAndLoadRules
-- example values
, domain1Text
, domain2Text
, RuleFile(..)
, simpleRuleFile
) where

import BasePrelude

import Data.List (sortOn)
import Data.Text (Text)
import qualified Data.Text.IO as TIO
import qualified Data.Yaml as Yaml
import Named ((:!), arg)
import NeatInterpolation (text)
import qualified System.IO.Temp as Temp
import System.FilePath (takeDirectory, (</>))
import qualified System.Directory as Dir
import System.FilePath ((</>))
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (assertBool, assertEqual, Assertion, testCase)
import Test.Tasty.HUnit (testCase)

import Fencer.Rules
import Fencer.Rules.Test.Helpers (expectLoadRules)
import Fencer.Rules.Test.Types
import Fencer.Types


Expand Down Expand Up @@ -190,101 +185,6 @@ test_rulesLoadRulesReadPermissions =
("domain2" </> "config" </> "config.yml")
domain2Text

----------------------------------------------------------------------------
-- Helpers
----------------------------------------------------------------------------

-- | Get a list of values on the Left or an empty list if it is a
-- Right value.
toErrorList :: Either [a] [b] -> [a]
toErrorList (Right _) = []
toErrorList (Left xs) = xs

-- | A record useful in testing, which groups together a file path,
-- its contents and file permissions.
data RuleFile = MkRuleFile
{ -- | The path to the file
ruleFilePath :: FilePath
-- | The contents of the file in plain text
, ruleFileContents :: Text
-- | A function specifying how the file permissions should be
-- changed, i.e., what they should be once the file is written to
-- disk.
, ruleFileModifyPermissions :: Dir.Permissions -> Dir.Permissions
}

simpleRuleFile :: FilePath -> Text -> RuleFile
simpleRuleFile p c = MkRuleFile p c id

-- | Write contents to a path in the given root and modify file
-- permissions.
writeFile
:: "root" :! FilePath
-> "file" :! RuleFile
-> IO ()
writeFile
(arg #root -> root)
(arg #file -> file) = do

let
dir = takeDirectory (ruleFilePath file)
fullPath = root </> (ruleFilePath file)
Dir.createDirectoryIfMissing True (root </> dir)
TIO.writeFile fullPath (ruleFileContents file)
perms <- Dir.getPermissions fullPath
Dir.setPermissions fullPath (ruleFileModifyPermissions file perms)

-- | Write the content of files at the given root and load the files.
writeAndLoadRules
:: "ignoreDotFiles" :! Bool
-> "root" :! FilePath
-> "files" :! [RuleFile]
-> IO (Either [LoadRulesError] [DomainDefinition])
writeAndLoadRules
(arg #ignoreDotFiles -> ignoreDotFiles)
(arg #root -> root)
(arg #files -> files) = do

forM_ files $ \file -> Fencer.Rules.Test.writeFile
(#root root)
(#file file)
loadRulesFromDirectory
(#rootDirectory root)
(#subDirectory ".")
(#ignoreDotFiles ignoreDotFiles)

-- | Create given directory structure and check that
-- 'loadRulesFromDirectory' produces expected result such that file
-- permissions are configurable.
expectLoadRules
:: "ignoreDotFiles" :! Bool
-> "files" :! [RuleFile]
-> "result" :! Either [LoadRulesError] [DomainDefinition]
-> Assertion
expectLoadRules
(arg #ignoreDotFiles -> ignoreDotFiles)
(arg #files -> files)
(arg #result -> result) =
Temp.withSystemTempDirectory "fencer-config" $ \tempDir ->
writeAndLoadRules
(#ignoreDotFiles ignoreDotFiles)
(#root tempDir)
(#files files)
>>= \case
f@(Left _) ->
-- Paths to temporary files vary and there is not much point
-- in writing down exact expected exception messages so the
-- only assertion made is that the number of exceptions is the
-- same.
assertEqual
"unexpected failure"
(length . toErrorList $ result)
(length . toErrorList $ f)
Right definitions -> assertBool "unexpected definitions"
(((==) `on` show)
(sortOn domainDefinitionId <$> result)
(Right $ sortOn domainDefinitionId definitions))

----------------------------------------------------------------------------
-- Sample definitions
----------------------------------------------------------------------------
Expand Down
100 changes: 100 additions & 0 deletions test/Fencer/Rules/Test/Helpers.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedLabels #-}

-- | Module with helper functions used in rules and other testing.
module Fencer.Rules.Test.Helpers
( toErrorList
, writeContentsToFile
, writeAndLoadRules
, expectLoadRules
)
where

import BasePrelude

import qualified Data.Text.IO as TIO
import Named ((:!), arg)
import qualified System.Directory as Dir
import System.FilePath (FilePath, takeDirectory, (</>))
import qualified System.IO.Temp as Temp
import Test.Tasty.HUnit (assertBool, assertEqual, Assertion)

import Fencer.Rules (LoadRulesError(..), loadRulesFromDirectory)
import Fencer.Rules.Test.Types (RuleFile(..))
import Fencer.Types (DomainDefinition(..))

-- | Get a list of values on the Left or an empty list if it is a
-- Right value.
toErrorList :: Either [a] [b] -> [a]
toErrorList (Right _) = []
toErrorList (Left xs) = xs

-- | Write contents to a path in the given root and modify file
-- permissions.
writeContentsToFile
:: "root" :! FilePath
-> "file" :! RuleFile
-> IO ()
writeContentsToFile
(arg #root -> root)
(arg #file -> file) = do

let
dir = takeDirectory (ruleFilePath file)
fullPath = root </> (ruleFilePath file)
Dir.createDirectoryIfMissing True (root </> dir)
TIO.writeFile fullPath (ruleFileContents file)
perms <- Dir.getPermissions fullPath
Dir.setPermissions fullPath (ruleFileModifyPermissions file perms)

-- | Write the content of files at the given root and load the files.
writeAndLoadRules
:: "ignoreDotFiles" :! Bool
-> "root" :! FilePath
-> "files" :! [RuleFile]
-> IO (Either [LoadRulesError] [DomainDefinition])
writeAndLoadRules
(arg #ignoreDotFiles -> ignoreDotFiles)
(arg #root -> root)
(arg #files -> files) = do

forM_ files $ \file -> writeContentsToFile
(#root root)
(#file file)
loadRulesFromDirectory
(#rootDirectory root)
(#subDirectory ".")
(#ignoreDotFiles ignoreDotFiles)

-- | Create given directory structure and check that
-- 'loadRulesFromDirectory' produces expected result such that file
-- permissions are configurable.
expectLoadRules
:: "ignoreDotFiles" :! Bool
-> "files" :! [RuleFile]
-> "result" :! Either [LoadRulesError] [DomainDefinition]
-> Assertion
expectLoadRules
(arg #ignoreDotFiles -> ignoreDotFiles)
(arg #files -> files)
(arg #result -> result) =
Temp.withSystemTempDirectory "fencer-config" $ \tempDir ->
writeAndLoadRules
(#ignoreDotFiles ignoreDotFiles)
(#root tempDir)
(#files files)
>>= \case
f@(Left _) ->
-- Paths to temporary files vary and there is not much point
-- in writing down exact expected exception messages so the
-- only assertion made is that the number of exceptions is the
-- same.
assertEqual
"unexpected failure"
(length . toErrorList $ result)
(length . toErrorList $ f)
Right definitions -> assertBool "unexpected definitions"
(((==) `on` show)
(sortOn domainDefinitionId <$> result)
(Right $ sortOn domainDefinitionId definitions))

27 changes: 27 additions & 0 deletions test/Fencer/Rules/Test/Types.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-- | Types useful for rule testing.
module Fencer.Rules.Test.Types
( RuleFile(..)
, simpleRuleFile)
where

import BasePrelude

import Data.Text (Text)
import qualified System.Directory as Dir
import System.FilePath (FilePath)

-- | A record useful in testing, which groups together a file path,
-- its contents and file permissions.
data RuleFile = MkRuleFile
{ -- | The path to the file
ruleFilePath :: FilePath
-- | The contents of the file in plain text
, ruleFileContents :: Text
-- | A function specifying how the file permissions should be
-- changed, i.e., what they should be once the file is written to
-- disk.
, ruleFileModifyPermissions :: Dir.Permissions -> Dir.Permissions
}

simpleRuleFile :: FilePath -> Text -> RuleFile
simpleRuleFile p c = MkRuleFile p c id
10 changes: 6 additions & 4 deletions test/Fencer/Server/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import Fencer.Settings (defaultGRPCPort, getLogLevel, newLogger)
import Fencer.Types
import Fencer.Rules
import qualified Fencer.Rules.Test as RTest
import Fencer.Rules.Test.Helpers (writeAndLoadRules)
import Fencer.Rules.Test.Types (RuleFile(..), simpleRuleFile)
import qualified Fencer.Proto as Proto

{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
Expand Down Expand Up @@ -142,7 +144,7 @@ test_serverResponseReadPermissions =
testCase "OK response with one YAML file without read permissions" $
Temp.withSystemTempDirectory "fencer-config" $ \tempDir -> do
server <- serverIO
RTest.writeAndLoadRules
writeAndLoadRules
(#ignoreDotFiles False)
(#root tempDir)
(#files files)
Expand All @@ -158,13 +160,13 @@ test_serverResponseReadPermissions =
(expectedResponse, Grpc.StatusOk)
response
where
files :: [RTest.RuleFile]
files :: [RuleFile]
files =
[ RTest.MkRuleFile
[ MkRuleFile
("domain1" </> "config.yml")
RTest.domain1Text
(const Dir.emptyPermissions)
, RTest.simpleRuleFile
, simpleRuleFile
("domain2" </> "config" </> "config.yml")
RTest.domain2Text
]
Expand Down

0 comments on commit f182af2

Please sign in to comment.