rtnetlink-0.1.0.1: tests/Main.hs
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Control.Exception (bracket)
import Data.Functor ((<$>))
import System.Posix (getEffectiveUserID)
import System.Socket.Family.Inet (inetAddressFromTuple)
import System.Socket.Family.Inet6 (inet6AddressFromTuple)
import Test.Hspec
import System.Linux.RTNetlink
import System.Linux.RTNetlink.Link
import System.Linux.RTNetlink.Address
loopback :: LinkName
loopback = LinkName "lo"
testLink :: LinkName
testLink = LinkName "foobazblargle"
notALink :: LinkName
notALink = LinkName "notalink"
localhost4 :: InetAddress
localhost4 = inetAddressFromTuple (127,0,0,1)
localhost6 :: Inet6Address
localhost6 = inet6AddressFromTuple (0,0,0,0,0,0,0,1)
testAddress4 :: InetAddress
testAddress4 = inetAddressFromTuple (169,254,42,42)
testAddress6 :: Inet6Address
testAddress6 = inet6AddressFromTuple (0xfe80,42,42,42,42,42,42,42)
createTestInterface :: IO ()
createTestInterface = runRTNL $ do
create $ Bridge testLink
[LinkIndex n] <- dump testLink
let prefix4 = IfPrefix 24
prefix6 = IfPrefix 64
index = IfIndex n
create $ IfInetAddress testAddress4 prefix4 index
create $ IfInet6Address testAddress6 prefix6 index
withTestInterface :: IO a -> IO a
withTestInterface = bracket createTestInterface (const destroyTestLink) . const
createTestLink :: IO ()
createTestLink = runRTNL (create $ Bridge testLink)
destroyTestLink :: IO ()
destroyTestLink = runRTNL $ destroy testLink
withTestLink :: IO a -> IO a
withTestLink = bracket createTestLink (const destroyTestLink) . const
main :: IO ()
main = do
haveRoot <- (0 ==) <$> getEffectiveUserID
hspec $ do
describe "dump" testDump
describe "create" $
if haveRoot
then testCreate
else it "should create things" $ pendingWith "requires root"
describe "change" $
if haveRoot
then testChange
else it "should change things" $ pendingWith "requires root"
describe "destroy" $
if haveRoot
then testDestroy
else it "should destroy things" $ pendingWith "requires root"
testDump :: Spec
testDump = do
context "when operating on layer-2 links" $ do
it "gets link names" $ do
links <- runRTNL $ dump AnyLink
links `shouldSatisfy` elem loopback
it "gets link indices" $ do
runRTNL (dump loopback) `shouldReturn` [LinkIndex 1]
it "gets link states" $ do
runRTNL (dump loopback) `shouldReturn` [Up]
context "when given a non-existent link name" $ do
it "throws an exception" $ do
runRTNL (dump notALink :: RTNL [()]) `shouldThrow` anyIOException
context "when operating on layer-3 interfaces" $ do
it "gets link ethernet addresses" $ do
runRTNL (dump loopback) `shouldReturn` [LinkEther 0 0 0 0 0 0]
it "gets interface ipv4 addresses" $ do
addresses <- runRTNL $ dump AnyInterface
addresses `shouldSatisfy` elem localhost4
it "gets interface ipv6 addresses" $ do
addresses <- runRTNL $ dump AnyInterface
addresses `shouldSatisfy` elem localhost6
testCreate :: Spec
testCreate = do
context "when operating on layer-2 links" $ after_ destroyTestLink $ do
it "creates bridge links" $ do
links <- runRTNL $ do
create $ Bridge testLink
dump AnyLink
links `shouldSatisfy` elem testLink
it "creates dummy links" $ do
links <- runRTNL $ do
create $ Dummy testLink
dump AnyLink
links `shouldSatisfy` elem testLink
context "when operating on layer-3 interfaces" $ around_ withTestLink $ do
it "creates ipv4 addresses" $ do
addresses <- runRTNL $ do
[LinkIndex n] <- dump testLink
let prefix = IfPrefix 24
index = IfIndex n
interface = IfInetAddress testAddress4 prefix index
create interface
dump AnyInterface
addresses `shouldSatisfy` elem testAddress4
it "creates ipv6 addresses" $ do
addresses <- runRTNL $ do
[LinkIndex n] <- dump testLink
let prefix = IfPrefix 64
index = IfIndex n
interface = IfInet6Address testAddress6 prefix index
create interface
dump AnyInterface
addresses `shouldSatisfy` elem testAddress6
context "when given a bad interface index" $ do
it "throws an exception" $ do
indices <- runRTNL $ dump AnyInterface
let badIx = maximum indices + 1
prefix = IfPrefix 24
interface = IfInetAddress testAddress4 prefix badIx
runRTNL (create interface) `shouldThrow` anyIOException
context "when given a silly prefix" $ do
it "throws an exception" $ do
[LinkIndex n] <- runRTNL $ dump testLink
let index = IfIndex n
badPrefix = IfPrefix 42
interface = IfInetAddress testAddress4 badPrefix index
runRTNL (create interface) `shouldThrow` anyIOException
testChange :: Spec
testChange = do
context "when operating on layer-2 links" $ around_ withTestLink $ do
it "brings links up" $ do
[state] <- runRTNL $ do
change testLink Up
dump testLink
state `shouldBe` Up
it "brings links down" $ do
[state] <- runRTNL $ do
change testLink Up
change testLink Down
dump testLink
state `shouldBe` Down
context "when given a non-existent link name" $ do
it "throws an exception" $ do
runRTNL (change notALink Up) `shouldThrow` anyIOException
testDestroy :: Spec
testDestroy = do
context "when operating on layer-2 links" $ before_ createTestLink $ do
it "destroys links by name" $ do
links <- runRTNL $ do
destroy testLink
dump AnyLink
links `shouldSatisfy` not . elem testLink
it "destroys links by index" $ do
links <- runRTNL $ do
[LinkIndex n] <- dump testLink
destroy $ LinkIndex n
dump AnyLink
links `shouldSatisfy` not . elem testLink
context "when given a non-existent link name" $ after_ destroyTestLink $ do
it "throws an exception" $ do
runRTNL (destroy notALink) `shouldThrow` anyIOException
context "when operating on layer-3 interfaces" $ around_ withTestInterface $ do
it "destroys ipv4 addresses" $ do
addresses <- runRTNL $ do
[LinkIndex n] <- dump testLink
let prefix = IfPrefix 24
index = IfIndex n
interface = IfInetAddress testAddress4 prefix index
destroy interface
dump AnyInterface
addresses `shouldSatisfy` not . elem testAddress4
it "destroys ipv6 addresses" $ do
addresses <- runRTNL $ do
[LinkIndex n] <- dump testLink
let prefix = IfPrefix 64
index = IfIndex n
interface = IfInet6Address testAddress6 prefix index
destroy interface
dump AnyInterface
addresses `shouldSatisfy` not . elem testAddress6