Statistics
| Branch: | Tag: | Revision:

root / Ganeti / HTools / QC.hs @ 49f9627a

History | View | Annotate | Download (13.8 kB)

1 9b1e1cc9 Iustin Pop
{-| Unittests for ganeti-htools
2 e2fa2baf Iustin Pop
3 e2fa2baf Iustin Pop
-}
4 e2fa2baf Iustin Pop
5 e2fa2baf Iustin Pop
{-
6 e2fa2baf Iustin Pop
7 e2fa2baf Iustin Pop
Copyright (C) 2009 Google Inc.
8 e2fa2baf Iustin Pop
9 e2fa2baf Iustin Pop
This program is free software; you can redistribute it and/or modify
10 e2fa2baf Iustin Pop
it under the terms of the GNU General Public License as published by
11 e2fa2baf Iustin Pop
the Free Software Foundation; either version 2 of the License, or
12 e2fa2baf Iustin Pop
(at your option) any later version.
13 e2fa2baf Iustin Pop
14 e2fa2baf Iustin Pop
This program is distributed in the hope that it will be useful, but
15 e2fa2baf Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
16 e2fa2baf Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 e2fa2baf Iustin Pop
General Public License for more details.
18 e2fa2baf Iustin Pop
19 e2fa2baf Iustin Pop
You should have received a copy of the GNU General Public License
20 e2fa2baf Iustin Pop
along with this program; if not, write to the Free Software
21 e2fa2baf Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22 e2fa2baf Iustin Pop
02110-1301, USA.
23 e2fa2baf Iustin Pop
24 e2fa2baf Iustin Pop
-}
25 e2fa2baf Iustin Pop
26 15f4c8ca Iustin Pop
module Ganeti.HTools.QC
27 c15f7183 Iustin Pop
    ( testPeerMap
28 c15f7183 Iustin Pop
    , testContainer
29 c15f7183 Iustin Pop
    , testInstance
30 c15f7183 Iustin Pop
    , testNode
31 c15f7183 Iustin Pop
    , testText
32 c15f7183 Iustin Pop
    , testCluster
33 7dd5ee6c Iustin Pop
    ) where
34 15f4c8ca Iustin Pop
35 15f4c8ca Iustin Pop
import Test.QuickCheck
36 7dd5ee6c Iustin Pop
import Test.QuickCheck.Batch
37 15f4c8ca Iustin Pop
import Data.Maybe
38 8fcf251f Iustin Pop
import qualified Data.Map
39 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.CLI as CLI
40 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Cluster as Cluster
41 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Container as Container
42 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.IAlloc as IAlloc
43 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Instance as Instance
44 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Loader as Loader
45 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Node as Node
46 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.PeerMap as PeerMap
47 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Text as Text
48 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Types as Types
49 15f4c8ca Iustin Pop
import qualified Ganeti.HTools.Utils as Utils
50 15f4c8ca Iustin Pop
51 8fcf251f Iustin Pop
-- | Maximum memory (1TiB, somewhat random value)
52 8fcf251f Iustin Pop
maxMem :: Int
53 8fcf251f Iustin Pop
maxMem = 1024 * 1024
54 8fcf251f Iustin Pop
55 49f9627a Iustin Pop
-- | Maximum disk (8TiB, somewhat random value)
56 8fcf251f Iustin Pop
maxDsk :: Int
57 49f9627a Iustin Pop
maxDsk = 1024 * 1024 * 8
58 8fcf251f Iustin Pop
59 8fcf251f Iustin Pop
-- | Max CPUs (1024, somewhat random value)
60 8fcf251f Iustin Pop
maxCpu :: Int
61 8fcf251f Iustin Pop
maxCpu = 1024
62 8fcf251f Iustin Pop
63 79a72ce7 Iustin Pop
-- | Simple checker for whether OpResult is fail or pass
64 79a72ce7 Iustin Pop
isFailure :: Types.OpResult a -> Bool
65 79a72ce7 Iustin Pop
isFailure (Types.OpFail _) = True
66 79a72ce7 Iustin Pop
isFailure _ = False
67 79a72ce7 Iustin Pop
68 8fcf251f Iustin Pop
-- | Simple checker for whether Result is fail or pass
69 8fcf251f Iustin Pop
isOk :: Types.Result a -> Bool
70 8fcf251f Iustin Pop
isOk (Types.Ok _ ) = True
71 8fcf251f Iustin Pop
isOk _ = False
72 8fcf251f Iustin Pop
73 15f4c8ca Iustin Pop
-- copied from the introduction to quickcheck
74 15f4c8ca Iustin Pop
instance Arbitrary Char where
75 095d7ac0 Iustin Pop
    arbitrary = choose ('\32', '\128')
