Statistics
| Branch: | Tag: | Revision:

root / htest / Test / Ganeti / HTools / Node.hs @ 61899e64

History | View | Annotate | Download (12 kB)

1 e1ee7d5a Iustin Pop
{-# LANGUAGE TemplateHaskell #-}
2 e1ee7d5a Iustin Pop
{-# OPTIONS_GHC -fno-warn-orphans #-}
3 e1ee7d5a Iustin Pop
4 e1ee7d5a Iustin Pop
{-| Unittests for ganeti-htools.
5 e1ee7d5a Iustin Pop
6 e1ee7d5a Iustin Pop
-}
7 e1ee7d5a Iustin Pop
8 e1ee7d5a Iustin Pop
{-
9 e1ee7d5a Iustin Pop
10 e1ee7d5a Iustin Pop
Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
11 e1ee7d5a Iustin Pop
12 e1ee7d5a Iustin Pop
This program is free software; you can redistribute it and/or modify
13 e1ee7d5a Iustin Pop
it under the terms of the GNU General Public License as published by
14 e1ee7d5a Iustin Pop
the Free Software Foundation; either version 2 of the License, or
15 e1ee7d5a Iustin Pop
(at your option) any later version.
16 e1ee7d5a Iustin Pop
17 e1ee7d5a Iustin Pop
This program is distributed in the hope that it will be useful, but
18 e1ee7d5a Iustin Pop
WITHOUT ANY WARRANTY; without even the implied warranty of
19 e1ee7d5a Iustin Pop
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 e1ee7d5a Iustin Pop
General Public License for more details.
21 e1ee7d5a Iustin Pop
22 e1ee7d5a Iustin Pop
You should have received a copy of the GNU General Public License
23 e1ee7d5a Iustin Pop
along with this program; if not, write to the Free Software
24 e1ee7d5a Iustin Pop
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 e1ee7d5a Iustin Pop
02110-1301, USA.
26 e1ee7d5a Iustin Pop
27 e1ee7d5a Iustin Pop
-}
28 e1ee7d5a Iustin Pop
29 e1ee7d5a Iustin Pop
module Test.Ganeti.HTools.Node
30 e09c1fa0 Iustin Pop
  ( testHTools_Node
31 e1ee7d5a Iustin Pop
  , Node.Node(..)
32 e1ee7d5a Iustin Pop
  , setInstanceSmallerThanNode
33 e1ee7d5a Iustin Pop
  , genNode
34 e1ee7d5a Iustin Pop
  , genOnlineNode
35 e1ee7d5a Iustin Pop
  ) where
36 e1ee7d5a Iustin Pop
37 e1ee7d5a Iustin Pop
import Test.QuickCheck
38 e1ee7d5a Iustin Pop
39 e1ee7d5a Iustin Pop
import Control.Monad
40 e1ee7d5a Iustin Pop
import qualified Data.Map as Map
41 e1ee7d5a Iustin Pop
import Data.List
42 e1ee7d5a Iustin Pop
43 e1ee7d5a Iustin Pop
import Test.Ganeti.TestHelper
44 e1ee7d5a Iustin Pop
import Test.Ganeti.TestCommon
45 e1ee7d5a Iustin Pop
import Test.Ganeti.TestHTools
46 e1ee7d5a Iustin Pop
import Test.Ganeti.HTools.Instance (genInstanceSmallerThanNode)
47 e1ee7d5a Iustin Pop
48 a8038349 Iustin Pop
import Ganeti.BasicTypes
49 e1ee7d5a Iustin Pop
import qualified Ganeti.HTools.Container as Container
50 e1ee7d5a Iustin Pop
import qualified Ganeti.HTools.Instance as Instance
51 e1ee7d5a Iustin Pop
import qualified Ganeti.HTools.Node as Node
52 e1ee7d5a Iustin Pop
import qualified Ganeti.HTools.Types as Types
53 e1ee7d5a Iustin Pop
54 e1ee7d5a Iustin Pop
-- * Arbitrary instances
55 e1ee7d5a Iustin Pop
56 dd77da99 Helga Velroyen
-- | Generates an arbitrary node based on sizing information.
57 e1ee7d5a Iustin Pop
genNode :: Maybe Int -- ^ Minimum node size in terms of units
58 e1ee7d5a Iustin Pop
        -> Maybe Int -- ^ Maximum node size (when Nothing, bounded
59 e1ee7d5a Iustin Pop
                     -- just by the max... constants)
60 e1ee7d5a Iustin Pop
        -> Gen Node.Node
61 e1ee7d5a Iustin Pop
genNode min_multiplier max_multiplier = do
62 e1ee7d5a Iustin Pop
  let (base_mem, base_dsk, base_cpu) =
63 e1ee7d5a Iustin Pop
        case min_multiplier of
64 e1ee7d5a Iustin Pop
          Just mm -> (mm * Types.unitMem,
65 e1ee7d5a Iustin Pop
                      mm * Types.unitDsk,
66 e1ee7d5a Iustin Pop
                      mm * Types.unitCpu)
67 e1ee7d5a Iustin Pop
          Nothing -> (0, 0, 0)
68 e1ee7d5a Iustin Pop
      (top_mem, top_dsk, top_cpu)  =
69 e1ee7d5a Iustin Pop
        case max_multiplier of
70 e1ee7d5a Iustin Pop
          Just mm -> (mm * Types.unitMem,
71 e1ee7d5a Iustin Pop
                      mm * Types.unitDsk,
72 e1ee7d5a Iustin Pop
                      mm * Types.unitCpu)
73 e1ee7d5a Iustin Pop
          Nothing -> (maxMem, maxDsk, maxCpu)
74 e1ee7d5a Iustin Pop
  name  <- getFQDN
75 e1ee7d5a Iustin Pop
  mem_t <- choose (base_mem, top_mem)
76 e1ee7d5a Iustin Pop
  mem_f <- choose (base_mem, mem_t)
77 e1ee7d5a Iustin Pop
  mem_n <- choose (0, mem_t - mem_f)
78 e1ee7d5a Iustin Pop
  dsk_t <- choose (base_dsk, top_dsk)
79 e1ee7d5a Iustin Pop
  dsk_f <- choose (base_dsk, dsk_t)
80 e1ee7d5a Iustin Pop
  cpu_t <- choose (base_cpu, top_cpu)
81 e1ee7d5a Iustin Pop
  offl  <- arbitrary
82 e1ee7d5a Iustin Pop
  let n = Node.create name (fromIntegral mem_t) mem_n mem_f
83 e1ee7d5a Iustin Pop
          (fromIntegral dsk_t) dsk_f (fromIntegral cpu_t) offl 1 0
84 e1ee7d5a Iustin Pop
      n' = Node.setPolicy nullIPolicy n
85 e1ee7d5a Iustin Pop
  return $ Node.buildPeers n' Container.empty
86 e1ee7d5a Iustin Pop
87 e1ee7d5a Iustin Pop
-- | Helper function to generate a sane node.
88 e1ee7d5a Iustin Pop
genOnlineNode :: Gen Node.Node
89 5b11f8db Iustin Pop
genOnlineNode =
90 e1ee7d5a Iustin Pop
  arbitrary `suchThat` (\n -> not (Node.offline n) &&
91 e1ee7d5a Iustin Pop
                              not (Node.failN1 n) &&
92 e1ee7d5a Iustin Pop
                              Node.availDisk n > 0 &&
93 e1ee7d5a Iustin Pop
                              Node.availMem n > 0 &&
94 e1ee7d5a Iustin Pop
                              Node.availCpu n > 0)
95 e1ee7d5a Iustin Pop
96 e1ee7d5a Iustin Pop
-- and a random node
97 e1ee7d5a Iustin Pop
instance Arbitrary Node.Node where
98 e1ee7d5a Iustin Pop
  arbitrary = genNode Nothing Nothing
99 e1ee7d5a Iustin Pop
100 e1ee7d5a Iustin Pop
-- * Test cases
101 e1ee7d5a Iustin Pop
102 20bc5360 Iustin Pop
prop_setAlias :: Node.Node -> String -> Bool
103 20bc5360 Iustin Pop
prop_setAlias node name =
104 e1ee7d5a Iustin Pop
  Node.name newnode == Node.name node &&
105 e1ee7d5a Iustin Pop
  Node.alias newnode == name
106 e1ee7d5a Iustin Pop
    where newnode = Node.setAlias node name
107 e1ee7d5a Iustin Pop
108 20bc5360 Iustin Pop
prop_setOffline :: Node.Node -> Bool -> Property
109 20bc5360 Iustin Pop
prop_setOffline node status =
110 e1ee7d5a Iustin Pop
  Node.offline newnode ==? status
111 e1ee7d5a Iustin Pop
    where newnode = Node.setOffline node status
112 e1ee7d5a Iustin Pop
113 20bc5360 Iustin Pop
prop_setXmem :: Node.Node -> Int -> Property
114 20bc5360 Iustin Pop
prop_setXmem node xm =
115 e1ee7d5a Iustin Pop
  Node.xMem newnode ==? xm
116 e1ee7d5a Iustin Pop
    where newnode = Node.setXmem node xm
117 e1ee7d5a Iustin Pop
118 20bc5360 Iustin Pop
prop_setMcpu :: Node.Node -> Double -> Property
119 20bc5360 Iustin Pop
prop_setMcpu node mc =
120 e1ee7d5a Iustin Pop
  Types.iPolicyVcpuRatio (Node.iPolicy newnode) ==? mc
121 e1ee7d5a Iustin Pop
    where newnode = Node.setMcpu node mc
122 e1ee7d5a Iustin Pop
123 77ffd663 Helga Velroyen
prop_setFmemGreater :: Node.Node -> Int -> Property
124 77ffd663 Helga Velroyen
prop_setFmemGreater node new_mem =
125 77ffd663 Helga Velroyen
  not (Node.failN1 node) && (Node.rMem node >= 0) &&
126 77ffd663 Helga Velroyen
  (new_mem > Node.rMem node) ==>
127 77ffd663 Helga Velroyen
  not (Node.failN1 (Node.setFmem node new_mem))
128 77ffd663 Helga Velroyen
129 77ffd663 Helga Velroyen
prop_setFmemExact :: Node.Node -> Property
130 77ffd663 Helga Velroyen
prop_setFmemExact node =
131 77ffd663 Helga Velroyen
  not (Node.failN1 node) && (Node.rMem node >= 0) ==>
132 77ffd663 Helga Velroyen
  not (Node.failN1 (Node.setFmem node (Node.rMem node)))
133 77ffd663 Helga Velroyen
134 77ffd663 Helga Velroyen
-- Check if adding an instance that consumes exactly all reserved
135 77ffd663 Helga Velroyen
-- memory does not raise an N+1 error
136 77ffd663 Helga Velroyen
prop_addPri_NoN1Fail :: Property
137 77ffd663 Helga Velroyen
prop_addPri_NoN1Fail =
138 77ffd663 Helga Velroyen
  forAll genOnlineNode $ \node ->
139 77ffd663 Helga Velroyen
  forAll (genInstanceSmallerThanNode node) $ \inst ->
140 77ffd663 Helga Velroyen
  let inst' = inst { Instance.mem = Node.fMem node - Node.rMem node }
141 dddb2bc9 Helga Velroyen
  in (Node.addPri node inst' /=? Bad Types.FailN1)
142 77ffd663 Helga Velroyen
143 e1ee7d5a Iustin Pop
-- | Check that an instance add with too high memory or disk will be
144 e1ee7d5a Iustin Pop
-- rejected.
145 20bc5360 Iustin Pop
prop_addPriFM :: Node.Node -> Instance.Instance -> Property
146 20bc5360 Iustin Pop
prop_addPriFM node inst =
147 e1ee7d5a Iustin Pop
  Instance.mem inst >= Node.fMem node && not (Node.failN1 node) &&
148 e1ee7d5a Iustin Pop
  not (Instance.isOffline inst) ==>
149 dd77da99 Helga Velroyen
  (Node.addPri node inst'' ==? Bad Types.FailMem)
150 e1ee7d5a Iustin Pop
  where inst' = setInstanceSmallerThanNode node inst
151 e1ee7d5a Iustin Pop
        inst'' = inst' { Instance.mem = Instance.mem inst }
152 e1ee7d5a Iustin Pop
153 e1ee7d5a Iustin Pop
-- | Check that adding a primary instance with too much disk fails
154 e1ee7d5a Iustin Pop
-- with type FailDisk.
155 20bc5360 Iustin Pop
prop_addPriFD :: Node.Node -> Instance.Instance -> Property
156 20bc5360 Iustin Pop
prop_addPriFD node inst =
157 e1ee7d5a Iustin Pop
  forAll (elements Instance.localStorageTemplates) $ \dt ->
158 e1ee7d5a Iustin Pop
  Instance.dsk inst >= Node.fDsk node && not (Node.failN1 node) ==>
159 e1ee7d5a Iustin Pop
  let inst' = setInstanceSmallerThanNode node inst
160 e1ee7d5a Iustin Pop
      inst'' = inst' { Instance.dsk = Instance.dsk inst
161 e1ee7d5a Iustin Pop
                     , Instance.diskTemplate = dt }
162 dd77da99 Helga Velroyen
  in (Node.addPri node inst'' ==? Bad Types.FailDisk)
163 e1ee7d5a Iustin Pop
164 e1ee7d5a Iustin Pop
-- | Check that adding a primary instance with too many VCPUs fails
165 e1ee7d5a Iustin Pop
-- with type FailCPU.
166 20bc5360 Iustin Pop
prop_addPriFC :: Property
167 20bc5360 Iustin Pop
prop_addPriFC =
168 e1ee7d5a Iustin Pop
  forAll (choose (1, maxCpu)) $ \extra ->
169 e1ee7d5a Iustin Pop
  forAll genOnlineNode $ \node ->
170 e1ee7d5a Iustin Pop
  forAll (arbitrary `suchThat` Instance.notOffline) $ \inst ->
171 e1ee7d5a Iustin Pop
  let inst' = setInstanceSmallerThanNode node inst
172 e1ee7d5a Iustin Pop
      inst'' = inst' { Instance.vcpus = Node.availCpu node + extra }
173 e1ee7d5a Iustin Pop
  in case Node.addPri node inst'' of
174 a8038349 Iustin Pop
       Bad Types.FailCPU -> passTest
175 e1ee7d5a Iustin Pop
       v -> failTest $ "Expected OpFail FailCPU, but got " ++ show v
176 e1ee7d5a Iustin Pop
177 e1ee7d5a Iustin Pop
-- | Check that an instance add with too high memory or disk will be
178 e1ee7d5a Iustin Pop
-- rejected.
179 20bc5360 Iustin Pop
prop_addSec :: Node.Node -> Instance.Instance -> Int -> Property
180 20bc5360 Iustin Pop
prop_addSec node inst pdx =
181 e1ee7d5a Iustin Pop
  ((Instance.mem inst >= (Node.fMem node - Node.rMem node) &&
182 e1ee7d5a Iustin Pop
    not (Instance.isOffline inst)) ||
183 e1ee7d5a Iustin Pop
   Instance.dsk inst >= Node.fDsk node) &&
184 e1ee7d5a Iustin Pop
  not (Node.failN1 node) ==>
185 a8038349 Iustin Pop
      isBad (Node.addSec node inst pdx)
186 e1ee7d5a Iustin Pop
187 e1ee7d5a Iustin Pop
-- | Check that an offline instance with reasonable disk size but
188 e1ee7d5a Iustin Pop
-- extra mem/cpu can always be added.
189 20bc5360 Iustin Pop
prop_addOfflinePri :: NonNegative Int -> NonNegative Int -> Property
190 20bc5360 Iustin Pop
prop_addOfflinePri (NonNegative extra_mem) (NonNegative extra_cpu) =
191 e1ee7d5a Iustin Pop
  forAll genOnlineNode $ \node ->
192 e1ee7d5a Iustin Pop
  forAll (genInstanceSmallerThanNode node) $ \inst ->
193 e1ee7d5a Iustin Pop
  let inst' = inst { Instance.runSt = Types.AdminOffline
194 e1ee7d5a Iustin Pop
                   , Instance.mem = Node.availMem node + extra_mem
195 e1ee7d5a Iustin Pop
                   , Instance.vcpus = Node.availCpu node + extra_cpu }
196 e1ee7d5a Iustin Pop
  in case Node.addPri node inst' of
197 a8038349 Iustin Pop
       Ok _ -> passTest
198 e1ee7d5a Iustin Pop
       v -> failTest $ "Expected OpGood, but got: " ++ show v
199 e1ee7d5a Iustin Pop
200 e1ee7d5a Iustin Pop
-- | Check that an offline instance with reasonable disk size but
201 e1ee7d5a Iustin Pop
-- extra mem/cpu can always be added.
202 20bc5360 Iustin Pop
prop_addOfflineSec :: NonNegative Int -> NonNegative Int
203 20bc5360 Iustin Pop
                   -> Types.Ndx -> Property
204 20bc5360 Iustin Pop
prop_addOfflineSec (NonNegative extra_mem) (NonNegative extra_cpu) pdx =
205 e1ee7d5a Iustin Pop
  forAll genOnlineNode $ \node ->
206 e1ee7d5a Iustin Pop
  forAll (genInstanceSmallerThanNode node) $ \inst ->
207 e1ee7d5a Iustin Pop
  let inst' = inst { Instance.runSt = Types.AdminOffline
208 e1ee7d5a Iustin Pop
                   , Instance.mem = Node.availMem node + extra_mem
209 e1ee7d5a Iustin Pop
                   , Instance.vcpus = Node.availCpu node + extra_cpu
210 e1ee7d5a Iustin Pop
                   , Instance.diskTemplate = Types.DTDrbd8 }
