1 {-# LANGUAGE TemplateHaskell, TypeSynonymInstances, FlexibleInstances #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 {-| Unittests for ganeti-htools.
10 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 module Test.Ganeti.Objects
35 import Test.QuickCheck
37 import Control.Applicative
38 import qualified Data.Map as Map
39 import qualified Data.Set as Set
41 import Test.Ganeti.Query.Language (genJSValue)
42 import Test.Ganeti.TestHelper
43 import Test.Ganeti.TestCommon
44 import Test.Ganeti.Types ()
46 import qualified Ganeti.Constants as C
47 import Ganeti.Objects as Objects
50 {-# ANN module "HLint: ignore Use camelCase" #-}
52 -- * Arbitrary instances
54 $(genArbitrary ''PartialNDParams)
56 instance Arbitrary Node where
57 arbitrary = Node <$> genFQDN <*> genFQDN <*> genFQDN
58 <*> arbitrary <*> arbitrary <*> arbitrary <*> genFQDN
59 <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
60 <*> arbitrary <*> arbitrary <*> genFQDN <*> arbitrary
61 <*> (Set.fromList <$> genTags)
63 $(genArbitrary ''BlockDriver)
65 $(genArbitrary ''DiskMode)
67 instance Arbitrary DiskLogicalId where
68 arbitrary = oneof [ LIDPlain <$> arbitrary <*> arbitrary
69 , LIDDrbd8 <$> genFQDN <*> genFQDN <*> arbitrary
70 <*> arbitrary <*> arbitrary <*> arbitrary
71 , LIDFile <$> arbitrary <*> arbitrary
72 , LIDBlockDev <$> arbitrary <*> arbitrary
73 , LIDRados <$> arbitrary <*> arbitrary
76 -- | 'Disk' 'arbitrary' instance. Since we don't test disk hierarchy
77 -- properties, we only generate disks with no children (FIXME), as
78 -- generating recursive datastructures is a bit more work.
79 instance Arbitrary Disk where
80 arbitrary = Disk <$> arbitrary <*> pure [] <*> arbitrary
81 <*> arbitrary <*> arbitrary
83 -- FIXME: we should generate proper values, >=0, etc., but this is
84 -- hard for partial ones, where all must be wrapped in a 'Maybe'
85 $(genArbitrary ''PartialBeParams)
87 $(genArbitrary ''AdminState)
89 $(genArbitrary ''PartialNicParams)
91 $(genArbitrary ''PartialNic)
93 instance Arbitrary Instance where
96 <$> genFQDN <*> genFQDN <*> genFQDN -- OS name, but...
98 -- FIXME: add non-empty hvparams when they're a proper type
99 <*> pure (GenericContainer Map.empty) <*> arbitrary
100 -- ... and for OSParams
101 <*> pure (GenericContainer Map.empty) <*> arbitrary <*> arbitrary
102 <*> arbitrary <*> arbitrary <*> arbitrary
104 <*> arbitrary <*> arbitrary
110 <*> (Set.fromList <$> genTags)
112 -- | FIXME: This generates completely random data, without normal
114 $(genArbitrary ''PartialISpecParams)
116 -- | FIXME: This generates completely random data, without normal
118 $(genArbitrary ''PartialIPolicy)
120 -- | FIXME: This generates completely random data, without normal
122 instance Arbitrary NodeGroup where
123 arbitrary = NodeGroup <$> genFQDN <*> pure [] <*> arbitrary <*> arbitrary
124 <*> arbitrary <*> pure (GenericContainer Map.empty)
126 <*> arbitrary <*> arbitrary
132 <*> (Set.fromList <$> genTags)
134 $(genArbitrary ''FilledISpecParams)
135 $(genArbitrary ''FilledIPolicy)
136 $(genArbitrary ''IpFamily)
137 $(genArbitrary ''FilledNDParams)
138 $(genArbitrary ''FilledNicParams)
139 $(genArbitrary ''FilledBeParams)
141 -- | No real arbitrary instance for 'ClusterHvParams' yet.
142 instance Arbitrary ClusterHvParams where
143 arbitrary = return $ GenericContainer Map.empty
145 -- | No real arbitrary instance for 'OsHvParams' yet.
146 instance Arbitrary OsHvParams where
147 arbitrary = return $ GenericContainer Map.empty
149 instance Arbitrary ClusterNicParams where
150 arbitrary = (GenericContainer . Map.singleton C.ppDefault) <$> arbitrary
152 instance Arbitrary OsParams where
153 arbitrary = (GenericContainer . Map.fromList) <$> arbitrary
155 instance Arbitrary ClusterOsParams where
156 arbitrary = (GenericContainer . Map.fromList) <$> arbitrary
158 instance Arbitrary ClusterBeParams where
159 arbitrary = (GenericContainer . Map.fromList) <$> arbitrary
161 instance Arbitrary TagSet where
162 arbitrary = Set.fromList <$> genTags
164 $(genArbitrary ''Cluster)
166 instance Arbitrary Network where
167 arbitrary = Network <$>
185 <*> genMaybe genJSValue
188 -- external reservations
193 <*> (Set.fromList <$> genTags)
195 -- | Generator for config data with an empty cluster (no instances),
196 -- with N defined nodes.
197 genEmptyCluster :: Int -> Gen ConfigData
198 genEmptyCluster ncount = do
199 nodes <- vector ncount
202 nodes' = zipWith (\n idx ->
203 let newname = nodeName n ++ "-" ++ show idx
204 in (newname, n { nodeGroup = guuid,
205 nodeName = newname}))
207 nodemap = Map.fromList nodes'
208 contnodes = if Map.size nodemap /= ncount
209 then error ("Inconsistent node map, duplicates in" ++
210 " node name list? Names: " ++
211 show (map fst nodes'))
212 else GenericContainer nodemap
213 continsts = GenericContainer Map.empty
215 let contgroups = GenericContainer $ Map.singleton guuid grp
217 cluster <- resize 8 arbitrary
218 let c = ConfigData version cluster contnodes contgroups continsts serial
223 -- | Tests that fillDict behaves correctly
224 prop_fillDict :: [(Int, Int)] -> [(Int, Int)] -> Property
225 prop_fillDict defaults custom =
226 let d_map = Map.fromList defaults
227 d_keys = map fst defaults
228 c_map = Map.fromList custom
229 c_keys = map fst custom
230 in conjoin [ printTestCase "Empty custom filling"
231 (fillDict d_map Map.empty [] == d_map)
232 , printTestCase "Empty defaults filling"
233 (fillDict Map.empty c_map [] == c_map)
234 , printTestCase "Delete all keys"
235 (fillDict d_map c_map (d_keys++c_keys) == Map.empty)
238 -- | Test that the serialisation of 'DiskLogicalId', which is
239 -- implemented manually, is idempotent. Since we don't have a
240 -- standalone JSON instance for DiskLogicalId (it's a data type that
241 -- expands over two fields in a JSObject), we test this by actially
242 -- testing entire Disk serialisations. So this tests two things at
244 prop_Disk_serialisation :: Disk -> Property
245 prop_Disk_serialisation = testSerialisation
247 -- | Check that node serialisation is idempotent.
248 prop_Node_serialisation :: Node -> Property
249 prop_Node_serialisation = testSerialisation
251 -- | Check that instance serialisation is idempotent.
252 prop_Inst_serialisation :: Instance -> Property
253 prop_Inst_serialisation = testSerialisation
255 -- | Check that network serialisation is idempotent.
256 prop_Network_serialisation :: Network -> Property
257 prop_Network_serialisation = testSerialisation
259 -- | Check config serialisation.
260 prop_Config_serialisation :: Property
261 prop_Config_serialisation =
262 forAll (choose (0, maxNodes `div` 4) >>= genEmptyCluster) testSerialisation
266 , 'prop_Disk_serialisation
267 , 'prop_Inst_serialisation
268 , 'prop_Network_serialisation
269 , 'prop_Node_serialisation
270 , 'prop_Config_serialisation