76 15f4c8ca Iustin Pop
77 15f4c8ca Iustin Pop
-- let's generate a random instance
78 15f4c8ca Iustin Pop
instance Arbitrary Instance.Instance where
79 15f4c8ca Iustin Pop
    arbitrary = do
80 15f4c8ca Iustin Pop
      name <- arbitrary
81 8fcf251f Iustin Pop
      mem <- choose (0, maxMem)
82 8fcf251f Iustin Pop
      dsk <- choose (0, maxDsk)
83 1ae7a904 Iustin Pop
      run_st <- elements ["ERROR_up", "ERROR_down", "ADMIN_down"
84 1ae7a904 Iustin Pop
                         , "ERROR_nodedown", "ERROR_nodeoffline"
85 1ae7a904 Iustin Pop
                         , "running"
86 1ae7a904 Iustin Pop
                         , "no_such_status1", "no_such_status2"]
87 15f4c8ca Iustin Pop
      pn <- arbitrary
88 15f4c8ca Iustin Pop
      sn <- arbitrary
89 8fcf251f Iustin Pop
      vcpus <- choose (0, maxCpu)
90 434c15d5 Iustin Pop
      return $ Instance.create name mem dsk vcpus run_st [] pn sn
91 15f4c8ca Iustin Pop
92 15f4c8ca Iustin Pop
-- and a random node
93 15f4c8ca Iustin Pop
instance Arbitrary Node.Node where
94 15f4c8ca Iustin Pop
    arbitrary = do
95 15f4c8ca Iustin Pop
      name <- arbitrary
96 8fcf251f Iustin Pop
      mem_t <- choose (0, maxMem)
97 15f4c8ca Iustin Pop
      mem_f <- choose (0, mem_t)
98 15f4c8ca Iustin Pop
      mem_n <- choose (0, mem_t - mem_f)
99 8fcf251f Iustin Pop
      dsk_t <- choose (0, maxDsk)
100 15f4c8ca Iustin Pop
      dsk_f <- choose (0, dsk_t)
101 8fcf251f Iustin Pop
      cpu_t <- choose (0, maxCpu)
102 15f4c8ca Iustin Pop
      offl <- arbitrary
103 15f4c8ca Iustin Pop
      let n = Node.create name (fromIntegral mem_t) mem_n mem_f
104 8fcf251f Iustin Pop
              (fromIntegral dsk_t) dsk_f (fromIntegral cpu_t) offl
105 9cf4267a Iustin Pop
          n' = Node.buildPeers n Container.empty
106 15f4c8ca Iustin Pop
      return n'
107 15f4c8ca Iustin Pop
108 8fcf251f Iustin Pop
setInstanceSmallerThanNode node inst =
109 8fcf251f Iustin Pop
    inst { Instance.mem = (Node.availMem node) `div` 2
110 8fcf251f Iustin Pop
         , Instance.dsk = (Node.availDisk node) `div` 2
111 8fcf251f Iustin Pop
         , Instance.vcpus = (Node.availCpu node) `div` 2
112 8fcf251f Iustin Pop
         }
