1 {-| Unittests for ganeti-htools
7 Copyright (C) 2009 Google Inc.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 module Ganeti.HTools.QC
33 import Test.QuickCheck
34 import Test.QuickCheck.Batch
36 import qualified Ganeti.HTools.CLI as CLI
37 import qualified Ganeti.HTools.Cluster as Cluster
38 import qualified Ganeti.HTools.Container as Container
39 import qualified Ganeti.HTools.IAlloc as IAlloc
40 import qualified Ganeti.HTools.Instance as Instance
41 import qualified Ganeti.HTools.Loader as Loader
42 import qualified Ganeti.HTools.Node as Node
43 import qualified Ganeti.HTools.PeerMap as PeerMap
44 import qualified Ganeti.HTools.Rapi as Rapi
45 import qualified Ganeti.HTools.Text as Text
46 import qualified Ganeti.HTools.Types as Types
47 import qualified Ganeti.HTools.Utils as Utils
49 -- | Simple checker for whether OpResult is fail or pass
50 isFailure :: Types.OpResult a -> Bool
51 isFailure (Types.OpFail _) = True
54 -- copied from the introduction to quickcheck
55 instance Arbitrary Char where
56 arbitrary = choose ('\32', '\128')
58 -- let's generate a random instance
59 instance Arbitrary Instance.Instance where
68 return $ Instance.create name mem dsk vcpus run_st pn sn
71 instance Arbitrary Node.Node where
75 mem_f <- choose (0, mem_t)
76 mem_n <- choose (0, mem_t - mem_f)
78 dsk_f <- choose (0, dsk_t)
81 let n = Node.create name (fromIntegral mem_t) mem_n mem_f
82 (fromIntegral dsk_t) dsk_f cpu_t offl
83 n' = Node.buildPeers n Container.empty
86 -- | Make sure add is idempotent
87 prop_PeerMap_addIdempotent pmap key elem =
88 fn puniq == fn (fn puniq)
89 where _types = (pmap::PeerMap.PeerMap,
90 key::PeerMap.Key, elem::PeerMap.Elem)
91 fn = PeerMap.add key elem
92 puniq = PeerMap.accumArray const pmap
94 -- | Make sure remove is idempotent
95 prop_PeerMap_removeIdempotent pmap key =
96 fn puniq == fn (fn puniq)
97 where _types = (pmap::PeerMap.PeerMap, key::PeerMap.Key)
98 fn = PeerMap.remove key
99 puniq = PeerMap.accumArray const pmap
101 -- | Make sure a missing item returns 0
102 prop_PeerMap_findMissing pmap key =
103 PeerMap.find key (PeerMap.remove key puniq) == 0
104 where _types = (pmap::PeerMap.PeerMap, key::PeerMap.Key)
105 puniq = PeerMap.accumArray const pmap
107 -- | Make sure an added item is found
108 prop_PeerMap_addFind pmap key elem =
109 PeerMap.find key (PeerMap.add key elem puniq) == elem
110 where _types = (pmap::PeerMap.PeerMap,
111 key::PeerMap.Key, elem::PeerMap.Elem)
112 puniq = PeerMap.accumArray const pmap
114 -- | Manual check that maxElem returns the maximum indeed, or 0 for null
115 prop_PeerMap_maxElem pmap =
116 PeerMap.maxElem puniq == if null puniq then 0
117 else (maximum . snd . unzip) puniq
118 where _types = pmap::PeerMap.PeerMap
119 puniq = PeerMap.accumArray const pmap
122 [ run prop_PeerMap_addIdempotent
123 , run prop_PeerMap_removeIdempotent
124 , run prop_PeerMap_maxElem
125 , run prop_PeerMap_addFind
126 , run prop_PeerMap_findMissing
131 prop_Container_addTwo cdata i1 i2 =
132 fn i1 i2 cont == fn i2 i1 cont &&
133 fn i1 i2 cont == fn i1 i2 (fn i1 i2 cont)
134 where _types = (cdata::[Int],
136 cont = foldl (\c x -> Container.add x x c) Container.empty cdata
137 fn x1 x2 = Container.addTwo x1 x1 x2 x2
140 [ run prop_Container_addTwo ]
142 -- Simple instance tests, we only have setter/getters
144 prop_Instance_setIdx inst idx =
145 Instance.idx (Instance.setIdx inst idx) == idx
146 where _types = (inst::Instance.Instance, idx::Types.Idx)
148 prop_Instance_setName inst name =
149 Instance.name (Instance.setName inst name) == name
150 where _types = (inst::Instance.Instance, name::String)
152 prop_Instance_setPri inst pdx =
153 Instance.pnode (Instance.setPri inst pdx) == pdx
154 where _types = (inst::Instance.Instance, pdx::Types.Ndx)
156 prop_Instance_setSec inst sdx =
157 Instance.snode (Instance.setSec inst sdx) == sdx
158 where _types = (inst::Instance.Instance, sdx::Types.Ndx)
160 prop_Instance_setBoth inst pdx sdx =
161 Instance.pnode si == pdx && Instance.snode si == sdx
162 where _types = (inst::Instance.Instance, pdx::Types.Ndx, sdx::Types.Ndx)
163 si = Instance.setBoth inst pdx sdx
166 [ run prop_Instance_setIdx
167 , run prop_Instance_setName
168 , run prop_Instance_setPri
169 , run prop_Instance_setSec
170 , run prop_Instance_setBoth
175 -- | Check that an instance add with too high memory or disk will be rejected
176 prop_Node_addPri node inst = (Instance.mem inst >= Node.f_mem node ||
177 Instance.dsk inst >= Node.f_dsk node) &&
178 not (Node.failN1 node)
180 isFailure (Node.addPri node inst)
181 where _types = (node::Node.Node, inst::Instance.Instance)
184 -- | Check that an instance add with too high memory or disk will be rejected
185 prop_Node_addSec node inst pdx =
186 (Instance.mem inst >= (Node.f_mem node - Node.r_mem node) ||
187 Instance.dsk inst >= Node.f_dsk node) &&
188 not (Node.failN1 node)
189 ==> isFailure (Node.addSec node inst pdx)
190 where _types = (node::Node.Node, inst::Instance.Instance, pdx::Int)
193 [ run prop_Node_addPri
194 , run prop_Node_addSec