211 e1ee7d5a Iustin Pop
  in case Node.addSec node inst' pdx of
212 a8038349 Iustin Pop
       Ok _ -> passTest
213 e1ee7d5a Iustin Pop
       v -> failTest $ "Expected OpGood/OpGood, but got: " ++ show v
214 e1ee7d5a Iustin Pop
215 e1ee7d5a Iustin Pop
-- | Checks for memory reservation changes.
216 20bc5360 Iustin Pop
prop_rMem :: Instance.Instance -> Property
217 20bc5360 Iustin Pop
prop_rMem inst =
218 e1ee7d5a Iustin Pop
  not (Instance.isOffline inst) ==>
219 e1ee7d5a Iustin Pop
  forAll (genOnlineNode `suchThat` ((> Types.unitMem) . Node.fMem)) $ \node ->
220 e1ee7d5a Iustin Pop
  -- ab = auto_balance, nb = non-auto_balance
221 e1ee7d5a Iustin Pop
  -- we use -1 as the primary node of the instance
222 e1ee7d5a Iustin Pop
  let inst' = inst { Instance.pNode = -1, Instance.autoBalance = True
223 e1ee7d5a Iustin Pop
                   , Instance.diskTemplate = Types.DTDrbd8 }
224 e1ee7d5a Iustin Pop
      inst_ab = setInstanceSmallerThanNode node inst'
