1 {-# LANGUAGE TemplateHaskell #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 {-| Unittests for ganeti-htools.
10 Copyright (C) 2009, 2010, 2011, 2012 Google Inc.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 module Test.Ganeti.HTools.Instance
31 , genInstanceSmallerThanNode
32 , genInstanceMaybeBiggerThanNode
33 , genInstanceSmallerThan
34 , genInstanceOnNodeList
36 , Instance.Instance(..)
39 import Test.QuickCheck hiding (Result)
41 import Test.Ganeti.TestHelper
42 import Test.Ganeti.TestCommon
43 import Test.Ganeti.HTools.Types ()
45 import Ganeti.BasicTypes
46 import qualified Ganeti.HTools.Instance as Instance
47 import qualified Ganeti.HTools.Node as Node
48 import qualified Ganeti.HTools.Container as Container
49 import qualified Ganeti.HTools.Loader as Loader
50 import qualified Ganeti.HTools.Types as Types
52 -- * Arbitrary instances
54 -- | Generates a random instance with maximum disk/mem/cpu values.
55 genInstanceSmallerThan :: Int -> Int -> Int -> Gen Instance.Instance
56 genInstanceSmallerThan lim_mem lim_dsk lim_cpu = do
58 mem <- choose (0, lim_mem)
59 dsk <- choose (0, lim_dsk)
63 vcpus <- choose (0, lim_cpu)
66 let disk = Instance.Disk dsk spindles
67 return $ Instance.create
68 name mem dsk [disk] vcpus run_st [] True pn sn dt 1 []
70 -- | Generates an instance smaller than a node.
71 genInstanceSmallerThanNode :: Node.Node -> Gen Instance.Instance
72 genInstanceSmallerThanNode node =
73 genInstanceSmallerThan (Node.availMem node `div` 2)
74 (Node.availDisk node `div` 2)
75 (Node.availCpu node `div` 2)
77 -- | Generates an instance possibly bigger than a node.
78 genInstanceMaybeBiggerThanNode :: Node.Node -> Gen Instance.Instance
79 genInstanceMaybeBiggerThanNode node =
80 genInstanceSmallerThan (Node.availMem node + Types.unitMem * 2)
81 (Node.availDisk node + Types.unitDsk * 3)
82 (Node.availCpu node + Types.unitCpu * 4)
84 -- | Generates an instance with nodes on a node list.
85 -- The following rules are respected:
86 -- 1. The instance is never bigger than its primary node
87 -- 2. If possible the instance has different pnode and snode
88 -- 3. Else disk templates which require secondary nodes are disabled
89 genInstanceOnNodeList :: Node.List -> Gen Instance.Instance
90 genInstanceOnNodeList nl = do
91 let nsize = Container.size nl
92 pnode <- choose (0, nsize-1)
93 let (snodefilter, dtfilter) =
95 then ((/= pnode), const True)
96 else (const True, not . Instance.hasSecondary)
97 snode <- choose (0, nsize-1) `suchThat` snodefilter
98 i <- genInstanceSmallerThanNode (Container.find pnode nl) `suchThat` dtfilter
99 return $ i { Instance.pNode = pnode, Instance.sNode = snode }
101 -- | Generates an instance list given an instance generator.
102 genInstanceList :: Gen Instance.Instance -> Gen Instance.List
103 genInstanceList igen = fmap (snd . Loader.assignIndices) names_instances
104 where names_instances =
105 (fmap . map) (\n -> (Instance.name n, n)) $ listOf igen
107 -- let's generate a random instance
108 instance Arbitrary Instance.Instance where
109 arbitrary = genInstanceSmallerThan maxMem maxDsk maxCpu
113 -- Simple instance tests, we only have setter/getters
115 prop_creat :: Instance.Instance -> Property
117 Instance.name inst ==? Instance.alias inst
119 prop_setIdx :: Instance.Instance -> Types.Idx -> Property
120 prop_setIdx inst idx =
121 Instance.idx (Instance.setIdx inst idx) ==? idx
123 prop_setName :: Instance.Instance -> String -> Bool
124 prop_setName inst name =
125 Instance.name newinst == name &&
126 Instance.alias newinst == name
127 where newinst = Instance.setName inst name
129 prop_setAlias :: Instance.Instance -> String -> Bool
130 prop_setAlias inst name =
131 Instance.name newinst == Instance.name inst &&
132 Instance.alias newinst == name
133 where newinst = Instance.setAlias inst name
135 prop_setPri :: Instance.Instance -> Types.Ndx -> Property
136 prop_setPri inst pdx =
137 Instance.pNode (Instance.setPri inst pdx) ==? pdx
139 prop_setSec :: Instance.Instance -> Types.Ndx -> Property
140 prop_setSec inst sdx =
141 Instance.sNode (Instance.setSec inst sdx) ==? sdx
143 prop_setBoth :: Instance.Instance -> Types.Ndx -> Types.Ndx -> Bool
144 prop_setBoth inst pdx sdx =
145 Instance.pNode si == pdx && Instance.sNode si == sdx
146 where si = Instance.setBoth inst pdx sdx
148 prop_shrinkMG :: Instance.Instance -> Property
150 Instance.mem inst >= 2 * Types.unitMem ==>
151 case Instance.shrinkByType inst Types.FailMem of
152 Ok inst' -> Instance.mem inst' ==? Instance.mem inst - Types.unitMem
153 Bad msg -> failTest msg
155 prop_shrinkMF :: Instance.Instance -> Property
157 forAll (choose (0, 2 * Types.unitMem - 1)) $ \mem ->
158 let inst' = inst { Instance.mem = mem}
159 in isBad $ Instance.shrinkByType inst' Types.FailMem
161 prop_shrinkCG :: Instance.Instance -> Property
163 Instance.vcpus inst >= 2 * Types.unitCpu ==>
164 case Instance.shrinkByType inst Types.FailCPU of
165 Ok inst' -> Instance.vcpus inst' ==? Instance.vcpus inst - Types.unitCpu
166 Bad msg -> failTest msg
168 prop_shrinkCF :: Instance.Instance -> Property
170 forAll (choose (0, 2 * Types.unitCpu - 1)) $ \vcpus ->
171 let inst' = inst { Instance.vcpus = vcpus }
172 in isBad $ Instance.shrinkByType inst' Types.FailCPU
174 prop_shrinkDG :: Instance.Instance -> Property
176 Instance.dsk inst >= 2 * Types.unitDsk ==>
177 case Instance.shrinkByType inst Types.FailDisk of
178 Ok inst' -> Instance.dsk inst' ==? Instance.dsk inst - Types.unitDsk
179 Bad msg -> failTest msg
181 prop_shrinkDF :: Instance.Instance -> Property
183 forAll (choose (0, 2 * Types.unitDsk - 1)) $ \dsk ->
184 let inst' = inst { Instance.dsk = dsk }
185 in isBad $ Instance.shrinkByType inst' Types.FailDisk
187 prop_setMovable :: Instance.Instance -> Bool -> Property
188 prop_setMovable inst m =
189 Instance.movable inst' ==? m
190 where inst' = Instance.setMovable inst m
192 testSuite "HTools/Instance"