113 8fcf251f Iustin Pop
114 15f4c8ca Iustin Pop
-- | Make sure add is idempotent
115 fbb95f28 Iustin Pop
prop_PeerMap_addIdempotent pmap key em =
116 15f4c8ca Iustin Pop
    fn puniq == fn (fn puniq)
117 7bc82927 Iustin Pop
    where _types = (pmap::PeerMap.PeerMap,
118 fbb95f28 Iustin Pop
                    key::PeerMap.Key, em::PeerMap.Elem)
119 fbb95f28 Iustin Pop
          fn = PeerMap.add key em
120 7bc82927 Iustin Pop
          puniq = PeerMap.accumArray const pmap
121 15f4c8ca Iustin Pop
122 15f4c8ca Iustin Pop
-- | Make sure remove is idempotent
123 15f4c8ca Iustin Pop
prop_PeerMap_removeIdempotent pmap key =
124 15f4c8ca Iustin Pop
    fn puniq == fn (fn puniq)
125 7bc82927 Iustin Pop
    where _types = (pmap::PeerMap.PeerMap, key::PeerMap.Key)
126 7bc82927 Iustin Pop
          fn = PeerMap.remove key
127 15f4c8ca Iustin Pop
          puniq = PeerMap.accumArray const pmap
128 15f4c8ca Iustin Pop
129 15f4c8ca Iustin Pop
-- | Make sure a missing item returns 0
130 15f4c8ca Iustin Pop
prop_PeerMap_findMissing pmap key =
131 15f4c8ca Iustin Pop
    PeerMap.find key (PeerMap.remove key puniq) == 0
132 7bc82927 Iustin Pop
    where _types = (pmap::PeerMap.PeerMap, key::PeerMap.Key)
133 15f4c8ca Iustin Pop
          puniq = PeerMap.accumArray const pmap
134 15f4c8ca Iustin Pop
135 15f4c8ca Iustin Pop
-- | Make sure an added item is found
136 fbb95f28 Iustin Pop
prop_PeerMap_addFind pmap key em =
137 fbb95f28 Iustin Pop
    PeerMap.find key (PeerMap.add key em puniq) == em
138 7bc82927 Iustin Pop
    where _types = (pmap::PeerMap.PeerMap,
139 fbb95f28 Iustin Pop
                    key::PeerMap.Key, em::PeerMap.Elem)
140 7bc82927 Iustin Pop
          puniq = PeerMap.accumArray const pmap
141 15f4c8ca Iustin Pop
142 15f4c8ca Iustin Pop
-- | Manual check that maxElem returns the maximum indeed, or 0 for null
143 15f4c8ca Iustin Pop
prop_PeerMap_maxElem pmap =
144 15f4c8ca Iustin Pop
    PeerMap.maxElem puniq == if null puniq then 0
145 15f4c8ca Iustin Pop
                             else (maximum . snd . unzip) puniq
146 7bc82927 Iustin Pop
    where _types = pmap::PeerMap.PeerMap
147 15f4c8ca Iustin Pop
          puniq = PeerMap.accumArray const pmap
148 15f4c8ca Iustin Pop
149 c15f7183 Iustin Pop
testPeerMap =
150 7dd5ee6c Iustin Pop
    [ run prop_PeerMap_addIdempotent
151 7dd5ee6c Iustin Pop
    , run prop_PeerMap_removeIdempotent
152 7dd5ee6c Iustin Pop
    , run prop_PeerMap_maxElem
153 7dd5ee6c Iustin Pop
    , run prop_PeerMap_addFind
154 7dd5ee6c Iustin Pop
    , run prop_PeerMap_findMissing
155 7dd5ee6c Iustin Pop
    ]
156 7dd5ee6c Iustin Pop
157 095d7ac0 Iustin Pop
-- Container tests
158 095d7ac0 Iustin Pop
159 095d7ac0 Iustin Pop
prop_Container_addTwo cdata i1 i2 =
160 095d7ac0 Iustin Pop
    fn i1 i2 cont == fn i2 i1 cont &&