225 e1ee7d5a Iustin Pop
      inst_nb = inst_ab { Instance.autoBalance = False }
226 e1ee7d5a Iustin Pop
      -- now we have the two instances, identical except the
227 e1ee7d5a Iustin Pop
      -- autoBalance attribute
228 e1ee7d5a Iustin Pop
      orig_rmem = Node.rMem node
229 e1ee7d5a Iustin Pop
      inst_idx = Instance.idx inst_ab
230 e1ee7d5a Iustin Pop
      node_add_ab = Node.addSec node inst_ab (-1)
231 e1ee7d5a Iustin Pop
      node_add_nb = Node.addSec node inst_nb (-1)
232 e1ee7d5a Iustin Pop
      node_del_ab = liftM (`Node.removeSec` inst_ab) node_add_ab
233 e1ee7d5a Iustin Pop
      node_del_nb = liftM (`Node.removeSec` inst_nb) node_add_nb
234 e1ee7d5a Iustin Pop
  in case (node_add_ab, node_add_nb, node_del_ab, node_del_nb) of
235 a8038349 Iustin Pop
       (Ok a_ab, Ok a_nb,
236 a8038349 Iustin Pop
        Ok d_ab, Ok d_nb) ->
237 e1ee7d5a Iustin Pop
         printTestCase "Consistency checks failed" $
