1 {-# LANGUAGE TemplateHaskell, FlexibleInstances, TypeSynonymInstances #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 {-| Unittests for ganeti-htools.
10 Copyright (C) 2009, 2010, 2011, 2012, 2013 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.Types
31 , Types.AllocPolicy(..)
32 , Types.DiskTemplate(..)
39 import Test.QuickCheck hiding (Result)
42 import Control.Applicative
43 import Control.Monad (replicateM)
45 import Test.Ganeti.TestHelper
46 import Test.Ganeti.TestCommon
47 import Test.Ganeti.TestHTools
48 import Test.Ganeti.Types (allDiskTemplates)
50 import Ganeti.BasicTypes
51 import qualified Ganeti.Constants as C
52 import Ganeti.ConstantUtils
53 import qualified Ganeti.HTools.Types as Types
55 {-# ANN module "HLint: ignore Use camelCase" #-}
59 -- * Arbitrary instance
61 $(genArbitrary ''Types.FailMode)
63 instance Arbitrary a => Arbitrary (Types.OpResult a) where
64 arbitrary = arbitrary >>= \c ->
67 else Bad <$> arbitrary
69 instance Arbitrary Types.ISpec where
71 mem_s <- arbitrary::Gen (NonNegative Int)
72 dsk_c <- arbitrary::Gen (NonNegative Int)
73 dsk_s <- arbitrary::Gen (NonNegative Int)
74 cpu_c <- arbitrary::Gen (NonNegative Int)
75 nic_c <- arbitrary::Gen (NonNegative Int)
76 su <- arbitrary::Gen (NonNegative Int)
77 return Types.ISpec { Types.iSpecMemorySize = fromIntegral mem_s
78 , Types.iSpecCpuCount = fromIntegral cpu_c
79 , Types.iSpecDiskSize = fromIntegral dsk_s
80 , Types.iSpecDiskCount = fromIntegral dsk_c
81 , Types.iSpecNicCount = fromIntegral nic_c
82 , Types.iSpecSpindleUse = fromIntegral su
85 -- | Generates an ispec bigger than the given one.
86 genBiggerISpec :: Types.ISpec -> Gen Types.ISpec
87 genBiggerISpec imin = do
88 mem_s <- choose (Types.iSpecMemorySize imin, maxBound)
89 dsk_c <- choose (Types.iSpecDiskCount imin, maxBound)
90 dsk_s <- choose (Types.iSpecDiskSize imin, maxBound)
91 cpu_c <- choose (Types.iSpecCpuCount imin, maxBound)
92 nic_c <- choose (Types.iSpecNicCount imin, maxBound)
93 su <- choose (Types.iSpecSpindleUse imin, maxBound)
94 return Types.ISpec { Types.iSpecMemorySize = fromIntegral mem_s
95 , Types.iSpecCpuCount = fromIntegral cpu_c
96 , Types.iSpecDiskSize = fromIntegral dsk_s
97 , Types.iSpecDiskCount = fromIntegral dsk_c
98 , Types.iSpecNicCount = fromIntegral nic_c
99 , Types.iSpecSpindleUse = fromIntegral su
102 genMinMaxISpecs :: Gen Types.MinMaxISpecs
105 imax <- genBiggerISpec imin
106 return Types.MinMaxISpecs { Types.minMaxISpecsMinSpec = imin
107 , Types.minMaxISpecsMaxSpec = imax
110 instance Arbitrary Types.MinMaxISpecs where
111 arbitrary = genMinMaxISpecs
113 genMinMaxStdISpecs :: Gen (Types.MinMaxISpecs, Types.ISpec)
114 genMinMaxStdISpecs = do
116 istd <- genBiggerISpec imin
117 imax <- genBiggerISpec istd
118 return (Types.MinMaxISpecs { Types.minMaxISpecsMinSpec = imin
119 , Types.minMaxISpecsMaxSpec = imax
123 genIPolicySpecs :: Gen ([Types.MinMaxISpecs], Types.ISpec)
125 num_mm <- choose (1, 6) -- 6 is just an arbitrary limit
126 std_compl <- choose (1, num_mm)
127 mm_head <- replicateM (std_compl - 1) genMinMaxISpecs
128 (mm_middle, istd) <- genMinMaxStdISpecs
129 mm_tail <- replicateM (num_mm - std_compl) genMinMaxISpecs
130 return (mm_head ++ (mm_middle : mm_tail), istd)
133 instance Arbitrary Types.IPolicy where
135 (iminmax, istd) <- genIPolicySpecs
136 num_tmpl <- choose (0, length allDiskTemplates)
137 dts <- genUniquesList num_tmpl arbitrary
138 vcpu_ratio <- choose (1.0, maxVcpuRatio)
139 spindle_ratio <- choose (1.0, maxSpindleRatio)
140 return Types.IPolicy { Types.iPolicyMinMaxISpecs = iminmax
141 , Types.iPolicyStdSpec = istd
142 , Types.iPolicyDiskTemplates = dts
143 , Types.iPolicyVcpuRatio = vcpu_ratio
144 , Types.iPolicySpindleRatio = spindle_ratio
149 prop_ISpec_serialisation :: Types.ISpec -> Property
150 prop_ISpec_serialisation = testSerialisation
152 prop_IPolicy_serialisation :: Types.IPolicy -> Property
153 prop_IPolicy_serialisation = testSerialisation
155 prop_opToResult :: Types.OpResult Int -> Property
158 Bad _ -> printTestCase ("expected bad but got " ++ show r) $ isBad r
160 Bad msg -> failTest ("expected Ok but got Bad " ++ msg)
162 where r = Types.opToResult op
164 prop_eitherToResult :: Either String Int -> Bool
165 prop_eitherToResult ei =
171 where r = eitherToResult ei
173 -- | Test 'AutoRepairType' ordering is as expected and consistent with Python
175 case_AutoRepairType_sort :: Assertion
176 case_AutoRepairType_sort = do
177 let expected = [ Types.ArFixStorage
182 all_hs_raw = mkSet $ map Types.autoRepairTypeToRaw [minBound..maxBound]
183 assertEqual "Haskell order" expected [minBound..maxBound]
184 assertEqual "consistent with Python" C.autoRepairAllTypes all_hs_raw
186 -- | Test 'AutoRepairResult' type is equivalent with Python codebase.
187 case_AutoRepairResult_pyequiv :: Assertion
188 case_AutoRepairResult_pyequiv = do
189 let all_py_results = C.autoRepairAllResults
190 all_hs_results = mkSet $
191 map Types.autoRepairResultToRaw [minBound..maxBound]
192 assertEqual "for AutoRepairResult equivalence" all_py_results all_hs_results
194 testSuite "HTools/Types"
195 [ 'prop_ISpec_serialisation
196 , 'prop_IPolicy_serialisation
198 , 'prop_eitherToResult
199 , 'case_AutoRepairType_sort
200 , 'case_AutoRepairResult_pyequiv