161 095d7ac0 Iustin Pop
       fn i1 i2 cont == fn i1 i2 (fn i1 i2 cont)
162 095d7ac0 Iustin Pop
    where _types = (cdata::[Int],
163 095d7ac0 Iustin Pop
                    i1::Int, i2::Int)
164 095d7ac0 Iustin Pop
          cont = foldl (\c x -> Container.add x x c) Container.empty cdata
165 095d7ac0 Iustin Pop
          fn x1 x2 = Container.addTwo x1 x1 x2 x2
166 095d7ac0 Iustin Pop
167 c15f7183 Iustin Pop
testContainer =
168 7dd5ee6c Iustin Pop
    [ run prop_Container_addTwo ]
169 095d7ac0 Iustin Pop
170 7bc82927 Iustin Pop
-- Simple instance tests, we only have setter/getters
171 7bc82927 Iustin Pop
172 7bc82927 Iustin Pop
prop_Instance_setIdx inst idx =
173 7bc82927 Iustin Pop
    Instance.idx (Instance.setIdx inst idx) == idx
174 7bc82927 Iustin Pop
    where _types = (inst::Instance.Instance, idx::Types.Idx)
175 7bc82927 Iustin Pop
176 7bc82927 Iustin Pop
prop_Instance_setName inst name =
177 7bc82927 Iustin Pop
    Instance.name (Instance.setName inst name) == name
178 7bc82927 Iustin Pop
    where _types = (inst::Instance.Instance, name::String)
179 7bc82927 Iustin Pop
180 7bc82927 Iustin Pop
prop_Instance_setPri inst pdx =
181 2060348b Iustin Pop
    Instance.pNode (Instance.setPri inst pdx) == pdx
182 7bc82927 Iustin Pop
    where _types = (inst::Instance.Instance, pdx::Types.Ndx)
183 7bc82927 Iustin Pop
184 7bc82927 Iustin Pop
prop_Instance_setSec inst sdx =
185 2060348b Iustin Pop
    Instance.sNode (Instance.setSec inst sdx) == sdx
186 7bc82927 Iustin Pop
    where _types = (inst::Instance.Instance, sdx::Types.Ndx)
187 7bc82927 Iustin Pop
188 7bc82927 Iustin Pop
prop_Instance_setBoth inst pdx sdx =
189 2060348b Iustin Pop
    Instance.pNode si == pdx && Instance.sNode si == sdx
190 7bc82927 Iustin Pop
    where _types = (inst::Instance.Instance, pdx::Types.Ndx, sdx::Types.Ndx)
191 7bc82927 Iustin Pop
          si = Instance.setBoth inst pdx sdx
192 7bc82927 Iustin Pop
193 1ae7a904 Iustin Pop
prop_Instance_runStatus_True inst =
194 1ae7a904 Iustin Pop
    let run_st = Instance.running inst
195 2060348b Iustin Pop
        run_tx = Instance.runSt inst
196 1ae7a904 Iustin Pop
    in
197 a46f34d7 Iustin Pop
      run_tx `elem` Instance.runningStates ==> run_st
198 1ae7a904 Iustin Pop
199 1ae7a904 Iustin Pop
prop_Instance_runStatus_False inst =
200 1ae7a904 Iustin Pop
    let run_st = Instance.running inst
201 2060348b Iustin Pop
        run_tx = Instance.runSt inst
202 1ae7a904 Iustin Pop
    in
203 a46f34d7 Iustin Pop
      run_tx `notElem` Instance.runningStates ==> not run_st
204 1ae7a904 Iustin Pop
205 8fcf251f Iustin Pop
prop_Instance_shrinkMG inst =
206 8fcf251f Iustin Pop
    Instance.mem inst >= 2 * Types.unitMem ==>
207 8fcf251f Iustin Pop
        case Instance.shrinkByType inst Types.FailMem of
208 8fcf251f Iustin Pop
          Types.Ok inst' ->
209 8fcf251f Iustin Pop
              Instance.mem inst' == Instance.mem inst - Types.unitMem
