Add support for luxi backend in CLI/hspace/hbal
[ganeti-local] / Ganeti / HTools / QC.hs
1 {-| Unittests for ganeti-htools
2
3 -}
4
5 {-
6
7 Copyright (C) 2009 Google Inc.
8
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.
13
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.
18
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
22 02110-1301, USA.
23
24 -}
25
26 module Ganeti.HTools.QC
27     ( test_PeerMap
28     , test_Container
29     , test_Instance
30     , test_Node
31     ) where
32
33 import Test.QuickCheck
34 import Test.QuickCheck.Batch
35 import Data.Maybe
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
48
49 -- | Simple checker for whether OpResult is fail or pass
50 isFailure :: Types.OpResult a -> Bool
51 isFailure (Types.OpFail _) = True
52 isFailure _ = False
53
54 -- copied from the introduction to quickcheck
55 instance Arbitrary Char where
56     arbitrary = choose ('\32', '\128')
57
58 -- let's generate a random instance
59 instance Arbitrary Instance.Instance where
60     arbitrary = do
61       name <- arbitrary
62       mem <- choose(0, 100)
63       dsk <- choose(0, 100)
64       run_st <- arbitrary
65       pn <- arbitrary
66       sn <- arbitrary
67       vcpus <- arbitrary
68       return $ Instance.create name mem dsk vcpus run_st pn sn
69
70 -- and a random node
71 instance Arbitrary Node.Node where
72     arbitrary = do
73       name <- arbitrary
74       mem_t <- arbitrary
75       mem_f <- choose (0, mem_t)
76       mem_n <- choose (0, mem_t - mem_f)
77       dsk_t <- arbitrary
78       dsk_f <- choose (0, dsk_t)
79       cpu_t <- arbitrary
80       offl <- arbitrary
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
84       return n'
85
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
93
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
100
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
106
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
113
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
120
121 test_PeerMap =
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
127     ]
128
129 -- Container tests
130
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],
135                     i1::Int, i2::Int)
136           cont = foldl (\c x -> Container.add x x c) Container.empty cdata
137           fn x1 x2 = Container.addTwo x1 x1 x2 x2
138
139 test_Container =
140     [ run prop_Container_addTwo ]
141
142 -- Simple instance tests, we only have setter/getters
143
144 prop_Instance_setIdx inst idx =
145     Instance.idx (Instance.setIdx inst idx) == idx
146     where _types = (inst::Instance.Instance, idx::Types.Idx)
147
148 prop_Instance_setName inst name =
149     Instance.name (Instance.setName inst name) == name
150     where _types = (inst::Instance.Instance, name::String)
151
152 prop_Instance_setPri inst pdx =
153     Instance.pnode (Instance.setPri inst pdx) == pdx
154     where _types = (inst::Instance.Instance, pdx::Types.Ndx)
155
156 prop_Instance_setSec inst sdx =
157     Instance.snode (Instance.setSec inst sdx) == sdx
158     where _types = (inst::Instance.Instance, sdx::Types.Ndx)
159
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
164
165 test_Instance =
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
171     ]
172
173 -- Node tests
174
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)
179                              ==>
180                              isFailure (Node.addPri node inst)
181     where _types = (node::Node.Node, inst::Instance.Instance)
182
183
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)
191
192 test_Node =
193     [ run prop_Node_addPri
194     , run prop_Node_addSec
195     ]