Revision 20bc5360

b/htest/Test/Ganeti/Confd/Utils.hs
64 64
-- | Test that signing messages and checking signatures is correct. It
65 65
-- also tests, indirectly the serialisation of messages so we don't
66 66
-- need a separate test for that.
67
prop_ConfdUtils_req_sign :: Hash.HashKey        -- ^ The hash key
68
                    -> NonNegative Integer -- ^ The base timestamp
69
                    -> Positive Integer    -- ^ Delta for out of window
70
                    -> Bool                -- ^ Whether delta should be + or -
71
                    -> Confd.ConfdRequest
72
                    -> Property
73
prop_ConfdUtils_req_sign key (NonNegative timestamp) (Positive bad_delta)
67
prop_req_sign :: Hash.HashKey        -- ^ The hash key
68
              -> NonNegative Integer -- ^ The base timestamp
69
              -> Positive Integer    -- ^ Delta for out of window
70
              -> Bool                -- ^ Whether delta should be + or -
71
              -> Confd.ConfdRequest
72
              -> Property
73
prop_req_sign key (NonNegative timestamp) (Positive bad_delta)
74 74
                         pm crq =
75 75
  forAll (choose (0, fromIntegral C.confdMaxClockSkew)) $ \ good_delta ->
76 76
  let encoded = J.encode crq
......
89 89

  
90 90
-- | Tests that signing with a different key fails detects failure
91 91
-- correctly.
92
prop_ConfdUtils_bad_key :: String             -- ^ Salt
93
                   -> Confd.ConfdRequest -- ^ Request
94
                   -> Property
95
prop_ConfdUtils_bad_key salt crq =
92
prop_bad_key :: String             -- ^ Salt
93
             -> Confd.ConfdRequest -- ^ Request
94
             -> Property
95
prop_bad_key salt crq =
96 96
  -- fixme: we hardcode here the expected length of a sha1 key, as
97 97
  -- otherwise we could have two short keys that differ only in the
98 98
  -- final zero elements count, and those will be expanded to be the
......
106 106
     Confd.Utils.parseRequest key_verify encoded