238 e1ee7d5a Iustin Pop
           Node.rMem a_ab >  orig_rmem &&
239 e1ee7d5a Iustin Pop
           Node.rMem a_ab - orig_rmem == Instance.mem inst_ab &&
240 e1ee7d5a Iustin Pop
           Node.rMem a_nb == orig_rmem &&
241 e1ee7d5a Iustin Pop
           Node.rMem d_ab == orig_rmem &&
242 e1ee7d5a Iustin Pop
           Node.rMem d_nb == orig_rmem &&
243 e1ee7d5a Iustin Pop
           -- this is not related to rMem, but as good a place to
244 e1ee7d5a Iustin Pop
           -- test as any
245 e1ee7d5a Iustin Pop
           inst_idx `elem` Node.sList a_ab &&
246 e1ee7d5a Iustin Pop
           inst_idx `notElem` Node.sList d_ab
247 e1ee7d5a Iustin Pop
       x -> failTest $ "Failed to add/remove instances: " ++ show x
248 e1ee7d5a Iustin Pop
249 e1ee7d5a Iustin Pop
-- | Check mdsk setting.
250 20bc5360 Iustin Pop
prop_setMdsk :: Node.Node -> SmallRatio -> Bool
251 20bc5360 Iustin Pop
prop_setMdsk node mx =
252 e1ee7d5a Iustin Pop
  Node.loDsk node' >= 0 &&
