Take the foldl out of Loader.fixNodes
[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 -- copied from the introduction to quickcheck
50 instance Arbitrary Char where
51     arbitrary = choose ('\32', '\128')
52
53 -- let's generate a random instance
54 instance Arbitrary Instance.Instance where
55     arbitrary = do
56       name <- arbitrary
57       mem <- choose(0, 100)
58       dsk <- choose(0, 100)
59       run_st <- arbitrary
60       pn <- arbitrary
61       sn <- arbitrary
62       return $ Instance.create name mem dsk run_st pn sn
63
64 -- and a random node
65 instance Arbitrary Node.Node where
66     arbitrary = do
67       name <- arbitrary
68       mem_t <- arbitrary
69       mem_f <- choose (0, mem_t)
70       mem_n <- choose (0, mem_t - mem_f)
71       dsk_t <- arbitrary
72       dsk_f <- choose (0, dsk_t)
73       offl <- arbitrary
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
77       return n'
78
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
86
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
93
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
99
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
106
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
113
114 test_PeerMap =
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
120     ]
121
122 -- Container tests
123
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],
128                     i1::Int, i2::Int)
129           cont = foldl (\c x -> Container.add x x c) Container.empty cdata
130           fn x1 x2 = Container.addTwo x1 x1 x2 x2
131
132 test_Container =
133     [ run prop_Container_addTwo ]
134
135 -- Simple instance tests, we only have setter/getters
136
137 prop_Instance_setIdx inst idx =
138     Instance.idx (Instance.setIdx inst idx) == idx
139     where _types = (inst::Instance.Instance, idx::Types.Idx)
140
141 prop_Instance_setName inst name =
142     Instance.name (Instance.setName inst name) == name
143     where _types = (inst::Instance.Instance, name::String)
144
145 prop_Instance_setPri inst pdx =
146     Instance.pnode (Instance.setPri inst pdx) == pdx
147     where _types = (inst::Instance.Instance, pdx::Types.Ndx)
148
149 prop_Instance_setSec inst sdx =
150     Instance.snode (Instance.setSec inst sdx) == sdx
151     where _types = (inst::Instance.Instance, sdx::Types.Ndx)
152
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
157
158 test_Instance =
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
164     ]
165
166 -- Node tests
167
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)
172                              ==>
173                              isNothing(Node.addPri node inst)
174     where _types = (node::Node.Node, inst::Instance.Instance)
175
176
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)
184
185 test_Node =
186     [ run prop_Node_addPri
187     , run prop_Node_addSec
188     ]