210 8fcf251f Iustin Pop
          _ -> False
211 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance)
212 8fcf251f Iustin Pop
213 8fcf251f Iustin Pop
prop_Instance_shrinkMF inst =
214 8fcf251f Iustin Pop
    Instance.mem inst < 2 * Types.unitMem ==>
215 8fcf251f Iustin Pop
        not . isOk $ Instance.shrinkByType inst Types.FailMem
216 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance)
217 8fcf251f Iustin Pop
218 8fcf251f Iustin Pop
prop_Instance_shrinkCG inst =
219 8fcf251f Iustin Pop
    Instance.vcpus inst >= 2 * Types.unitCpu ==>
220 8fcf251f Iustin Pop
        case Instance.shrinkByType inst Types.FailCPU of
221 8fcf251f Iustin Pop
          Types.Ok inst' ->
222 8fcf251f Iustin Pop
              Instance.vcpus inst' == Instance.vcpus inst - Types.unitCpu
223 8fcf251f Iustin Pop
          _ -> False
224 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance)
225 8fcf251f Iustin Pop
226 8fcf251f Iustin Pop
prop_Instance_shrinkCF inst =
227 8fcf251f Iustin Pop
    Instance.vcpus inst < 2 * Types.unitCpu ==>
228 8fcf251f Iustin Pop
        not . isOk $ Instance.shrinkByType inst Types.FailCPU
229 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance)
230 8fcf251f Iustin Pop
231 8fcf251f Iustin Pop
prop_Instance_shrinkDG inst =
232 8fcf251f Iustin Pop
    Instance.dsk inst >= 2 * Types.unitDsk ==>
233 8fcf251f Iustin Pop
        case Instance.shrinkByType inst Types.FailDisk of
234 8fcf251f Iustin Pop
          Types.Ok inst' ->
235 8fcf251f Iustin Pop
              Instance.dsk inst' == Instance.dsk inst - Types.unitDsk
236 8fcf251f Iustin Pop
          _ -> False
237 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance)
238 8fcf251f Iustin Pop
239 8fcf251f Iustin Pop
prop_Instance_shrinkDF inst =
240 8fcf251f Iustin Pop
    Instance.dsk inst < 2 * Types.unitDsk ==>
241 8fcf251f Iustin Pop
        not . isOk $ Instance.shrinkByType inst Types.FailDisk
242 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance)
243 8fcf251f Iustin Pop
244 8fcf251f Iustin Pop
prop_Instance_setMovable inst m =
245 8fcf251f Iustin Pop
    Instance.movable inst' == m
246 8fcf251f Iustin Pop
    where _types = (inst::Instance.Instance, m::Bool)
247 8fcf251f Iustin Pop
          inst' = Instance.setMovable inst m
248 8fcf251f Iustin Pop
249 c15f7183 Iustin Pop
testInstance =
250 7dd5ee6c Iustin Pop
    [ run prop_Instance_setIdx
251 7dd5ee6c Iustin Pop
    , run prop_Instance_setName
252 7dd5ee6c Iustin Pop
    , run prop_Instance_setPri
253 7dd5ee6c Iustin Pop
    , run prop_Instance_setSec
254 7dd5ee6c Iustin Pop
    , run prop_Instance_setBoth
255 1ae7a904 Iustin Pop
    , run prop_Instance_runStatus_True
256 1ae7a904 Iustin Pop
    , run prop_Instance_runStatus_False
257 8fcf251f Iustin Pop
    , run prop_Instance_shrinkMG
258 8fcf251f Iustin Pop
    , run prop_Instance_shrinkMF
259 8fcf251f Iustin Pop
    , run prop_Instance_shrinkCG
260 8fcf251f Iustin Pop
    , run prop_Instance_shrinkCF
261 8fcf251f Iustin Pop
    , run prop_Instance_shrinkDG
262 8fcf251f Iustin Pop
    , run prop_Instance_shrinkDF
263 8fcf251f Iustin Pop
    , run prop_Instance_setMovable
264 1ae7a904 Iustin Pop
    ]
