Statistics
| Branch: | Tag: | Revision:

root / test / hs / Test / Ganeti / HTools / Types.hs @ 87f15934

History | View | Annotate | Download (6.9 kB)

1
{-# LANGUAGE TemplateHaskell, FlexibleInstances, TypeSynonymInstances #-}
2
{-# OPTIONS_GHC -fno-warn-orphans #-}
3

    
4
{-| Unittests for ganeti-htools.
5

    
6
-}
7

    
8
{-
9

    
10
Copyright (C) 2009, 2010, 2011, 2012, 2013 Google Inc.
11

    
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.
16

    
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.
21

    
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
25
02110-1301, USA.
26

    
27
-}
28

    
29
module Test.Ganeti.HTools.Types
30
  ( testHTools_Types
31
  , Types.AllocPolicy(..)
32
  , Types.DiskTemplate(..)
33
  , Types.FailMode(..)
34
  , Types.ISpec(..)
35
  , Types.IPolicy(..)
36
  , nullIPolicy
37
  ) where
38

    
39
import Test.QuickCheck hiding (Result)
40
import Test.HUnit
41

    
42
import Control.Applicative
43
import Control.Monad (replicateM)
44

    
45
import Test.Ganeti.TestHelper
46
import Test.Ganeti.TestCommon
47
import Test.Ganeti.TestHTools
48
import Test.Ganeti.Types (allDiskTemplates)
49

    
50
import Ganeti.BasicTypes
51
import qualified Ganeti.Constants as C
52
import Ganeti.ConstantUtils
53
import qualified Ganeti.HTools.Types as Types
54

    
55
{-# ANN module "HLint: ignore Use camelCase" #-}
56

    
57
-- * Helpers
58

    
59
-- * Arbitrary instance
60

    
61
$(genArbitrary ''Types.FailMode)
62

    
63
instance Arbitrary a => Arbitrary (Types.OpResult a) where
64
  arbitrary = arbitrary >>= \c ->
65
              if c
66
                then Ok  <$> arbitrary
67
                else Bad <$> arbitrary
68

    
69
instance Arbitrary Types.ISpec where
70
  arbitrary = do
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
83
                       }
84

    
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
100
                     }
101

    
102
genMinMaxISpecs :: Gen Types.MinMaxISpecs
103
genMinMaxISpecs = do
104
  imin <- arbitrary
105
  imax <- genBiggerISpec imin
106
  return Types.MinMaxISpecs { Types.minMaxISpecsMinSpec = imin
107
                             , Types.minMaxISpecsMaxSpec = imax
108
                             }
109

    
110
instance Arbitrary Types.MinMaxISpecs where
111
  arbitrary = genMinMaxISpecs
112

    
113
genMinMaxStdISpecs :: Gen (Types.MinMaxISpecs, Types.ISpec)
114
genMinMaxStdISpecs = do
115
  imin <- arbitrary
116
  istd <- genBiggerISpec imin
117
  imax <- genBiggerISpec istd
118
  return (Types.MinMaxISpecs { Types.minMaxISpecsMinSpec = imin
119
                             , Types.minMaxISpecsMaxSpec = imax
120
                             },
121
          istd)
122

    
123
genIPolicySpecs :: Gen ([Types.MinMaxISpecs], Types.ISpec)
124
genIPolicySpecs = do
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)
131

    
132

    
133
instance Arbitrary Types.IPolicy where
134
  arbitrary = do
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
145
                         }
146

    
147
-- * Test cases
148

    
149
prop_ISpec_serialisation :: Types.ISpec -> Property
150
prop_ISpec_serialisation = testSerialisation
151

    
152
prop_IPolicy_serialisation :: Types.IPolicy -> Property
153
prop_IPolicy_serialisation = testSerialisation
154

    
155
prop_opToResult :: Types.OpResult Int -> Property
156
prop_opToResult op =
157
  case op of
158
    Bad _ -> printTestCase ("expected bad but got " ++ show r) $ isBad r
159
    Ok v  -> case r of
160
               Bad msg -> failTest ("expected Ok but got Bad " ++ msg)
161
               Ok v' -> v ==? v'
162
  where r = Types.opToResult op
163

    
164
prop_eitherToResult :: Either String Int -> Bool
165
prop_eitherToResult ei =
166
  case ei of
167
    Left _ -> isBad r
168
    Right v -> case r of
169
                 Bad _ -> False
170
                 Ok v' -> v == v'
171
    where r = eitherToResult ei :: Result Int
172

    
173
-- | Test 'AutoRepairType' ordering is as expected and consistent with Python
174
-- codebase.
175
case_AutoRepairType_sort :: Assertion
176
case_AutoRepairType_sort = do
177
  let expected = [ Types.ArFixStorage
178
                 , Types.ArMigrate
179
                 , Types.ArFailover
180
                 , Types.ArReinstall
181
                 ]
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
185

    
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
193

    
194
testSuite "HTools/Types"
195
            [ 'prop_ISpec_serialisation
196
            , 'prop_IPolicy_serialisation
197
            , 'prop_opToResult
198
            , 'prop_eitherToResult
199
            , 'case_AutoRepairType_sort
200
            , 'case_AutoRepairResult_pyequiv
201
            ]