Statistics
| Branch: | Tag: | Revision:

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