265 1ae7a904 Iustin Pop
266 1ae7a904 Iustin Pop
-- Instance text loader tests
267 1ae7a904 Iustin Pop
268 1ae7a904 Iustin Pop
prop_Text_Load_Instance name mem dsk vcpus status pnode snode pdx sdx =
269 1ae7a904 Iustin Pop
    let vcpus_s = show vcpus
270 1ae7a904 Iustin Pop
        dsk_s = show dsk
271 1ae7a904 Iustin Pop
        mem_s = show mem
272 1ae7a904 Iustin Pop
        rsnode = snode ++ "a" -- non-empty secondary node
273 1ae7a904 Iustin Pop
        rsdx = if pdx == sdx
274 1ae7a904 Iustin Pop
               then sdx + 1
275 1ae7a904 Iustin Pop
               else sdx
276 1ae7a904 Iustin Pop
        ndx = [(pnode, pdx), (rsnode, rsdx)]
277 434c15d5 Iustin Pop
        tags = ""
278 1ae7a904 Iustin Pop
        inst = Text.loadInst ndx
279 434c15d5 Iustin Pop
               [name, mem_s, dsk_s, vcpus_s, status, pnode, rsnode, tags]::
280 1ae7a904 Iustin Pop
               Maybe (String, Instance.Instance)
281 1ae7a904 Iustin Pop
        _types = ( name::String, mem::Int, dsk::Int
282 1ae7a904 Iustin Pop
                 , vcpus::Int, status::String
283 1ae7a904 Iustin Pop
                 , pnode::String, snode::String
284 1ae7a904 Iustin Pop
                 , pdx::Types.Ndx, sdx::Types.Ndx)
285 1ae7a904 Iustin Pop
    in
286 1ae7a904 Iustin Pop
      case inst of
287 1ae7a904 Iustin Pop
        Nothing -> False
288 1ae7a904 Iustin Pop
        Just (_, i) ->
289 1ae7a904 Iustin Pop
            (Instance.name i == name &&
290 1ae7a904 Iustin Pop
             Instance.vcpus i == vcpus &&
291 1ae7a904 Iustin Pop
             Instance.mem i == mem &&
292 2060348b Iustin Pop
             Instance.pNode i == pdx &&
293 2060348b Iustin Pop
             Instance.sNode i == rsdx)
294 1ae7a904 Iustin Pop
295 c15f7183 Iustin Pop
testText =
296 1ae7a904 Iustin Pop
    [ run prop_Text_Load_Instance
297 7dd5ee6c Iustin Pop
    ]
298 7dd5ee6c Iustin Pop
299 7dd5ee6c Iustin Pop
-- Node tests
300 7dd5ee6c Iustin Pop
301 7bc82927 Iustin Pop
-- | Check that an instance add with too high memory or disk will be rejected
302 8fcf251f Iustin Pop
prop_Node_addPriFM node inst = Instance.mem inst >= Node.fMem node &&
303 8fcf251f Iustin Pop
                               not (Node.failN1 node)
304 8fcf251f Iustin Pop
                               ==>
305 8fcf251f Iustin Pop
                               case Node.addPri node inst'' of
306 8fcf251f Iustin Pop
                                 Types.OpFail Types.FailMem -> True
307 8fcf251f Iustin Pop
                                 _ -> False
308 15f4c8ca Iustin Pop
    where _types = (node::Node.Node, inst::Instance.Instance)
309 8fcf251f Iustin Pop
          inst' = setInstanceSmallerThanNode node inst
310 8fcf251f Iustin Pop
          inst'' = inst' { Instance.mem = Instance.mem inst }
311 8fcf251f Iustin Pop
312 8fcf251f Iustin Pop
prop_Node_addPriFD node inst = Instance.dsk inst >= Node.fDsk node &&
313 8fcf251f Iustin Pop
                               not (Node.failN1 node)