253 e1ee7d5a Iustin Pop
  fromIntegral (Node.loDsk node') <= Node.tDsk node &&
254 e1ee7d5a Iustin Pop
  Node.availDisk node' >= 0 &&
255 e1ee7d5a Iustin Pop
  Node.availDisk node' <= Node.fDsk node' &&
256 e1ee7d5a Iustin Pop
  fromIntegral (Node.availDisk node') <= Node.tDsk node' &&
257 e1ee7d5a Iustin Pop
  Node.mDsk node' == mx'
258 e1ee7d5a Iustin Pop
    where node' = Node.setMdsk node mx'
259 e1ee7d5a Iustin Pop
          SmallRatio mx' = mx
260 e1ee7d5a Iustin Pop
261 e1ee7d5a Iustin Pop
-- Check tag maps
262 20bc5360 Iustin Pop
prop_tagMaps_idempotent :: Property
263 20bc5360 Iustin Pop
prop_tagMaps_idempotent =
264 e1ee7d5a Iustin Pop
  forAll genTags $ \tags ->
265 e1ee7d5a Iustin Pop
  Node.delTags (Node.addTags m tags) tags ==? m
266 e1ee7d5a Iustin Pop
    where m = Map.empty
267 e1ee7d5a Iustin Pop
268 20bc5360 Iustin Pop
prop_tagMaps_reject :: Property
269 20bc5360 Iustin Pop
prop_tagMaps_reject =
270 e1ee7d5a Iustin Pop
  forAll (genTags `suchThat` (not . null)) $ \tags ->
271 e1ee7d5a Iustin Pop
  let m = Node.addTags Map.empty tags
272 e1ee7d5a Iustin Pop
  in all (\t -> Node.rejectAddTags m [t]) tags
273 e1ee7d5a Iustin Pop
274 20bc5360 Iustin Pop
prop_showField :: Node.Node -> Property
275 20bc5360 Iustin Pop
prop_showField node =
276 e1ee7d5a Iustin Pop
  forAll (elements Node.defaultFields) $ \ field ->
277 e1ee7d5a Iustin Pop
  fst (Node.showHeader field) /= Types.unknownField &&
278 e1ee7d5a Iustin Pop
  Node.showField node field /= Types.unknownField
279 e1ee7d5a Iustin Pop
280 20bc5360 Iustin Pop
prop_computeGroups :: [Node.Node] -> Bool
281 20bc5360 Iustin Pop
prop_computeGroups nodes =
282 e1ee7d5a Iustin Pop
  let ng = Node.computeGroups nodes
283 e1ee7d5a Iustin Pop
      onlyuuid = map fst ng
284 e1ee7d5a Iustin Pop
  in length nodes == sum (map (length . snd) ng) &&
285 e1ee7d5a Iustin Pop
     all (\(guuid, ns) -> all ((== guuid) . Node.group) ns) ng &&
286 e1ee7d5a Iustin Pop
     length (nub onlyuuid) == length onlyuuid &&
287 e1ee7d5a Iustin Pop
     (null nodes || not (null ng))
288 e1ee7d5a Iustin Pop
289 e1ee7d5a Iustin Pop
-- Check idempotence of add/remove operations
290 20bc5360 Iustin Pop
prop_addPri_idempotent :: Property
291 20bc5360 Iustin Pop
prop_addPri_idempotent =
292 e1ee7d5a Iustin Pop
  forAll genOnlineNode $ \node ->
293 e1ee7d5a Iustin Pop
  forAll (genInstanceSmallerThanNode node) $ \inst ->
294 e1ee7d5a Iustin Pop
  case Node.addPri node inst of
295 a8038349 Iustin Pop
    Ok node' -> Node.removePri node' inst ==? node
296 e1ee7d5a Iustin Pop
    _ -> failTest "Can't add instance"
297 e1ee7d5a Iustin Pop
298 20bc5360 Iustin Pop
prop_addSec_idempotent :: Property
299 20bc5360 Iustin Pop
prop_addSec_idempotent =
300 e1ee7d5a Iustin Pop
  forAll genOnlineNode $ \node ->
301 e1ee7d5a Iustin Pop
  forAll (genInstanceSmallerThanNode node) $ \inst ->
302 e1ee7d5a Iustin Pop
  let pdx = Node.idx node + 1
303 e1ee7d5a Iustin Pop
      inst' = Instance.setPri inst pdx
304 e1ee7d5a Iustin Pop
      inst'' = inst' { Instance.diskTemplate = Types.DTDrbd8 }
305 e1ee7d5a Iustin Pop
  in case Node.addSec node inst'' pdx of
306 a8038349 Iustin Pop
       Ok node' -> Node.removeSec node' inst'' ==? node
307 e1ee7d5a Iustin Pop
       _ -> failTest "Can't add instance"
308 e1ee7d5a Iustin Pop
309 e09c1fa0 Iustin Pop
testSuite "HTools/Node"
310 20bc5360 Iustin Pop
            [ 'prop_setAlias
311 20bc5360 Iustin Pop
            , 'prop_setOffline
312 20bc5360 Iustin Pop
            , 'prop_setMcpu
313 77ffd663 Helga Velroyen
            , 'prop_setFmemGreater
314 77ffd663 Helga Velroyen
            , 'prop_setFmemExact
315 20bc5360 Iustin Pop
            , 'prop_setXmem
316 20bc5360 Iustin Pop
            , 'prop_addPriFM
317 20bc5360 Iustin Pop
            , 'prop_addPriFD
318 20bc5360 Iustin Pop
            , 'prop_addPriFC
319 77ffd663 Helga Velroyen
            , 'prop_addPri_NoN1Fail
320 20bc5360 Iustin Pop
            , 'prop_addSec
321 20bc5360 Iustin Pop
            , 'prop_addOfflinePri
322 20bc5360 Iustin Pop
            , 'prop_addOfflineSec
323 20bc5360 Iustin Pop
            , 'prop_rMem
324 20bc5360 Iustin Pop
            , 'prop_setMdsk
325 20bc5360 Iustin Pop
            , 'prop_tagMaps_idempotent
326 20bc5360 Iustin Pop
            , 'prop_tagMaps_reject
327 20bc5360 Iustin Pop
            , 'prop_showField
328 20bc5360 Iustin Pop
            , 'prop_computeGroups
329 20bc5360 Iustin Pop
            , 'prop_addPri_idempotent
330 20bc5360 Iustin Pop
            , 'prop_addSec_idempotent
331 e1ee7d5a Iustin Pop
            ]