107 107

  
108 108
testSuite "ConfdUtils"
109
  [ 'prop_ConfdUtils_req_sign
110
  , 'prop_ConfdUtils_bad_key
109
  [ 'prop_req_sign
110
  , 'prop_bad_key
111 111
  ]
b/htest/Test/Ganeti/HTools/CLI.hs
43 43
import qualified Ganeti.HTools.Types as Types
44 44

  
45 45
-- | Test correct parsing.
46
prop_CLI_parseISpec :: String -> Int -> Int -> Int -> Property
47
prop_CLI_parseISpec descr dsk mem cpu =
46
prop_parseISpec :: String -> Int -> Int -> Int -> Property
47
prop_parseISpec descr dsk mem cpu =
48 48
  let str = printf "%d,%d,%d" dsk mem cpu::String
49 49
  in CLI.parseISpecString descr str ==? Types.Ok (Types.RSpec cpu mem dsk)
50 50

  
51 51
-- | Test parsing failure due to wrong section count.
52
prop_CLI_parseISpecFail :: String -> Property
53
prop_CLI_parseISpecFail descr =
52
prop_parseISpecFail :: String -> Property
53
prop_parseISpecFail descr =
54 54
  forAll (choose (0,100) `suchThat` ((/=) 3)) $ \nelems ->
55 55
  forAll (replicateM nelems arbitrary) $ \values ->
56 56
  let str = intercalate "," $ map show (values::[Int])
......
59 59
       _ -> property True
60 60

  
61 61
-- | Test parseYesNo.
62
prop_CLI_parseYesNo :: Bool -> Bool -> [Char] -> Property
63
prop_CLI_parseYesNo def testval val =
62
prop_parseYesNo :: Bool -> Bool -> [Char] -> Property
63
prop_parseYesNo def testval val =
64 64
  forAll (elements [val, "yes", "no"]) $ \actual_val ->
65 65
  if testval
66 66
    then CLI.parseYesNo def Nothing ==? Types.Ok def
......
84 84
           Right (options, _) -> fn options ==? Just val
85 85

  
86 86
-- | Test a few string arguments.
87
prop_CLI_StringArg :: [Char] -> Property
88
prop_CLI_StringArg argument =
87
prop_StringArg :: [Char] -> Property
88
prop_StringArg argument =
89 89
  let args = [ (CLI.oDataFile,      CLI.optDataFile)
90 90
             , (CLI.oDynuFile,      CLI.optDynuFile)
91 91
             , (CLI.oSaveCluster,   CLI.optSaveCluster)
......
109 109

  
110 110
-- | Test that all binaries support some common options. There is
111 111
-- nothing actually random about this test...
112
prop_CLI_stdopts :: Property
113
prop_CLI_stdopts =
112
prop_stdopts :: Property
113
prop_stdopts =
114 114
  let params = ["-h", "--help", "-V", "--version"]
115 115
      opts = map (\(name, (_, o)) -> (name, o)) Program.personalities
116 116
      -- apply checkEarlyExit across the cartesian product of params and opts
117 117
  in conjoin [checkEarlyExit n o p | p <- params, (n, o) <- opts]
118 118

  
119 119
testSuite "CLI"
120
          [ 'prop_CLI_parseISpec
121
          , 'prop_CLI_parseISpecFail
122
          , 'prop_CLI_parseYesNo
123
          , 'prop_CLI_StringArg
124
          , 'prop_CLI_stdopts
120
          [ 'prop_parseISpec
121
          , 'prop_parseISpecFail
122
          , 'prop_parseYesNo
123
          , 'prop_StringArg
124
          , 'prop_stdopts
125 125
          ]
b/htest/Test/Ganeti/HTools/Cluster.hs
98 98

  
99 99
-- | Check that the cluster score is close to zero for a homogeneous
100 100
-- cluster.
101
prop_Cluster_Score_Zero :: Node.Node -> Property
102
prop_Cluster_Score_Zero node =
101
prop_Score_Zero :: Node.Node -> Property
102
prop_Score_Zero node =
103 103
  forAll (choose (1, 1024)) $ \count ->
104 104
    (not (Node.offline node) && not (Node.failN1 node) && (count > 0) &&
105 105
     (Node.tDsk node > 0) && (Node.tMem node > 0)) ==>
......
111 111
  in score <= 1e-12
112 112

  
113 113
-- | Check that cluster stats are sane.
114
prop_Cluster_CStats_sane :: Property
115
prop_Cluster_CStats_sane =
114
prop_CStats_sane :: Property
115
prop_CStats_sane =
116 116
  forAll (choose (1, 1024)) $ \count ->
117 117
  forAll genOnlineNode $ \node ->
118 118
  let fn = Node.buildPeers node Container.empty
......
124 124

  
125 125
-- | Check that one instance is allocated correctly, without
126 126
-- rebalances needed.
127
prop_Cluster_Alloc_sane :: Instance.Instance -> Property
128
prop_Cluster_Alloc_sane inst =
127
prop_Alloc_sane :: Instance.Instance -> Property
128
prop_Alloc_sane inst =
129 129
  forAll (choose (5, 20)) $ \count ->
130 130
  forAll genOnlineNode $ \node ->
131 131
  let (nl, il, inst') = makeSmallEmptyCluster node count inst
......
145 145
-- instance spec via tiered allocation (whatever the original instance
146 146
-- spec), on either one or two nodes. Furthermore, we test that
147 147
-- computed allocation statistics are correct.
148
prop_Cluster_CanTieredAlloc :: Instance.Instance -> Property
149
prop_Cluster_CanTieredAlloc inst =
148
prop_CanTieredAlloc :: Instance.Instance -> Property
149
prop_CanTieredAlloc inst =
150 150
  forAll (choose (2, 5)) $ \count ->
151 151
  forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node ->
152 152
  let nl = makeSmallCluster node count
......
193 193

  
194 194
-- | Checks that on a 4-8 node cluster, once we allocate an instance,
195 195
-- we can also relocate it.
196
prop_Cluster_AllocRelocate :: Property
197
prop_Cluster_AllocRelocate =
196
prop_AllocRelocate :: Property
197
prop_AllocRelocate =
198 198
  forAll (choose (4, 8)) $ \count ->
199 199
  forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node ->
200 200
  forAll (genInstanceSmallerThanNode node `suchThat` isMirrored) $ \inst ->
......
235 235

  
236 236
-- | Checks that on a 4-8 node cluster, once we allocate an instance,
237 237
-- we can also node-evacuate it.
238
prop_Cluster_AllocEvacuate :: Property
239
prop_Cluster_AllocEvacuate =
238
prop_AllocEvacuate :: Property
239
prop_AllocEvacuate =
240 240
  forAll (choose (4, 8)) $ \count ->
241 241
  forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node ->
242 242
  forAll (genInstanceSmallerThanNode node `suchThat` isMirrored) $ \inst ->
......
252 252
-- | Checks that on a 4-8 node cluster with two node groups, once we
253 253
-- allocate an instance on the first node group, we can also change
254 254
-- its group.
255
prop_Cluster_AllocChangeGroup :: Property
256
prop_Cluster_AllocChangeGroup =
255
prop_AllocChangeGroup :: Property
256
prop_AllocChangeGroup =
257 257
  forAll (choose (4, 8)) $ \count ->
258 258
  forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node ->
259 259
  forAll (genInstanceSmallerThanNode node `suchThat` isMirrored) $ \inst ->
......
274 274

  
275 275
-- | Check that allocating multiple instances on a cluster, then
276 276
-- adding an empty node, results in a valid rebalance.
277
prop_Cluster_AllocBalance :: Property
278
prop_Cluster_AllocBalance =
277
prop_AllocBalance :: Property
278
prop_AllocBalance =
279 279
  forAll (genNode (Just 5) (Just 128)) $ \node ->
280 280
  forAll (choose (3, 5)) $ \count ->
281 281
  not (Node.offline node) && not (Node.failN1 node) ==>
......
296 296
            canBalance tbl True True False
297 297

  
298 298
-- | Checks consistency.
299
prop_Cluster_CheckConsistency :: Node.Node -> Instance.Instance -> Bool
300
prop_Cluster_CheckConsistency node inst =
299
prop_CheckConsistency :: Node.Node -> Instance.Instance -> Bool
300
prop_CheckConsistency node inst =
301 301
  let nl = makeSmallCluster node 3
302 302
      [node1, node2, node3] = Container.elems nl
303 303
      node3' = node3 { Node.group = 1 }
......
311 311
     (not . null $ ccheck [(0, inst3)])
312 312

  
313 313
-- | For now, we only test that we don't lose instances during the split.
314
prop_Cluster_SplitCluster :: Node.Node -> Instance.Instance -> Property
315
prop_Cluster_SplitCluster node inst =
314
prop_SplitCluster :: Node.Node -> Instance.Instance -> Property
315
prop_SplitCluster node inst =
316 316
  forAll (choose (0, 100)) $ \icnt ->
317 317
  let nl = makeSmallCluster node 2
318 318
      (nl', il') = foldl (\(ns, is) _ -> assignInstance ns is inst 0 1)
......
339 339
-- times, and generates a random instance that can be allocated on
340 340
-- this mini-cluster; it then checks that after applying a policy that
341 341
-- the instance doesn't fits, the allocation fails.
342
prop_Cluster_AllocPolicy :: Node.Node -> Property
343
prop_Cluster_AllocPolicy node =
342
prop_AllocPolicy :: Node.Node -> Property
343
prop_AllocPolicy node =
344 344
  -- rqn is the required nodes (1 or 2)
345 345
  forAll (choose (1, 2)) $ \rqn ->
346 346
  forAll (choose (5, 20)) $ \count ->
......
353 353
  in not $ canAllocOn nl rqn inst
354 354

  
355 355
testSuite "Cluster"
356
            [ 'prop_Cluster_Score_Zero
357
            , 'prop_Cluster_CStats_sane
358
            , 'prop_Cluster_Alloc_sane
359
            , 'prop_Cluster_CanTieredAlloc
360
            , 'prop_Cluster_AllocRelocate
361
            , 'prop_Cluster_AllocEvacuate
362
            , 'prop_Cluster_AllocChangeGroup
363
            , 'prop_Cluster_AllocBalance
364
            , 'prop_Cluster_CheckConsistency
365
            , 'prop_Cluster_SplitCluster
366
            , 'prop_Cluster_AllocPolicy
356
            [ 'prop_Score_Zero
357
            , 'prop_CStats_sane
358
            , 'prop_Alloc_sane
359
            , 'prop_CanTieredAlloc
360
            , 'prop_AllocRelocate
361
            , 'prop_AllocEvacuate
362
            , 'prop_AllocChangeGroup
363
            , 'prop_AllocBalance
364
            , 'prop_CheckConsistency
365
            , 'prop_SplitCluster
366
            , 'prop_AllocPolicy
367 367
            ]
b/htest/Test/Ganeti/HTools/Container.hs
41 41
import qualified Ganeti.HTools.Node as Node
42 42

  
43 43
-- we silence the following due to hlint bug fixed in later versions
44
{-# ANN prop_Container_addTwo "HLint: ignore Avoid lambda" #-}
45
prop_Container_addTwo :: [Container.Key] -> Int -> Int -> Bool
46
prop_Container_addTwo cdata i1 i2 =
44
{-# ANN prop_addTwo "HLint: ignore Avoid lambda" #-}
45
prop_addTwo :: [Container.Key] -> Int -> Int -> Bool
46
prop_addTwo cdata i1 i2 =
47 47
  fn i1 i2 cont == fn i2 i1 cont &&
48 48
  fn i1 i2 cont == fn i1 i2 (fn i1 i2 cont)
49 49
    where cont = foldl (\c x -> Container.add x x c) Container.empty cdata
50 50
          fn x1 x2 = Container.addTwo x1 x1 x2 x2
51 51

  
52
prop_Container_nameOf :: Node.Node -> Property
53
prop_Container_nameOf node =
52
prop_nameOf :: Node.Node -> Property
53
prop_nameOf node =
54 54
  let nl = makeSmallCluster node 1
55 55
      fnode = head (Container.elems nl)
56 56
  in Container.nameOf nl (Node.idx fnode) ==? Node.name fnode
......
58 58
-- | We test that in a cluster, given a random node, we can find it by
59 59
-- its name and alias, as long as all names and aliases are unique,
60 60
-- and that we fail to find a non-existing name.
61
prop_Container_findByName :: Property
62
prop_Container_findByName =
61
prop_findByName :: Property
62
prop_findByName =
63 63
  forAll (genNode (Just 1) Nothing) $ \node ->
64 64
  forAll (choose (1, 20)) $ \ cnt ->
65 65
  forAll (choose (0, cnt - 1)) $ \ fidx ->
......
80 80
       (isNothing (Container.findByName nl' othername))
81 81

  
82 82
testSuite "Container"
83
            [ 'prop_Container_addTwo
84
            , 'prop_Container_nameOf
85
            , 'prop_Container_findByName
83
            [ 'prop_addTwo
84
            , 'prop_nameOf
85
            , 'prop_findByName
86 86
            ]
b/htest/Test/Ganeti/HTools/Instance.hs
72 72

  
73 73
-- Simple instance tests, we only have setter/getters
74 74

  
75
prop_Instance_creat :: Instance.Instance -> Property
76
prop_Instance_creat inst =
75
prop_creat :: Instance.Instance -> Property
76
prop_creat inst =
77 77
  Instance.name inst ==? Instance.alias inst
78 78

  
79
prop_Instance_setIdx :: Instance.Instance -> Types.Idx -> Property
80
prop_Instance_setIdx inst idx =
79
prop_setIdx :: Instance.Instance -> Types.Idx -> Property
80
prop_setIdx inst idx =
81 81
  Instance.idx (Instance.setIdx inst idx) ==? idx
82 82

  
83
prop_Instance_setName :: Instance.Instance -> String -> Bool
84
prop_Instance_setName inst name =
83
prop_setName :: Instance.Instance -> String -> Bool
84
prop_setName inst name =
85 85
  Instance.name newinst == name &&
86 86
  Instance.alias newinst == name
87 87
    where newinst = Instance.setName inst name
88 88

  
89
prop_Instance_setAlias :: Instance.Instance -> String -> Bool
90
prop_Instance_setAlias inst name =
89
prop_setAlias :: Instance.Instance -> String -> Bool
90
prop_setAlias inst name =
91 91
  Instance.name newinst == Instance.name inst &&
92 92
  Instance.alias newinst == name
93 93
    where newinst = Instance.setAlias inst name
94 94

  
95
prop_Instance_setPri :: Instance.Instance -> Types.Ndx -> Property
96
prop_Instance_setPri inst pdx =
95
prop_setPri :: Instance.Instance -> Types.Ndx -> Property
96
prop_setPri inst pdx =
97 97
  Instance.pNode (Instance.setPri inst pdx) ==? pdx
98 98

  
99
prop_Instance_setSec :: Instance.Instance -> Types.Ndx -> Property
100
prop_Instance_setSec inst sdx =
99
prop_setSec :: Instance.Instance -> Types.Ndx -> Property
100
prop_setSec inst sdx =
101 101
  Instance.sNode (Instance.setSec inst sdx) ==? sdx
102 102

  
103
prop_Instance_setBoth :: Instance.Instance -> Types.Ndx -> Types.Ndx -> Bool
104
prop_Instance_setBoth inst pdx sdx =
103
prop_setBoth :: Instance.Instance -> Types.Ndx -> Types.Ndx -> Bool
104
prop_setBoth inst pdx sdx =
105 105
  Instance.pNode si == pdx && Instance.sNode si == sdx
106 106
    where si = Instance.setBoth inst pdx sdx
107 107

  
108
prop_Instance_shrinkMG :: Instance.Instance -> Property
109
prop_Instance_shrinkMG inst =
108
prop_shrinkMG :: Instance.Instance -> Property
109
prop_shrinkMG inst =
110 110
  Instance.mem inst >= 2 * Types.unitMem ==>
111 111
    case Instance.shrinkByType inst Types.FailMem of
112 112
      Types.Ok inst' -> Instance.mem inst' == Instance.mem inst - Types.unitMem
113 113
      _ -> False
114 114

  
115
prop_Instance_shrinkMF :: Instance.Instance -> Property
116
prop_Instance_shrinkMF inst =
115
prop_shrinkMF :: Instance.Instance -> Property
116
prop_shrinkMF inst =
117 117
  forAll (choose (0, 2 * Types.unitMem - 1)) $ \mem ->
118 118
    let inst' = inst { Instance.mem = mem}
119 119
    in Types.isBad $ Instance.shrinkByType inst' Types.FailMem
120 120

  
121
prop_Instance_shrinkCG :: Instance.Instance -> Property
122
prop_Instance_shrinkCG inst =
121
prop_shrinkCG :: Instance.Instance -> Property
122
prop_shrinkCG inst =
123 123
  Instance.vcpus inst >= 2 * Types.unitCpu ==>
124 124
    case Instance.shrinkByType inst Types.FailCPU of
125 125
      Types.Ok inst' ->
126 126
        Instance.vcpus inst' == Instance.vcpus inst - Types.unitCpu
127 127
      _ -> False
128 128

  
129
prop_Instance_shrinkCF :: Instance.Instance -> Property
130
prop_Instance_shrinkCF inst =
129
prop_shrinkCF :: Instance.Instance -> Property
130
prop_shrinkCF inst =
131 131
  forAll (choose (0, 2 * Types.unitCpu - 1)) $ \vcpus ->
132 132
    let inst' = inst { Instance.vcpus = vcpus }
133 133
    in Types.isBad $ Instance.shrinkByType inst' Types.FailCPU
134 134

  
135
prop_Instance_shrinkDG :: Instance.Instance -> Property
136
prop_Instance_shrinkDG inst =
135
prop_shrinkDG :: Instance.Instance -> Property
136
prop_shrinkDG inst =
137 137
  Instance.dsk inst >= 2 * Types.unitDsk ==>
138 138
    case Instance.shrinkByType inst Types.FailDisk of
139 139
      Types.Ok inst' ->
140 140
        Instance.dsk inst' == Instance.dsk inst - Types.unitDsk
141 141
      _ -> False
142 142

  
143
prop_Instance_shrinkDF :: Instance.Instance -> Property
144
prop_Instance_shrinkDF inst =
143
prop_shrinkDF :: Instance.Instance -> Property
144
prop_shrinkDF inst =
145 145
  forAll (choose (0, 2 * Types.unitDsk - 1)) $ \dsk ->
146 146
    let inst' = inst { Instance.dsk = dsk }
147 147
    in Types.isBad $ Instance.shrinkByType inst' Types.FailDisk
148 148

  
149
prop_Instance_setMovable :: Instance.Instance -> Bool -> Property
150
prop_Instance_setMovable inst m =
149
prop_setMovable :: Instance.Instance -> Bool -> Property
150
prop_setMovable inst m =
151 151
  Instance.movable inst' ==? m
152 152
    where inst' = Instance.setMovable inst m
153 153

  
154 154
testSuite "Instance"
155
            [ 'prop_Instance_creat
156
            , 'prop_Instance_setIdx
157
            , 'prop_Instance_setName
158
            , 'prop_Instance_setAlias
159
            , 'prop_Instance_setPri
160
            , 'prop_Instance_setSec
161
            , 'prop_Instance_setBoth
162
            , 'prop_Instance_shrinkMG
163
            , 'prop_Instance_shrinkMF
164
            , 'prop_Instance_shrinkCG
165
            , 'prop_Instance_shrinkCF
166
            , 'prop_Instance_shrinkDG
167
            , 'prop_Instance_shrinkDF
168
            , 'prop_Instance_setMovable
155
            [ 'prop_creat
156
            , 'prop_setIdx
157
            , 'prop_setName
158
            , 'prop_setAlias
159
            , 'prop_setPri
160
            , 'prop_setSec
161
            , 'prop_setBoth
162
            , 'prop_shrinkMG
163
            , 'prop_shrinkMF
164
            , 'prop_shrinkCG
165
            , 'prop_shrinkCF
166
            , 'prop_shrinkDG
167
            , 'prop_shrinkDF
168
            , 'prop_setMovable
169 169
            ]
b/htest/Test/Ganeti/HTools/Loader.hs
44 44
import qualified Ganeti.HTools.Node as Node
45 45
import qualified Ganeti.HTools.Types as Types
46 46

  
47
prop_Loader_lookupNode :: [(String, Int)] -> String -> String -> Property
48
prop_Loader_lookupNode ktn inst node =
47
prop_lookupNode :: [(String, Int)] -> String -> String -> Property
48
prop_lookupNode ktn inst node =
49 49
  Loader.lookupNode nl inst node ==? Map.lookup node nl
50 50
    where nl = Map.fromList ktn
51 51

  
52
prop_Loader_lookupInstance :: [(String, Int)] -> String -> Property
53
prop_Loader_lookupInstance kti inst =
52
prop_lookupInstance :: [(String, Int)] -> String -> Property
53
prop_lookupInstance kti inst =
54 54
  Loader.lookupInstance il inst ==? Map.lookup inst il
55 55
    where il = Map.fromList kti
56 56

  
57
prop_Loader_assignIndices :: Property
58
prop_Loader_assignIndices =
57
prop_assignIndices :: Property
58
prop_assignIndices =
59 59
  -- generate nodes with unique names
60 60
  forAll (arbitrary `suchThat`
61 61
          (\nodes ->
......
71 71

  
72 72
-- | Checks that the number of primary instances recorded on the nodes
73 73
-- is zero.
74
prop_Loader_mergeData :: [Node.Node] -> Bool
75
prop_Loader_mergeData ns =
74
prop_mergeData :: [Node.Node] -> Bool
75
prop_mergeData ns =
76 76
  let na = Container.fromList $ map (\n -> (Node.idx n, n)) ns
77 77
  in case Loader.mergeData [] [] [] []
78 78
         (Loader.emptyCluster {Loader.cdNodes = na}) of
......
84 84
         null instances
85 85

  
86 86
-- | Check that compareNameComponent on equal strings works.
87
prop_Loader_compareNameComponent_equal :: String -> Bool
88
prop_Loader_compareNameComponent_equal s =
87
prop_compareNameComponent_equal :: String -> Bool
88
prop_compareNameComponent_equal s =
89 89
  BasicTypes.compareNameComponent s s ==
90 90
    BasicTypes.LookupResult BasicTypes.ExactMatch s
91 91

  
92 92
-- | Check that compareNameComponent on prefix strings works.
93
prop_Loader_compareNameComponent_prefix :: NonEmptyList Char -> String -> Bool
94
prop_Loader_compareNameComponent_prefix (NonEmpty s1) s2 =
93
prop_compareNameComponent_prefix :: NonEmptyList Char -> String -> Bool
94
prop_compareNameComponent_prefix (NonEmpty s1) s2 =
95 95
  BasicTypes.compareNameComponent (s1 ++ "." ++ s2) s1 ==
96 96
    BasicTypes.LookupResult BasicTypes.PartialMatch s1
97 97

  
98 98
testSuite "Loader"
99
            [ 'prop_Loader_lookupNode
100
            , 'prop_Loader_lookupInstance
101
            , 'prop_Loader_assignIndices
102
            , 'prop_Loader_mergeData
103
            , 'prop_Loader_compareNameComponent_equal
104
            , 'prop_Loader_compareNameComponent_prefix
99
            [ 'prop_lookupNode
100
            , 'prop_lookupInstance
101
            , 'prop_assignIndices
102
            , 'prop_mergeData
103
            , 'prop_compareNameComponent_equal
104
            , 'prop_compareNameComponent_prefix
105 105
            ]
b/htest/Test/Ganeti/HTools/Node.hs
98 98

  
99 99
-- * Test cases
100 100

  
101
prop_Node_setAlias :: Node.Node -> String -> Bool
102
prop_Node_setAlias node name =
101
prop_setAlias :: Node.Node -> String -> Bool
102
prop_setAlias node name =
103 103
  Node.name newnode == Node.name node &&
104 104
  Node.alias newnode == name
105 105
    where newnode = Node.setAlias node name
106 106

  
107
prop_Node_setOffline :: Node.Node -> Bool -> Property
108
prop_Node_setOffline node status =
107
prop_setOffline :: Node.Node -> Bool -> Property
108
prop_setOffline node status =
109 109
  Node.offline newnode ==? status
110 110
    where newnode = Node.setOffline node status
111 111

  
112
prop_Node_setXmem :: Node.Node -> Int -> Property
113
prop_Node_setXmem node xm =
112
prop_setXmem :: Node.Node -> Int -> Property
113
prop_setXmem node xm =
114 114
  Node.xMem newnode ==? xm
115 115
    where newnode = Node.setXmem node xm
116 116

  
117
prop_Node_setMcpu :: Node.Node -> Double -> Property
118
prop_Node_setMcpu node mc =
117
prop_setMcpu :: Node.Node -> Double -> Property
118
prop_setMcpu node mc =
119 119
  Types.iPolicyVcpuRatio (Node.iPolicy newnode) ==? mc
120 120
    where newnode = Node.setMcpu node mc
121 121

  
122 122
-- | Check that an instance add with too high memory or disk will be
123 123
-- rejected.
124
prop_Node_addPriFM :: Node.Node -> Instance.Instance -> Property
125
prop_Node_addPriFM node inst =
124
prop_addPriFM :: Node.Node -> Instance.Instance -> Property
125
prop_addPriFM node inst =
126 126
  Instance.mem inst >= Node.fMem node && not (Node.failN1 node) &&
127 127
  not (Instance.isOffline inst) ==>
128 128
  case Node.addPri node inst'' of
......
133 133

  
134 134
-- | Check that adding a primary instance with too much disk fails
135 135
-- with type FailDisk.
136
prop_Node_addPriFD :: Node.Node -> Instance.Instance -> Property
137
prop_Node_addPriFD node inst =
136
prop_addPriFD :: Node.Node -> Instance.Instance -> Property
137
prop_addPriFD node inst =
138 138
  forAll (elements Instance.localStorageTemplates) $ \dt ->
139 139
  Instance.dsk inst >= Node.fDsk node && not (Node.failN1 node) ==>
140 140
  let inst' = setInstanceSmallerThanNode node inst
......
146 146

  
147 147
-- | Check that adding a primary instance with too many VCPUs fails
148 148
-- with type FailCPU.
149
prop_Node_addPriFC :: Property
150
prop_Node_addPriFC =
149
prop_addPriFC :: Property
150
prop_addPriFC =
151 151
  forAll (choose (1, maxCpu)) $ \extra ->
152 152
  forAll genOnlineNode $ \node ->
153 153
  forAll (arbitrary `suchThat` Instance.notOffline) $ \inst ->
......
159 159

  
160 160
-- | Check that an instance add with too high memory or disk will be
161 161
-- rejected.
162
prop_Node_addSec :: Node.Node -> Instance.Instance -> Int -> Property
163
prop_Node_addSec node inst pdx =
162
prop_addSec :: Node.Node -> Instance.Instance -> Int -> Property
163
prop_addSec node inst pdx =
164 164
  ((Instance.mem inst >= (Node.fMem node - Node.rMem node) &&
165 165
    not (Instance.isOffline inst)) ||
166 166
   Instance.dsk inst >= Node.fDsk node) &&
......
169 169

  
170 170
-- | Check that an offline instance with reasonable disk size but
171 171
-- extra mem/cpu can always be added.
172
prop_Node_addOfflinePri :: NonNegative Int -> NonNegative Int -> Property
173
prop_Node_addOfflinePri (NonNegative extra_mem) (NonNegative extra_cpu) =
172
prop_addOfflinePri :: NonNegative Int -> NonNegative Int -> Property
173
prop_addOfflinePri (NonNegative extra_mem) (NonNegative extra_cpu) =
174 174
  forAll genOnlineNode $ \node ->
175 175
  forAll (genInstanceSmallerThanNode node) $ \inst ->
176 176
  let inst' = inst { Instance.runSt = Types.AdminOffline
......
182 182

  
183 183
-- | Check that an offline instance with reasonable disk size but
184 184
-- extra mem/cpu can always be added.
185
prop_Node_addOfflineSec :: NonNegative Int -> NonNegative Int
186
                        -> Types.Ndx -> Property
187
prop_Node_addOfflineSec (NonNegative extra_mem) (NonNegative extra_cpu) pdx =
185
prop_addOfflineSec :: NonNegative Int -> NonNegative Int
186
                   -> Types.Ndx -> Property
187
prop_addOfflineSec (NonNegative extra_mem) (NonNegative extra_cpu) pdx =
188 188
  forAll genOnlineNode $ \node ->
189 189
  forAll (genInstanceSmallerThanNode node) $ \inst ->
190 190
  let inst' = inst { Instance.runSt = Types.AdminOffline
......
196 196
       v -> failTest $ "Expected OpGood/OpGood, but got: " ++ show v
197 197

  
198 198
-- | Checks for memory reservation changes.
199
prop_Node_rMem :: Instance.Instance -> Property
200
prop_Node_rMem inst =
199
prop_rMem :: Instance.Instance -> Property
200
prop_rMem inst =
201 201
  not (Instance.isOffline inst) ==>
202 202
  forAll (genOnlineNode `suchThat` ((> Types.unitMem) . Node.fMem)) $ \node ->
203 203
  -- ab = auto_balance, nb = non-auto_balance
......
230 230
       x -> failTest $ "Failed to add/remove instances: " ++ show x
231 231

  
232 232
-- | Check mdsk setting.
233
prop_Node_setMdsk :: Node.Node -> SmallRatio -> Bool
234
prop_Node_setMdsk node mx =
233
prop_setMdsk :: Node.Node -> SmallRatio -> Bool
234
prop_setMdsk node mx =
235 235
  Node.loDsk node' >= 0 &&
236 236
  fromIntegral (Node.loDsk node') <= Node.tDsk node &&
237 237
  Node.availDisk node' >= 0 &&
......
242 242
          SmallRatio mx' = mx
243 243

  
244 244
-- Check tag maps
245
prop_Node_tagMaps_idempotent :: Property
246
prop_Node_tagMaps_idempotent =
245
prop_tagMaps_idempotent :: Property
246
prop_tagMaps_idempotent =
247 247
  forAll genTags $ \tags ->
248 248
  Node.delTags (Node.addTags m tags) tags ==? m
249 249
    where m = Map.empty
250 250

  
251
prop_Node_tagMaps_reject :: Property
252
prop_Node_tagMaps_reject =
251
prop_tagMaps_reject :: Property
252
prop_tagMaps_reject =
253 253
  forAll (genTags `suchThat` (not . null)) $ \tags ->
254 254
  let m = Node.addTags Map.empty tags
255 255
  in all (\t -> Node.rejectAddTags m [t]) tags
256 256

  
257
prop_Node_showField :: Node.Node -> Property
258
prop_Node_showField node =
257
prop_showField :: Node.Node -> Property
258
prop_showField node =
259 259
  forAll (elements Node.defaultFields) $ \ field ->
260 260
  fst (Node.showHeader field) /= Types.unknownField &&
261 261
  Node.showField node field /= Types.unknownField
262 262

  
263
prop_Node_computeGroups :: [Node.Node] -> Bool
264
prop_Node_computeGroups nodes =
263
prop_computeGroups :: [Node.Node] -> Bool
264
prop_computeGroups nodes =
265 265
  let ng = Node.computeGroups nodes
266 266
      onlyuuid = map fst ng
267 267
  in length nodes == sum (map (length . snd) ng) &&
......
270 270
     (null nodes || not (null ng))
271 271

  
272 272
-- Check idempotence of add/remove operations
273
prop_Node_addPri_idempotent :: Property
274
prop_Node_addPri_idempotent =
273
prop_addPri_idempotent :: Property
274
prop_addPri_idempotent =
275 275
  forAll genOnlineNode $ \node ->
276 276
  forAll (genInstanceSmallerThanNode node) $ \inst ->
277 277
  case Node.addPri node inst of
278 278
    Types.OpGood node' -> Node.removePri node' inst ==? node
279 279
    _ -> failTest "Can't add instance"
280 280

  
281
prop_Node_addSec_idempotent :: Property
282
prop_Node_addSec_idempotent =
281
prop_addSec_idempotent :: Property
282
prop_addSec_idempotent =
283 283
  forAll genOnlineNode $ \node ->
284 284
  forAll (genInstanceSmallerThanNode node) $ \inst ->
285 285
  let pdx = Node.idx node + 1
......
290 290
       _ -> failTest "Can't add instance"
291 291

  
292 292
testSuite "Node"
293
            [ 'prop_Node_setAlias
294
            , 'prop_Node_setOffline
295
            , 'prop_Node_setMcpu
296
            , 'prop_Node_setXmem
297
            , 'prop_Node_addPriFM
298
            , 'prop_Node_addPriFD
299
            , 'prop_Node_addPriFC
300
            , 'prop_Node_addSec
301
            , 'prop_Node_addOfflinePri
302
            , 'prop_Node_addOfflineSec
303
            , 'prop_Node_rMem
304
            , 'prop_Node_setMdsk
305
            , 'prop_Node_tagMaps_idempotent
306
            , 'prop_Node_tagMaps_reject
307
            , 'prop_Node_showField
308
            , 'prop_Node_computeGroups
309
            , 'prop_Node_addPri_idempotent
310
            , 'prop_Node_addSec_idempotent
293
            [ 'prop_setAlias
294
            , 'prop_setOffline
295
            , 'prop_setMcpu
296
            , 'prop_setXmem
297
            , 'prop_addPriFM
298
            , 'prop_addPriFD
299
            , 'prop_addPriFC
300
            , 'prop_addSec
301
            , 'prop_addOfflinePri
302
            , 'prop_addOfflineSec
303
            , 'prop_rMem
304
            , 'prop_setMdsk
305
            , 'prop_tagMaps_idempotent
306
            , 'prop_tagMaps_reject
307
            , 'prop_showField
308
            , 'prop_computeGroups
309
            , 'prop_addPri_idempotent
310
            , 'prop_addSec_idempotent
311 311
            ]
b/htest/Test/Ganeti/HTools/PeerMap.hs
36 36
import qualified Ganeti.HTools.PeerMap as PeerMap
37 37

  
38 38
-- | Make sure add is idempotent.
39
prop_PeerMap_addIdempotent :: PeerMap.PeerMap
40
                           -> PeerMap.Key -> PeerMap.Elem -> Property
41
prop_PeerMap_addIdempotent pmap key em =
39
prop_addIdempotent :: PeerMap.PeerMap
40
                   -> PeerMap.Key -> PeerMap.Elem -> Property
41
prop_addIdempotent pmap key em =
42 42
  fn puniq ==? fn (fn puniq)
43 43
    where fn = PeerMap.add key em
44 44
          puniq = PeerMap.accumArray const pmap
45 45

  
46 46
-- | Make sure remove is idempotent.
47
prop_PeerMap_removeIdempotent :: PeerMap.PeerMap -> PeerMap.Key -> Property
48
prop_PeerMap_removeIdempotent pmap key =
47
prop_removeIdempotent :: PeerMap.PeerMap -> PeerMap.Key -> Property
48
prop_removeIdempotent pmap key =
49 49
  fn puniq ==? fn (fn puniq)
50 50
    where fn = PeerMap.remove key
51 51
          puniq = PeerMap.accumArray const pmap
52 52

  
53 53
-- | Make sure a missing item returns 0.
54
prop_PeerMap_findMissing :: PeerMap.PeerMap -> PeerMap.Key -> Property
55
prop_PeerMap_findMissing pmap key =
54
prop_findMissing :: PeerMap.PeerMap -> PeerMap.Key -> Property
55
prop_findMissing pmap key =
56 56
  PeerMap.find key (PeerMap.remove key puniq) ==? 0
57 57
    where puniq = PeerMap.accumArray const pmap
58 58

  
59 59
-- | Make sure an added item is found.
60
prop_PeerMap_addFind :: PeerMap.PeerMap
60
prop_addFind :: PeerMap.PeerMap
61 61
                     -> PeerMap.Key -> PeerMap.Elem -> Property
62
prop_PeerMap_addFind pmap key em =
62
prop_addFind pmap key em =
63 63
  PeerMap.find key (PeerMap.add key em puniq) ==? em
64 64
    where puniq = PeerMap.accumArray const pmap
65 65

  
66 66
-- | Manual check that maxElem returns the maximum indeed, or 0 for null.
67
prop_PeerMap_maxElem :: PeerMap.PeerMap -> Property
68
prop_PeerMap_maxElem pmap =
67
prop_maxElem :: PeerMap.PeerMap -> Property
68
prop_maxElem pmap =
69 69
  PeerMap.maxElem puniq ==? if null puniq then 0
70 70
                              else (maximum . snd . unzip) puniq
71 71
    where puniq = PeerMap.accumArray const pmap
72 72

  
73 73
-- | List of tests for the PeerMap module.
74 74
testSuite "PeerMap"
75
            [ 'prop_PeerMap_addIdempotent
76
            , 'prop_PeerMap_removeIdempotent
77
            , 'prop_PeerMap_maxElem
78
            , 'prop_PeerMap_addFind
79
            , 'prop_PeerMap_findMissing
75
            [ 'prop_addIdempotent
76
            , 'prop_removeIdempotent
77
            , 'prop_maxElem
78
            , 'prop_addFind
79
            , 'prop_findMissing
80 80
            ]
b/htest/Test/Ganeti/HTools/Simu.hs
62 62

  
63 63
-- | Checks that given a set of corrects specs, we can load them
64 64
-- successfully, and that at high-level the values look right.
65
prop_Simu_Load :: Property
66
prop_Simu_Load =
65
prop_Load :: Property
66
prop_Load =
67 67
  forAll (choose (0, 10)) $ \ngroups ->
68 68
  forAll (replicateM ngroups genSimuSpec) $ \specs ->
69 69
  let strspecs = map (\(p, n, d, m, c) -> printf "%s,%d,%d,%d,%d"
......
93 93
             replicate ngroups Types.defIPolicy
94 94

  
95 95
testSuite "Simu"
96
            [ 'prop_Simu_Load
96
            [ 'prop_Load
97 97
            ]
b/htest/Test/Ganeti/HTools/Text.hs
52 52

  
53 53
-- * Instance text loader tests
54 54

  
55
prop_Text_Load_Instance :: String -> Int -> Int -> Int -> Types.InstanceStatus
56
                        -> NonEmptyList Char -> [Char]
57
                        -> NonNegative Int -> NonNegative Int -> Bool
58
                        -> Types.DiskTemplate -> Int -> Property
59
prop_Text_Load_Instance name mem dsk vcpus status
60
                        (NonEmpty pnode) snode
61
                        (NonNegative pdx) (NonNegative sdx) autobal dt su =
55
prop_Load_Instance :: String -> Int -> Int -> Int -> Types.InstanceStatus
56
                   -> NonEmptyList Char -> [Char]
57
                   -> NonNegative Int -> NonNegative Int -> Bool
58
                   -> Types.DiskTemplate -> Int -> Property
59
prop_Load_Instance name mem dsk vcpus status
60
                   (NonEmpty pnode) snode
61
                   (NonNegative pdx) (NonNegative sdx) autobal dt su =
62 62
  pnode /= snode && pdx /= sdx ==>
63 63
  let vcpus_s = show vcpus
64 64
      dsk_s = show dsk
......
93 93
               Instance.spindleUse i == su &&
94 94
               Types.isBad fail1
95 95

  
96
prop_Text_Load_InstanceFail :: [(String, Int)] -> [String] -> Property
97
prop_Text_Load_InstanceFail ktn fields =
96
prop_Load_InstanceFail :: [(String, Int)] -> [String] -> Property
97
prop_Load_InstanceFail ktn fields =
98 98
  length fields /= 10 && length fields /= 11 ==>
99 99
    case Text.loadInst nl fields of
100 100
      Types.Ok _ -> failTest "Managed to load instance from invalid data"
......
102 102
                       "Invalid/incomplete instance data: '" `isPrefixOf` msg
103 103
    where nl = Map.fromList ktn
104 104

  
105
prop_Text_Load_Node :: String -> Int -> Int -> Int -> Int -> Int
106
                    -> Int -> Bool -> Bool
107
prop_Text_Load_Node name tm nm fm td fd tc fo =
105
prop_Load_Node :: String -> Int -> Int -> Int -> Int -> Int
106
               -> Int -> Bool -> Bool
107
prop_Load_Node name tm nm fm td fd tc fo =
108 108
  let conv v = if v < 0
109 109
                 then "?"
110 110
                 else show v
......
134 134
                Node.fDsk node == fd &&
135 135
                Node.tCpu node == fromIntegral tc
136 136

  
137
prop_Text_Load_NodeFail :: [String] -> Property
138
prop_Text_Load_NodeFail fields =
137
prop_Load_NodeFail :: [String] -> Property
138
prop_Load_NodeFail fields =
139 139
  length fields /= 8 ==> isNothing $ Text.loadNode Map.empty fields
140 140

  
141
prop_Text_NodeLSIdempotent :: Property
142
prop_Text_NodeLSIdempotent =
141
prop_NodeLSIdempotent :: Property
142
prop_NodeLSIdempotent =
143 143
  forAll (genNode (Just 1) Nothing) $ \node ->
144 144
  -- override failN1 to what loadNode returns by default
145 145
  let n = Node.setPolicy Types.defIPolicy $
......
149 149
         Utils.sepSplit '|' . Text.serializeNode defGroupList) n ==?
150 150
    Just (Node.name n, n)
151 151

  
152
prop_Text_ISpecIdempotent :: Types.ISpec -> Property
153
prop_Text_ISpecIdempotent ispec =
152
prop_ISpecIdempotent :: Types.ISpec -> Property
153
prop_ISpecIdempotent ispec =
154 154
  case Text.loadISpec "dummy" . Utils.sepSplit ',' .
155 155
       Text.serializeISpec $ ispec of
156 156
    Types.Bad msg -> failTest $ "Failed to load ispec: " ++ msg
157 157
    Types.Ok ispec' -> ispec ==? ispec'
158 158

  
159
prop_Text_IPolicyIdempotent :: Types.IPolicy -> Property
160
prop_Text_IPolicyIdempotent ipol =
159
prop_IPolicyIdempotent :: Types.IPolicy -> Property
160
prop_IPolicyIdempotent ipol =
161 161
  case Text.loadIPolicy . Utils.sepSplit '|' $
162 162
       Text.serializeIPolicy owner ipol of
163 163
    Types.Bad msg -> failTest $ "Failed to load ispec: " ++ msg
......
171 171
-- allocations, not for the business logic). As such, it's a quite
172 172
-- complex and slow test, and that's the reason we restrict it to
173 173
-- small cluster sizes.
174
prop_Text_CreateSerialise :: Property
175
prop_Text_CreateSerialise =
174
prop_CreateSerialise :: Property
175
prop_CreateSerialise =
176 176
  forAll genTags $ \ctags ->
177 177
  forAll (choose (1, 20)) $ \maxiter ->
178 178
  forAll (choose (2, 10)) $ \count ->
......
200 200
                nl' ==? nl2
201 201

  
202 202
testSuite "Text"
203
            [ 'prop_Text_Load_Instance
204
            , 'prop_Text_Load_InstanceFail
205
            , 'prop_Text_Load_Node
206
            , 'prop_Text_Load_NodeFail
207
            , 'prop_Text_NodeLSIdempotent
208
            , 'prop_Text_ISpecIdempotent
209
            , 'prop_Text_IPolicyIdempotent
210
            , 'prop_Text_CreateSerialise
203
            [ 'prop_Load_Instance
204
            , 'prop_Load_InstanceFail
205
            , 'prop_Load_Node
206
            , 'prop_Load_NodeFail
207
            , 'prop_NodeLSIdempotent
208
            , 'prop_ISpecIdempotent
209
            , 'prop_IPolicyIdempotent
210
            , 'prop_CreateSerialise
211 211
            ]
b/htest/Test/Ganeti/HTools/Types.hs
127 127

  
128 128
-- * Test cases
129 129

  
130
prop_Types_AllocPolicy_serialisation :: Types.AllocPolicy -> Property
131
prop_Types_AllocPolicy_serialisation apol =
130
prop_AllocPolicy_serialisation :: Types.AllocPolicy -> Property
131
prop_AllocPolicy_serialisation apol =
132 132
  case J.readJSON (J.showJSON apol) of
133 133
    J.Ok p -> p ==? apol
134 134
    J.Error s -> failTest $ "Failed to deserialise: " ++ s
135 135

  
136
prop_Types_DiskTemplate_serialisation :: Types.DiskTemplate -> Property
137
prop_Types_DiskTemplate_serialisation dt =
136
prop_DiskTemplate_serialisation :: Types.DiskTemplate -> Property
137
prop_DiskTemplate_serialisation dt =
138 138
  case J.readJSON (J.showJSON dt) of
139 139
    J.Ok p -> p ==? dt
140 140
    J.Error s -> failTest $ "Failed to deserialise: " ++ s
141 141

  
142
prop_Types_ISpec_serialisation :: Types.ISpec -> Property
143
prop_Types_ISpec_serialisation ispec =
142
prop_ISpec_serialisation :: Types.ISpec -> Property
143
prop_ISpec_serialisation ispec =
144 144
  case J.readJSON (J.showJSON ispec) of
145 145
    J.Ok p -> p ==? ispec
146 146
    J.Error s -> failTest $ "Failed to deserialise: " ++ s
147 147

  
148
prop_Types_IPolicy_serialisation :: Types.IPolicy -> Property
149
prop_Types_IPolicy_serialisation ipol =
148
prop_IPolicy_serialisation :: Types.IPolicy -> Property
149
prop_IPolicy_serialisation ipol =
150 150
  case J.readJSON (J.showJSON ipol) of
151 151
    J.Ok p -> p ==? ipol
152 152
    J.Error s -> failTest $ "Failed to deserialise: " ++ s
153 153

  
154
prop_Types_EvacMode_serialisation :: Types.EvacMode -> Property
155
prop_Types_EvacMode_serialisation em =
154
prop_EvacMode_serialisation :: Types.EvacMode -> Property
155
prop_EvacMode_serialisation em =
156 156
  case J.readJSON (J.showJSON em) of
157 157
    J.Ok p -> p ==? em
158 158
    J.Error s -> failTest $ "Failed to deserialise: " ++ s
159 159

  
160
prop_Types_opToResult :: Types.OpResult Int -> Bool
161
prop_Types_opToResult op =
160
prop_opToResult :: Types.OpResult Int -> Bool
161
prop_opToResult op =
162 162
  case op of
163 163
    Types.OpFail _ -> Types.isBad r
164 164
    Types.OpGood v -> case r of
......
166 166
                        Types.Ok v' -> v == v'
167 167
  where r = Types.opToResult op
168 168

  
169
prop_Types_eitherToResult :: Either String Int -> Bool
170
prop_Types_eitherToResult ei =
169
prop_eitherToResult :: Either String Int -> Bool
170
prop_eitherToResult ei =
171 171
  case ei of
172 172
    Left _ -> Types.isBad r
173 173
    Right v -> case r of
......
176 176
    where r = Types.eitherToResult ei
177 177

  
178 178
testSuite "Types"
179
            [ 'prop_Types_AllocPolicy_serialisation
180
            , 'prop_Types_DiskTemplate_serialisation
181
            , 'prop_Types_ISpec_serialisation
182
            , 'prop_Types_IPolicy_serialisation
183
            , 'prop_Types_EvacMode_serialisation
184
            , 'prop_Types_opToResult
185
            , 'prop_Types_eitherToResult
179
            [ 'prop_AllocPolicy_serialisation
180
            , 'prop_DiskTemplate_serialisation
181
            , 'prop_ISpec_serialisation
182
            , 'prop_IPolicy_serialisation
183
            , 'prop_EvacMode_serialisation
184
            , 'prop_opToResult
185
            , 'prop_eitherToResult
186 186
            ]
b/htest/Test/Ganeti/HTools/Utils.hs
47 47

  
48 48
-- | If the list is not just an empty element, and if the elements do
49 49
-- not contain commas, then join+split should be idempotent.
50
prop_Utils_commaJoinSplit :: Property
51
prop_Utils_commaJoinSplit =
50
prop_commaJoinSplit :: Property
51
prop_commaJoinSplit =
52 52
  forAll (choose (0, 20)) $ \llen ->
53 53
  forAll (vectorOf llen genNonCommaString `suchThat` ((/=) [""])) $ \lst ->
54 54
  Utils.sepSplit ',' (Utils.commaJoin lst) ==? lst
55 55

  
56 56
-- | Split and join should always be idempotent.
57
prop_Utils_commaSplitJoin :: [Char] -> Property
58
prop_Utils_commaSplitJoin s =
57
prop_commaSplitJoin :: [Char] -> Property
58
prop_commaSplitJoin s =
59 59
  Utils.commaJoin (Utils.sepSplit ',' s) ==? s
60 60

  
61 61
-- | fromObjWithDefault, we test using the Maybe monad and an integer
62 62
-- value.
63
prop_Utils_fromObjWithDefault :: Integer -> String -> Bool
64
prop_Utils_fromObjWithDefault def_value random_key =
63
prop_fromObjWithDefault :: Integer -> String -> Bool
64
prop_fromObjWithDefault def_value random_key =
65 65
  -- a missing key will be returned with the default
66 66
  JSON.fromObjWithDefault [] random_key def_value == Just def_value &&
67 67
  -- a found key will be returned as is, not with default
......
69 69
       random_key (def_value+1) == Just def_value
70 70

  
71 71
-- | Test that functional if' behaves like the syntactic sugar if.
72
prop_Utils_if'if :: Bool -> Int -> Int -> Gen Prop
73
prop_Utils_if'if cnd a b =
72
prop_if'if :: Bool -> Int -> Int -> Gen Prop
73
prop_if'if cnd a b =
74 74
  Utils.if' cnd a b ==? if cnd then a else b
75 75

  
76 76
-- | Test basic select functionality
77
prop_Utils_select :: Int      -- ^ Default result
78
                  -> [Int]    -- ^ List of False values
79
                  -> [Int]    -- ^ List of True values
80
                  -> Gen Prop -- ^ Test result
81
prop_Utils_select def lst1 lst2 =
77
prop_select :: Int      -- ^ Default result
78
            -> [Int]    -- ^ List of False values
79
            -> [Int]    -- ^ List of True values
80
            -> Gen Prop -- ^ Test result
81
prop_select def lst1 lst2 =
82 82
  Utils.select def (flist ++ tlist) ==? expectedresult
83 83
    where expectedresult = Utils.if' (null lst2) def (head lst2)
84 84
          flist = zip (repeat False) lst1
85 85
          tlist = zip (repeat True)  lst2
86 86

  
87 87
-- | Test basic select functionality with undefined default
88
prop_Utils_select_undefd :: [Int]            -- ^ List of False values
89
                         -> NonEmptyList Int -- ^ List of True values
90
                         -> Gen Prop         -- ^ Test result
91
prop_Utils_select_undefd lst1 (NonEmpty lst2) =
88
prop_select_undefd :: [Int]            -- ^ List of False values
89
                   -> NonEmptyList Int -- ^ List of True values
90
                   -> Gen Prop         -- ^ Test result
91
prop_select_undefd lst1 (NonEmpty lst2) =
92 92
  Utils.select undefined (flist ++ tlist) ==? head lst2
93 93
    where flist = zip (repeat False) lst1
94 94
          tlist = zip (repeat True)  lst2
95 95

  
96 96
-- | Test basic select functionality with undefined list values
97
prop_Utils_select_undefv :: [Int]            -- ^ List of False values
98
                         -> NonEmptyList Int -- ^ List of True values
99
                         -> Gen Prop         -- ^ Test result
100
prop_Utils_select_undefv lst1 (NonEmpty lst2) =
97
prop_select_undefv :: [Int]            -- ^ List of False values
98
                   -> NonEmptyList Int -- ^ List of True values
99
                   -> Gen Prop         -- ^ Test result
100
prop_select_undefv lst1 (NonEmpty lst2) =
101 101
  Utils.select undefined cndlist ==? head lst2
102 102
    where flist = zip (repeat False) lst1
103 103
          tlist = zip (repeat True)  lst2
104 104
          cndlist = flist ++ tlist ++ [undefined]
105 105

  
106
prop_Utils_parseUnit :: NonNegative Int -> Property
107
prop_Utils_parseUnit (NonNegative n) =
106
prop_parseUnit :: NonNegative Int -> Property
107
prop_parseUnit (NonNegative n) =
108 108
  Utils.parseUnit (show n) ==? Types.Ok n .&&.
109 109
  Utils.parseUnit (show n ++ "m") ==? Types.Ok n .&&.
110 110
  Utils.parseUnit (show n ++ "M") ==? Types.Ok (truncate n_mb::Int) .&&.
......
121 121

  
122 122
-- | Test list for the Utils module.
123 123
testSuite "Utils"
124
            [ 'prop_Utils_commaJoinSplit
125
            , 'prop_Utils_commaSplitJoin
126
            , 'prop_Utils_fromObjWithDefault
127
            , 'prop_Utils_if'if
128
            , 'prop_Utils_select
129
            , 'prop_Utils_select_undefd
130
            , 'prop_Utils_select_undefv
131
            , 'prop_Utils_parseUnit
124
            [ 'prop_commaJoinSplit
125
            , 'prop_commaSplitJoin
126
            , 'prop_fromObjWithDefault
127
            , 'prop_if'if
128
            , 'prop_select
129
            , 'prop_select_undefd
130
            , 'prop_select_undefv
131
            , 'prop_parseUnit
132 132
            ]
b/htest/Test/Ganeti/JSON.hs
38 38
import qualified Ganeti.BasicTypes as BasicTypes
39 39
import qualified Ganeti.JSON as JSON
40 40

  
41
prop_JSON_toArray :: [Int] -> Property
42
prop_JSON_toArray intarr =
41
prop_toArray :: [Int] -> Property
42
prop_toArray intarr =
43 43
  let arr = map J.showJSON intarr in
44 44
  case JSON.toArray (J.JSArray arr) of
45 45
    BasicTypes.Ok arr' -> arr ==? arr'
46 46
    BasicTypes.Bad err -> failTest $ "Failed to parse array: " ++ err
47 47

  
48
prop_JSON_toArrayFail :: Int -> String -> Bool -> Property
49
prop_JSON_toArrayFail i s b =
48
prop_toArrayFail :: Int -> String -> Bool -> Property
49
prop_toArrayFail i s b =
50 50
  -- poor man's instance Arbitrary JSValue
51 51
  forAll (elements [J.showJSON i, J.showJSON s, J.showJSON b]) $ \item ->
52 52
  case JSON.toArray item of
......
54 54
    BasicTypes.Ok result -> failTest $ "Unexpected parse, got " ++ show result
55 55

  
56 56
testSuite "JSON"
57
          [ 'prop_JSON_toArray
58
          , 'prop_JSON_toArrayFail
57
          [ 'prop_toArray
58
          , 'prop_toArrayFail
59 59
          ]
b/htest/Test/Ganeti/Jobs.hs
48 48
-- * Test cases
49 49

  
50 50
-- | Check that (queued) job\/opcode status serialization is idempotent.
51
prop_Jobs_OpStatus_serialization :: Jobs.OpStatus -> Property
52
prop_Jobs_OpStatus_serialization os =
51
prop_OpStatus_serialization :: Jobs.OpStatus -> Property
52
prop_OpStatus_serialization os =
53 53
  case J.readJSON (J.showJSON os) of
54 54
    J.Error e -> failTest $ "Cannot deserialise: " ++ e
55 55
    J.Ok os' -> os ==? os'
56 56

  
57
prop_Jobs_JobStatus_serialization :: Jobs.JobStatus -> Property
58
prop_Jobs_JobStatus_serialization js =
57
prop_JobStatus_serialization :: Jobs.JobStatus -> Property
58
prop_JobStatus_serialization js =
59 59
  case J.readJSON (J.showJSON js) of
60 60
    J.Error e -> failTest $ "Cannot deserialise: " ++ e
61 61
    J.Ok js' -> js ==? js'
62 62

  
63 63
testSuite "Jobs"
64
            [ 'prop_Jobs_OpStatus_serialization
65
            , 'prop_Jobs_JobStatus_serialization
64
            [ 'prop_OpStatus_serialization
65
            , 'prop_JobStatus_serialization
66 66
            ]
b/htest/Test/Ganeti/Luxi.hs
86 86
      Luxi.ReqSetWatcherPause -> Luxi.SetWatcherPause <$> arbitrary
87 87

  
88 88
-- | Simple check that encoding/decoding of LuxiOp works.
89
prop_Luxi_CallEncoding :: Luxi.LuxiOp -> Property
90
prop_Luxi_CallEncoding op =
89
prop_CallEncoding :: Luxi.LuxiOp -> Property
90
prop_CallEncoding op =
91 91
  (Luxi.validateCall (Luxi.buildCall op) >>= Luxi.decodeCall) ==? Ok op
92 92

  
93 93
-- | Helper to a get a temporary file name.
......
115 115
-- | Monadic check that, given a server socket, we can connect via a
116 116
-- client to it, and that we can send a list of arbitrary messages and
117 117
-- get back what we sent.
118
prop_Luxi_ClientServer :: [[DNSChar]] -> Property
119
prop_Luxi_ClientServer dnschars = monadicIO $ do
118
prop_ClientServer :: [[DNSChar]] -> Property
119
prop_ClientServer dnschars = monadicIO $ do
120 120
  let msgs = map (map dnsGetChar) dnschars
121 121
  fpath <- run $ getTempFileName
122 122
  -- we need to create the server first, otherwise (if we do it in the
......
137 137
  stop $ replies ==? msgs
138 138

  
139 139
testSuite "Luxi"
140
          [ 'prop_Luxi_CallEncoding
141
          , 'prop_Luxi_ClientServer
140
          [ 'prop_CallEncoding
141
          , 'prop_ClientServer
142 142
          ]
b/htest/Test/Ganeti/Objects.hs
55 55
              <*> (Set.fromList <$> genTags)
56 56

  
57 57
-- | Tests that fillDict behaves correctly
58
prop_Objects_fillDict :: [(Int, Int)] -> [(Int, Int)] -> Property
59
prop_Objects_fillDict defaults custom =
58
prop_fillDict :: [(Int, Int)] -> [(Int, Int)] -> Property
59
prop_fillDict defaults custom =
60 60
  let d_map = Map.fromList defaults
61 61
      d_keys = map fst defaults
62 62
      c_map = Map.fromList custom
......
69 69
      (Objects.fillDict d_map c_map (d_keys++c_keys) == Map.empty)
70 70

  
71 71
testSuite "Objects"
72
  [ 'prop_Objects_fillDict
72
  [ 'prop_fillDict
73 73
  ]
b/htest/Test/Ganeti/OpCodes.hs
73 73
-- * Test cases
74 74

  
75 75
-- | Check that opcode serialization is idempotent.
76
prop_OpCodes_serialization :: OpCodes.OpCode -> Property
77
prop_OpCodes_serialization op =
76
prop_serialization :: OpCodes.OpCode -> Property
77
prop_serialization op =
78 78
  case J.readJSON (J.showJSON op) of
79 79
    J.Error e -> failTest $ "Cannot deserialise: " ++ e
80 80
    J.Ok op' -> op ==? op'
81 81

  
82 82
-- | Check that Python and Haskell defined the same opcode list.
83
case_OpCodes_AllDefined :: HUnit.Assertion
84
case_OpCodes_AllDefined = do
83
case_AllDefined :: HUnit.Assertion
84
case_AllDefined = do
85 85
  py_stdout <- runPython "from ganeti import opcodes\n\
86 86
                         \print '\\n'.join(opcodes.OP_MAPPING.keys())" "" >>=
87 87
               checkPythonResult
......
111 111
-- a better way to do this, for example by having a
112 112
-- separately-launched Python process (if not running the tests would
113 113
-- be skipped).
114
case_OpCodes_py_compat :: HUnit.Assertion
115
case_OpCodes_py_compat = do
114
case_py_compat :: HUnit.Assertion
115
case_py_compat = do
116 116
  let num_opcodes = length OpCodes.allOpIDs * 500
117 117
  sample_opcodes <- sample' (vectorOf num_opcodes
118 118
                             (arbitrary::Gen OpCodes.OpCode))
......
143 143
        ) $ zip opcodes decoded
144 144

  
145 145
testSuite "OpCodes"
146
            [ 'prop_OpCodes_serialization
147
            , 'case_OpCodes_AllDefined
148
            , 'case_OpCodes_py_compat
146
            [ 'prop_serialization
147
            , 'case_AllDefined
148
            , 'case_py_compat
149 149
            ]
b/htest/Test/Ganeti/Query/Language.hs
81 81

  
82 82
-- | Tests that serialisation/deserialisation of filters is
83 83
-- idempotent.
84
prop_Qlang_Serialisation :: Property
85
prop_Qlang_Serialisation =
84
prop_Serialisation :: Property
85
prop_Serialisation =
86 86
  forAll genFilter $ \flt ->
87 87
  J.readJSON (J.showJSON flt) ==? J.Ok flt
88 88

  
89
prop_Qlang_FilterRegex_instances :: Qlang.FilterRegex -> Property
90
prop_Qlang_FilterRegex_instances rex =
89
prop_FilterRegex_instances :: Qlang.FilterRegex -> Property
90
prop_FilterRegex_instances rex =
91 91
  printTestCase "failed JSON encoding"
92 92
    (J.readJSON (J.showJSON rex) ==? J.Ok rex) .&&.
93 93
  printTestCase "failed read/show instances" (read (show rex) ==? rex)
94 94

  
95 95
testSuite "Qlang"
96
  [ 'prop_Qlang_Serialisation
97
  , 'prop_Qlang_FilterRegex_instances
96
  [ 'prop_Serialisation
97
  , 'prop_FilterRegex_instances
98 98
  ]
b/htest/Test/Ganeti/Rpc.hs
53 53
-- offline nodes, we get a OfflineNodeError response.
54 54
-- FIXME: We need a way of generalizing this, running it for
55 55
-- every call manually will soon get problematic
56
prop_Rpc_noffl_request_allinstinfo :: Rpc.RpcCallAllInstancesInfo -> Property
57
prop_Rpc_noffl_request_allinstinfo call =
56
prop_noffl_request_allinstinfo :: Rpc.RpcCallAllInstancesInfo -> Property
57
prop_noffl_request_allinstinfo call =
58 58
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
59 59
      res <- run $ Rpc.executeRpcCall [node] call
60 60
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
61 61

  
62
prop_Rpc_noffl_request_instlist :: Rpc.RpcCallInstanceList -> Property
63
prop_Rpc_noffl_request_instlist call =
62
prop_noffl_request_instlist :: Rpc.RpcCallInstanceList -> Property
63
prop_noffl_request_instlist call =
64 64
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
65 65
      res <- run $ Rpc.executeRpcCall [node] call
66 66
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
67 67

  
68
prop_Rpc_noffl_request_nodeinfo :: Rpc.RpcCallNodeInfo -> Property
69
prop_Rpc_noffl_request_nodeinfo call =
68
prop_noffl_request_nodeinfo :: Rpc.RpcCallNodeInfo -> Property
69
prop_noffl_request_nodeinfo call =
70 70
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
71 71
      res <- run $ Rpc.executeRpcCall [node] call
72 72
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
73 73

  
74 74
testSuite "Rpc"
75
  [ 'prop_Rpc_noffl_request_allinstinfo
76
  , 'prop_Rpc_noffl_request_instlist
77
  , 'prop_Rpc_noffl_request_nodeinfo
75
  [ 'prop_noffl_request_allinstinfo
76
  , 'prop_noffl_request_instlist
77
  , 'prop_noffl_request_nodeinfo
78 78
  ]
b/htest/Test/Ganeti/Ssconf.hs
41 41
instance Arbitrary Ssconf.SSKey where
42 42
  arbitrary = elements [minBound..maxBound]
43 43

  
44
prop_Ssconf_filename :: Ssconf.SSKey -> Property
45
prop_Ssconf_filename key =
44
prop_filename :: Ssconf.SSKey -> Property
45
prop_filename key =
46 46
  printTestCase "Key doesn't start with correct prefix" $
47 47
    Ssconf.sSFilePrefix `isPrefixOf` Ssconf.keyToFilename (Just "") key
48 48

  
49 49
testSuite "Ssconf"
50
  [ 'prop_Ssconf_filename
50
  [ 'prop_filename
51 51
  ]
b/htest/Test/Ganeti/TestHelper.hs
38 38
import Test.QuickCheck
39 39
import Language.Haskell.TH
40 40

  
41
-- | Test property prefix.
42
propPrefix :: String
43
propPrefix = "prop_"
44

  
45
-- | Test case prefix.
46
casePrefix :: String
47
casePrefix = "case_"
48

  
41 49
-- | Tries to drop a prefix from a string.
42 50
simplifyName :: String -> String -> String
43 51
simplifyName pfx string = fromMaybe string (stripPrefix pfx string)
44 52

  
45 53
-- | Builds a test from a QuickCheck property.
46
runQC :: Testable prop => String -> String -> prop -> Test
47
runQC pfx name = testProperty (simplifyName ("prop_" ++ pfx ++ "_") name)
54
runProp :: Testable prop => String -> prop -> Test
55
runProp = testProperty . simplifyName propPrefix
48 56

  
49 57
-- | Builds a test for a HUnit test case.
50
runHUnit :: String -> String -> Assertion -> Test
51
runHUnit pfx name = testCase (simplifyName ("case_" ++ pfx ++ "_") name)
58
runCase :: String -> Assertion -> Test
59
runCase = testCase . simplifyName casePrefix
52 60

  
53 61
-- | Runs the correct test provider for a given test, based on its
54 62
-- name (not very nice, but...).
55
run :: String -> Name -> Q Exp
56
run tsname name =
63
run :: Name -> Q Exp
64
run name =
57 65
  let str = nameBase name
58 66
      nameE = varE name
59 67
      strE = litE (StringL str)
60 68
  in case () of
61
       _ | "prop_" `isPrefixOf` str -> [| runQC tsname $strE $nameE |]
62
         | "case_" `isPrefixOf` str -> [| runHUnit tsname $strE $nameE |]
69
       _ | propPrefix `isPrefixOf` str -> [| runProp $strE $nameE |]
70
         | casePrefix `isPrefixOf` str -> [| runCase $strE $nameE |]
63 71
         | otherwise -> fail $ "Unsupported test function name '" ++ str ++ "'"
64 72

  
65 73
-- | Builds a test suite.
66 74
testSuite :: String -> [Name] -> Q [Dec]
67 75
testSuite tsname tdef = do
68 76
  let fullname = mkName $ "test" ++ tsname
69
  tests <- mapM (run tsname) tdef
77
  tests <- mapM run tdef
70 78
  sigtype <- [t| (String, [Test]) |]
71 79
  return [ SigD fullname sigtype
72 80
         , ValD (VarP fullname) (NormalB (TupE [LitE (StringL tsname),

Also available in: Unified diff