314 8fcf251f Iustin Pop
                               ==>
315 8fcf251f Iustin Pop
                               case Node.addPri node inst'' of
316 8fcf251f Iustin Pop
                                 Types.OpFail Types.FailDisk -> True
317 8fcf251f Iustin Pop
                                 _ -> False
318 8fcf251f Iustin Pop
    where _types = (node::Node.Node, inst::Instance.Instance)
319 8fcf251f Iustin Pop
          inst' = setInstanceSmallerThanNode node inst
320 8fcf251f Iustin Pop
          inst'' = inst' { Instance.dsk = Instance.dsk inst }
321 8fcf251f Iustin Pop
322 8fcf251f Iustin Pop
prop_Node_addPriFC node inst = Instance.vcpus inst > Node.availCpu node &&
323 8fcf251f Iustin Pop
                               not (Node.failN1 node)
324 8fcf251f Iustin Pop
                               ==>
325 8fcf251f Iustin Pop
                               case Node.addPri node inst'' of
326 8fcf251f Iustin Pop
                                 Types.OpFail Types.FailCPU -> True
327 8fcf251f Iustin Pop
                                 _ -> False
328 8fcf251f Iustin Pop
    where _types = (node::Node.Node, inst::Instance.Instance)
329 8fcf251f Iustin Pop
          inst' = setInstanceSmallerThanNode node inst
330 8fcf251f Iustin Pop
          inst'' = inst' { Instance.vcpus = Instance.vcpus inst }
331 7bc82927 Iustin Pop
332 7bc82927 Iustin Pop
-- | Check that an instance add with too high memory or disk will be rejected
333 15f4c8ca Iustin Pop
prop_Node_addSec node inst pdx =
334 2060348b Iustin Pop
    (Instance.mem inst >= (Node.fMem node - Node.rMem node) ||
335 2060348b Iustin Pop
     Instance.dsk inst >= Node.fDsk node) &&
336 9f6dcdea Iustin Pop
    not (Node.failN1 node)
337 79a72ce7 Iustin Pop
    ==> isFailure (Node.addSec node inst pdx)
338 15f4c8ca Iustin Pop
        where _types = (node::Node.Node, inst::Instance.Instance, pdx::Int)
339 7dd5ee6c Iustin Pop
340 8fcf251f Iustin Pop
newtype SmallRatio = SmallRatio Double deriving Show
341 8fcf251f Iustin Pop
instance Arbitrary SmallRatio where
342 8fcf251f Iustin Pop
    arbitrary = do
343 8fcf251f Iustin Pop
      v <- choose (0, 1)
344 8fcf251f Iustin Pop
      return $ SmallRatio v
345 8fcf251f Iustin Pop
346 8fcf251f Iustin Pop
-- | Check mdsk setting
347 8fcf251f Iustin Pop
prop_Node_setMdsk node mx =
348 8fcf251f Iustin Pop
    Node.loDsk node' >= 0 &&
