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