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 -- copied from the introduction to quickcheck
50 instance Arbitrary Char where
51 arbitrary = choose ('\32', '\128')
53 -- let's generate a random instance
54 instance Arbitrary Instance.Instance where
62 return $ Instance.create name mem dsk run_st pn sn
65 instance Arbitrary Node.Node where
69 mem_f <- choose (0, mem_t)
70 mem_n <- choose (0, mem_t - mem_f)
72 dsk_f <- choose (0, dsk_t)
74 let n = Node.create name (fromIntegral mem_t) mem_n mem_f
75 (fromIntegral dsk_t) dsk_f offl
76 n' = Node.buildPeers n Container.empty
79 -- | Make sure add is idempotent
80 prop_PeerMap_addIdempotent pmap key elem =
81 fn puniq == fn (fn puniq)
82 where _types = (pmap::PeerMap.PeerMap,
83 key::PeerMap.Key, elem::PeerMap.Elem)
84 fn = PeerMap.add key elem
85 puniq = PeerMap.accumArray const pmap
87 -- | Make sure remove is idempotent
88 prop_PeerMap_removeIdempotent pmap key =
89 fn puniq == fn (fn puniq)
90 where _types = (pmap::PeerMap.PeerMap, key::PeerMap.Key)
91 fn = PeerMap.remove key
92 puniq = PeerMap.accumArray const pmap
94 -- | Make sure a missing item returns 0
95 prop_PeerMap_findMissing pmap key =
96 PeerMap.find key (PeerMap.remove key puniq) == 0
97 where _types = (pmap::PeerMap.PeerMap, key::PeerMap.Key)
98 puniq = PeerMap.accumArray const pmap
100 -- | Make sure an added item is found
101 prop_PeerMap_addFind pmap key elem =
102 PeerMap.find key (PeerMap.add key elem puniq) == elem
103 where _types = (pmap::PeerMap.PeerMap,
104 key::PeerMap.Key, elem::PeerMap.Elem)
105 puniq = PeerMap.accumArray const pmap
107 -- | Manual check that maxElem returns the maximum indeed, or 0 for null
108 prop_PeerMap_maxElem pmap =
109 PeerMap.maxElem puniq == if null puniq then 0
110 else (maximum . snd . unzip) puniq
111 where _types = pmap::PeerMap.PeerMap
112 puniq = PeerMap.accumArray const pmap
115 [ run prop_PeerMap_addIdempotent
116 , run prop_PeerMap_removeIdempotent
117 , run prop_PeerMap_maxElem
118 , run prop_PeerMap_addFind
119 , run prop_PeerMap_findMissing
124 prop_Container_addTwo cdata i1 i2 =
125 fn i1 i2 cont == fn i2 i1 cont &&
126 fn i1 i2 cont == fn i1 i2 (fn i1 i2 cont)
127 where _types = (cdata::[Int],
129 cont = foldl (\c x -> Container.add x x c) Container.empty cdata
130 fn x1 x2 = Container.addTwo x1 x1 x2 x2
133 [ run prop_Container_addTwo ]
135 -- Simple instance tests, we only have setter/getters
137 prop_Instance_setIdx inst idx =
138 Instance.idx (Instance.setIdx inst idx) == idx
139 where _types = (inst::Instance.Instance, idx::Types.Idx)
141 prop_Instance_setName inst name =
142 Instance.name (Instance.setName inst name) == name
143 where _types = (inst::Instance.Instance, name::String)
145 prop_Instance_setPri inst pdx =
146 Instance.pnode (Instance.setPri inst pdx) == pdx
147 where _types = (inst::Instance.Instance, pdx::Types.Ndx)
149 prop_Instance_setSec inst sdx =
150 Instance.snode (Instance.setSec inst sdx) == sdx
151 where _types = (inst::Instance.Instance, sdx::Types.Ndx)
153 prop_Instance_setBoth inst pdx sdx =
154 Instance.pnode si == pdx && Instance.snode si == sdx
155 where _types = (inst::Instance.Instance, pdx::Types.Ndx, sdx::Types.Ndx)
156 si = Instance.setBoth inst pdx sdx
159 [ run prop_Instance_setIdx
160 , run prop_Instance_setName
161 , run prop_Instance_setPri
162 , run prop_Instance_setSec
163 , run prop_Instance_setBoth
168 -- | Check that an instance add with too high memory or disk will be rejected
169 prop_Node_addPri node inst = (Instance.mem inst >= Node.f_mem node ||
170 Instance.dsk inst >= Node.f_dsk node) &&
171 not (Node.failN1 node)
173 isNothing(Node.addPri node inst)
174 where _types = (node::Node.Node, inst::Instance.Instance)
177 -- | Check that an instance add with too high memory or disk will be rejected
178 prop_Node_addSec node inst pdx =
179 (Instance.mem inst >= (Node.f_mem node - Node.r_mem node) ||
180 Instance.dsk inst >= Node.f_dsk node) &&
181 not (Node.failN1 node)
182 ==> isNothing(Node.addSec node inst pdx)
183 where _types = (node::Node.Node, inst::Instance.Instance, pdx::Int)
186 [ run prop_Node_addPri
187 , run prop_Node_addSec