349 8fcf251f Iustin Pop
    fromIntegral (Node.loDsk node') <= Node.tDsk node &&
350 8fcf251f Iustin Pop
    Node.availDisk node' >= 0 &&
351 8fcf251f Iustin Pop
    Node.availDisk node' <= Node.fDsk node' &&
352 8fcf251f Iustin Pop
    fromIntegral (Node.availDisk node') <= Node.tDsk node'
353 8fcf251f Iustin Pop
    where _types = (node::Node.Node, mx::SmallRatio)
354 8fcf251f Iustin Pop
          node' = Node.setMdsk node mx'
355 8fcf251f Iustin Pop
          SmallRatio mx' = mx
356 8fcf251f Iustin Pop
357 8fcf251f Iustin Pop
-- Check tag maps
358 8fcf251f Iustin Pop
prop_Node_tagMaps_idempotent tags =
359 8fcf251f Iustin Pop
    Node.delTags (Node.addTags m tags) tags == m
360 8fcf251f Iustin Pop
    where _types = (tags::[String])
361 8fcf251f Iustin Pop
          m = Data.Map.empty
362 8fcf251f Iustin Pop
363 8fcf251f Iustin Pop
prop_Node_tagMaps_reject tags =
364 8fcf251f Iustin Pop
    not (null tags) ==>
365 8fcf251f Iustin Pop
    any (\t -> Node.rejectAddTags m [t]) tags
366 8fcf251f Iustin Pop
    where _types = (tags::[String])
367 8fcf251f Iustin Pop
          m = Node.addTags (Data.Map.empty) tags
368 8fcf251f Iustin Pop
369 c15f7183 Iustin Pop
testNode =
370 8fcf251f Iustin Pop
    [ run prop_Node_addPriFM
371 8fcf251f Iustin Pop
    , run prop_Node_addPriFD
372 8fcf251f Iustin Pop
    , run prop_Node_addPriFC
373 7dd5ee6c Iustin Pop
    , run prop_Node_addSec
374 8fcf251f Iustin Pop
    , run prop_Node_setMdsk
375 8fcf251f Iustin Pop
    , run prop_Node_tagMaps_idempotent
376 8fcf251f Iustin Pop
    , run prop_Node_tagMaps_reject
377 7dd5ee6c Iustin Pop
    ]
378 cf35a869 Iustin Pop
379 cf35a869 Iustin Pop
380 cf35a869 Iustin Pop
-- Cluster tests
381 cf35a869 Iustin Pop
382 cf35a869 Iustin Pop
-- | Check that the cluster score is close to zero for a homogeneous cluster
383 cf35a869 Iustin Pop
prop_Score_Zero node count =
384 3a3c1eb4 Iustin Pop
    (not (Node.offline node) && not (Node.failN1 node) && (count > 0) &&
385 2060348b Iustin Pop
     (Node.tDsk node > 0) && (Node.tMem node > 0)) ==>
386 cf35a869 Iustin Pop
    let fn = Node.buildPeers node Container.empty
387 3a3c1eb4 Iustin Pop
        nlst = zip [1..] $ replicate count fn::[(Types.Ndx, Node.Node)]
388 cf35a869 Iustin Pop
        nl = Container.fromAssocList nlst
389 cf35a869 Iustin Pop
        score = Cluster.compCV nl
390 cf35a869 Iustin Pop
    -- we can't say == 0 here as the floating point errors accumulate;
391 cf35a869 Iustin Pop
    -- this should be much lower than the default score in CLI.hs
392 685f5bc6 Iustin Pop
    in score <= 1e-15
393 cf35a869 Iustin Pop
394 8fcf251f Iustin Pop
-- | Check that cluster stats are sane
395 8fcf251f Iustin Pop
prop_CStats_sane node count =
396 8fcf251f Iustin Pop
    (not (Node.offline node) && not (Node.failN1 node) && (count > 0) &&
397 8fcf251f Iustin Pop
     (Node.tDsk node > 0) && (Node.tMem node > 0)) ==>
398 8fcf251f Iustin Pop
    let fn = Node.buildPeers node Container.empty
399 8fcf251f Iustin Pop
        nlst = zip [1..] $ replicate count fn::[(Types.Ndx, Node.Node)]
400 8fcf251f Iustin Pop
        nl = Container.fromAssocList nlst
401 8fcf251f Iustin Pop
        cstats = Cluster.totalResources nl
402 8fcf251f Iustin Pop
    in Cluster.csAdsk cstats >= 0 &&
403 8fcf251f Iustin Pop
       Cluster.csAdsk cstats <= Cluster.csFdsk cstats
404 8fcf251f Iustin Pop
405 c15f7183 Iustin Pop
testCluster =
406 cf35a869 Iustin Pop
    [ run prop_Score_Zero
407 8fcf251f Iustin Pop
    , run prop_CStats_sane
408 cf35a869 Iustin Pop
    ]