bdcs-0.2.0: src/tests/BDCS/Export/FSTreeSpec.hs
-- Copyright (C) 2017 Red Hat, Inc.
--
-- This library is free software; you can redistribute it and/or
-- modify it under the terms of the GNU Lesser General Public
-- License as published by the Free Software Foundation; either
-- version 2.1 of the License, or (at your option) any later version.
--
-- This library is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- Lesser General Public License for more details.
--
-- You should have received a copy of the GNU Lesser General Public
-- License along with this library; if not, see <http://www.gnu.org/licenses/>.
{-# LANGUAGE OverloadedStrings #-}
module BDCS.Export.FSTreeSpec(spec)
where
import BDCS.DB(Files(..))
import BDCS.Export.FSTree
import Control.Monad.Except(runExceptT)
import Data.Bits((.|.))
import Data.Conduit((.|), runConduit)
import qualified Data.Conduit.List as CL
import Data.Either(isLeft)
import Data.Tree(Tree(..))
import System.Posix.Files(directoryMode, regularFileMode, symbolicLinkMode)
import Test.Hspec
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
spec :: Spec
spec = describe "Export.FSTree Tests" $ do
it "Adding a regular file to an empty tree" $
let file_a = regularTemplate{filesPath="/a"}
in addFiles [file_a] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Nothing) [
Node ("a", Just file_a) []
]
])
)
it "Adding directories before children" $
let dir_slash = directoryTemplate{filesPath="/"}
dir_a = directoryTemplate{filesPath="/a"}
file_b = regularTemplate{filesPath="/a/b"}
in addFiles [dir_slash, dir_a, file_b] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Just dir_slash) [
Node ("a", Just dir_a) [
Node ("b", Just file_b) []
]
]
])
)
it "Adding directories after children" $
let dir_slash = directoryTemplate{filesPath="/"}
dir_a = directoryTemplate{filesPath="/a"}
file_b = regularTemplate{filesPath="/a/b"}
in addFiles [file_b, dir_a, dir_slash] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Just dir_slash) [
Node ("a", Just dir_a) [
Node ("b", Just file_b) []
]
]
])
)
it "Replace a directory with a symlink" $
let bin_grep = regularTemplate{filesPath="/bin/grep"}
bin_link = symlinkTemplate{filesPath="/bin", filesTarget=Just "/usr/bin"}
in addFiles [bin_grep, bin_link] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Nothing) [
Node ("bin", Just bin_link) [],
Node ("usr", Nothing) [
Node ("bin", Nothing) [
Node ("grep", Just bin_grep) []
]
]
]
])
)
it "Add a file to a symlink path" $
let bin_grep = regularTemplate{filesPath="/bin/grep"}
bin_link = symlinkTemplate{filesPath="/bin", filesTarget=Just "/usr/bin"}
in addFiles [bin_link, bin_grep] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Nothing) [
Node ("bin", Just bin_link) [],
Node ("usr", Nothing) [
Node ("bin", Nothing) [
Node ("grep", Just bin_grep) []
]
]
]
])
)
it "Symlinks moving placeholders" $
let dir_a = directoryTemplate{filesPath="/a/b/c"}
dir_d = directoryTemplate{filesPath="/d/b"}
link = symlinkTemplate{filesPath="/a", filesTarget = Just "d"}
in addFiles [dir_a, dir_d, link] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Nothing) [
Node ("a", Just link) [],
Node ("d", Nothing) [
Node ("b", Just dir_d) [
Node ("c", Just dir_a) []
]
]
]
])
)
it "Symlink loop" $
let link_a = symlinkTemplate{filesPath="/a", filesTarget=Just "b"}
link_b = symlinkTemplate{filesPath="/b", filesTarget=Just "a"}
file = regularTemplate{filesPath="/b/c"}
in addFiles [link_a, link_b, file] >>= (`shouldSatisfy` isLeft)
it "Symlink with .." $
let link = symlinkTemplate{filesPath="/a/b", filesTarget=Just "../d"}
file = regularTemplate{filesPath="/a/b/c"}
in addFiles [link, file] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Nothing) [
Node ("a", Nothing) [
Node ("b", Just link) []
],
Node ("d", Nothing) [
Node ("c", Just file) []
]
]
])
)
it "Symlink with ." $
let link = symlinkTemplate{filesPath="/a/b", filesTarget=Just "./d"}
file = regularTemplate{filesPath="/a/b/c"}
in addFiles [link, file] >>= (`shouldBe` Right (
Node ("", Nothing) [
Node ("/", Nothing) [
Node ("a", Nothing) [
Node ("b", Just link) [],
Node ("d", Nothing) [
Node ("c", Just file) []
]
]
]
])
)
it "Symlink loop, different case" $
let link = symlinkTemplate{filesPath="/a", filesTarget=Just "."}
file = regularTemplate{filesPath="/a"}
in addFiles [link, file] >>= (`shouldSatisfy` isLeft)
where
-- Add a list of files and return the tree
addFiles :: Monad m => [Files] -> m (Either String FSTree)
addFiles files = runExceptT $ runConduit $ CL.sourceList files .| filesToTree
-- Just fill in the paths
regularTemplate :: Files
regularTemplate = Files "" "root" "root" 0 Nothing (fromIntegral $ regularFileMode .|. 0o644) 0 Nothing
directoryTemplate :: Files
directoryTemplate = Files "" "root" "root" 0 Nothing (fromIntegral $ directoryMode .|. 0o755) 0 Nothing
symlinkTemplate :: Files
symlinkTemplate = Files "" "root" "root" 0 Nothing (fromIntegral $ symbolicLinkMode .|. 0o644) 0 Nothing