1 {-# LANGUAGE TemplateHaskell, TypeSynonymInstances, FlexibleInstances #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 module Test.Ganeti.Network
12 import Ganeti.Network as Network
13 import Ganeti.Objects as Objects
16 import Test.Ganeti.Query.Language (genJSValue)
17 import Test.Ganeti.TestHelper
18 import Test.Ganeti.TestCommon
20 import qualified Data.Vector.Bit as B
21 import qualified Data.Vector.Unboxed as V
22 import qualified Data.Set as S
24 -- * Generators and arbitrary instances
26 -- | Generate an arbitrary string consisting of '0' and '1' of the given length.
27 genBitString :: Int -> Gen String
28 genBitString len = vectorOf len (elements "01")
30 -- | Generate an arbitrary string consisting of '0' and '1' of the maximum given
32 genBitStringMaxLen :: Int -> Gen String
33 genBitStringMaxLen maxLen = choose (0, maxLen) >>= genBitString
35 -- | Generates an arbitrary bit vector of the given length.
36 genBitVector :: Int -> Gen B.BitVector
38 boolList <- vector len::Gen [Bool]
39 return $ V.fromList boolList
41 -- | Generates a network instance with bit vectors of the given lengths for
42 -- reservations and external reservations.
43 genValidNetwork :: Int -> Gen Objects.Network
44 genValidNetwork maxLenBitStr = do
45 lenBitStr <- choose (0, maxLenBitStr)
46 name <- genName >>= mkNonEmpty
47 network_type <- genMaybe genNetworkType
48 mac_prefix <- genMaybe genName
50 net <- genName >>= mkNonEmpty
51 net6 <- genMaybe genName
52 gateway <- genMaybe genName
53 gateway6 <- genMaybe genName
54 size <- genMaybe genJSValue
55 res <- liftM Just (genBitString lenBitStr)
56 ext_res <- liftM Just (genBitString lenBitStr)
57 let n = Network name network_type mac_prefix family net net6 gateway
58 gateway6 size res ext_res 0 S.empty
61 -- | Generates an arbitrary network type.
62 genNetworkType :: Gen NetworkType
63 genNetworkType = elements [ PrivateNetwork, PublicNetwork ]
65 -- | Network instances are generated arbitrarily only with short bit strings to
66 -- not slow down the test execution too much.
67 instance Arbitrary Objects.Network where
68 arbitrary = genValidNetwork 256
70 -- | Generates address pools. The size of the network is intentionally
71 -- decoupled from the size of the bit vectors, to avoid slowing down
72 -- the tests by generating unnecessary bit strings.
73 genAddressPool :: Int -> Gen AddressPool
74 genAddressPool maxLenBitVec = do
76 lenBitVec <- choose (0, maxLenBitVec)
77 res <- genBitVector lenBitVec
78 ext_res <- genBitVector lenBitVec
79 return AddressPool { network = net
81 , extReservations = ext_res }
83 instance Arbitrary AddressPool where
84 arbitrary = genAddressPool ((2::Int)^(8::Int))
88 -- | Check the mapping of bit strings to bit vectors
89 prop_bitStringToBitVector :: Property
90 prop_bitStringToBitVector =
91 forAll (genBitStringMaxLen 256) $ \bs ->
92 let bitList = V.toList $ Network.bitStringToBitVector bs
93 bitCharList = Prelude.zip bitList bs
94 in Prelude.all checkBit bitCharList
96 -- | Check whether an element of a bit vector is consistent with an element
97 -- of a bit string (containing '0' and '1' characters).
98 checkBit :: (Bool, Char) -> Bool
99 checkBit (False, '0') = True
100 checkBit (True, '1') = True
103 -- | Check creation of an address pool when a network is given.
104 prop_createAddressPool :: Objects.Network -> Property
105 prop_createAddressPool n =
106 let valid = networkIsValid n
107 in case createAddressPool n of
108 Just _ -> True ==? valid
109 Nothing -> False ==? valid
111 -- | Check that the address pool's properties are calculated correctly.
112 prop_addressPoolProperties :: AddressPool -> Property
113 prop_addressPoolProperties a =
116 ("Not all reservations are included in 'allReservations' of " ++
117 "address pool:" ++ show a) (allReservationsSubsumesInternal a)
119 ("Not all external reservations are covered by 'allReservations' " ++
120 "of address pool: " ++ show a)
121 (allReservationsSubsumesExternal a)
123 ("The counts of free and reserved addresses do not add up for " ++
124 "address pool: " ++ show a)
127 ("'isFull' wrongly classified the status of the address pool: " ++
128 show a) (checkIsFull a)
130 ("Network map is inconsistent with reservations of address pool: " ++
131 show a) (checkGetMap a)
134 -- | Check that all internally reserved ips are included in 'allReservations'.
135 allReservationsSubsumesInternal :: AddressPool -> Bool
136 allReservationsSubsumesInternal a =
137 bitVectorSubsumes (allReservations a) (reservations a)
139 -- | Check that all externally reserved ips are included in 'allReservations'.
140 allReservationsSubsumesExternal :: AddressPool -> Bool
141 allReservationsSubsumesExternal a =
142 bitVectorSubsumes (allReservations a) (extReservations a)
144 -- | Checks if one bit vector subsumes the other one.
145 bitVectorSubsumes :: B.BitVector -> B.BitVector -> Bool
146 bitVectorSubsumes v1 v2 = V.and $
147 V.zipWith (\a b -> if b then a else True) v1 v2
149 -- | Check that the counts of free and reserved ips add up.
150 checkCounts :: AddressPool -> Bool
152 let res = reservations a
153 in V.length res == getFreeCount a + getReservedCount a
155 -- | Check that the detection of a full network works correctly.
156 checkIsFull :: AddressPool -> Bool
157 checkIsFull a = isFull a == V.notElem False (allReservations a)
159 -- | Check that the map representation of the network corresponds to the
160 -- network's reservations.
161 checkGetMap :: AddressPool -> Bool
163 allReservations a == V.fromList (Prelude.map (== 'X') (getMap a))
166 [ 'prop_bitStringToBitVector
167 , 'prop_createAddressPool
168 , 'prop_addressPoolProperties