Revision 305e174c

b/Makefile.am
433 433
	htools/Ganeti/THH.hs \
434 434
	htest/Test/Ganeti/TestHelper.hs \
435 435
	htest/Test/Ganeti/TestCommon.hs \
436
	htest/Test/Ganeti/Confd/Utils.hs \
436 437
	htest/Test/Ganeti/Objects.hs \
437
	htest/Test/Ganeti/Confd/Utils.hs
438
	htest/Test/Ganeti/Rpc.hs
438 439

  
439 440

  
440 441
HS_BUILT_SRCS = htools/Ganeti/HTools/Version.hs htools/Ganeti/Constants.hs
b/htest/Test/Ganeti/Objects.hs
26 26

  
27 27
-}
28 28

  
29
module Test.Ganeti.Objects (testObjects) where
29
module Test.Ganeti.Objects
30
  ( testObjects
31
  , Objects.Hypervisor(..)
32
  , Objects.Node(..)
33
  ) where
30 34

  
35
import Control.Applicative
31 36
import qualified Data.Map as Map
37
import qualified Data.Set as Set
32 38
import Test.QuickCheck
33 39

  
34 40
import Test.Ganeti.TestHelper
41
import Test.Ganeti.TestCommon
35 42
import qualified Ganeti.Objects as Objects
36 43

  
44
instance Arbitrary Objects.Hypervisor where
45
  arbitrary = elements [minBound..maxBound]
46

  
47
instance Arbitrary Objects.PartialNDParams where
48
  arbitrary = Objects.PartialNDParams <$> arbitrary <*> arbitrary
49

  
50
instance Arbitrary Objects.Node where
51
  arbitrary = Objects.Node <$> getFQDN <*> getFQDN <*> getFQDN
52
              <*> arbitrary <*> arbitrary <*> arbitrary <*> getFQDN
53
              <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
54
              <*> arbitrary <*> arbitrary <*> getFQDN <*> arbitrary
55
              <*> (Set.fromList <$> genTags)
56

  
37 57
-- | Tests that fillDict behaves correctly
38 58
prop_Objects_fillDict :: [(Int, Int)] -> [(Int, Int)] -> Property
39 59
prop_Objects_fillDict defaults custom =
b/htest/Test/Ganeti/Rpc.hs
1
{-# LANGUAGE TemplateHaskell #-}
2
{-# OPTIONS_GHC -fno-warn-orphans #-}
3

  
4
{-| Unittests for ganeti-htools.
5

  
6
-}
7

  
8
{-
9

  
10
Copyright (C) 2009, 2010, 2011, 2012 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.Rpc (testRpc) where
30

  
31
import Test.QuickCheck
32
import Test.QuickCheck.Monadic (monadicIO, run, stop)
33

  
34
import Control.Applicative
35

  
36
import Test.Ganeti.TestHelper
37
import Test.Ganeti.TestCommon
38
import Test.Ganeti.Objects ()
39

  
40
import qualified Ganeti.Rpc as Rpc
41
import qualified Ganeti.Objects as Objects
42

  
43
instance Arbitrary Rpc.RpcCallAllInstancesInfo where
44
  arbitrary = Rpc.RpcCallAllInstancesInfo <$> arbitrary
45

  
46
instance Arbitrary Rpc.RpcCallInstanceList where
47
  arbitrary = Rpc.RpcCallInstanceList <$> arbitrary
48

  
49
instance Arbitrary Rpc.RpcCallNodeInfo where
50
  arbitrary = Rpc.RpcCallNodeInfo <$> arbitrary <*> arbitrary
51

  
52
-- | Monadic check that, for an offline node and a call that does not
53
-- offline nodes, we get a OfflineNodeError response.
54
-- FIXME: We need a way of generalizing this, running it for
55
-- every call manually will soon get problematic
56
prop_Rpc_noffl_request_allinstinfo :: Rpc.RpcCallAllInstancesInfo -> Property
57
prop_Rpc_noffl_request_allinstinfo call =
58
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
59
      res <- run $ Rpc.executeRpcCall [node] call
60
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
61

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

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

  
74
testSuite "Rpc"
75
  [ 'prop_Rpc_noffl_request_allinstinfo
76
  , 'prop_Rpc_noffl_request_instlist
77
  , 'prop_Rpc_noffl_request_nodeinfo
78
  ]
b/htest/Test/Ganeti/TestCommon.hs
108 108
  if bool
109 109
    then Just <$> subgen
110 110
    else return Nothing
111

  
112
-- | Defines a tag type.
113
newtype TagChar = TagChar { tagGetChar :: Char }
114

  
115
-- | All valid tag chars. This doesn't need to match _exactly_
116
-- Ganeti's own tag regex, just enough for it to be close.
117
tagChar :: [Char]
118
tagChar = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ".+*/:@-"
119

  
120
instance Arbitrary TagChar where
121
  arbitrary = do
122
    c <- elements tagChar
123
    return (TagChar c)
124

  
125
-- | Generates a tag
126
genTag :: Gen [TagChar]
127
genTag = do
128
  -- the correct value would be C.maxTagLen, but that's way too
129
  -- verbose in unittests, and at the moment I don't see any possible
130
  -- bugs with longer tags and the way we use tags in htools
131
  n <- choose (1, 10)
132
  vector n
133

  
134
-- | Generates a list of tags (correctly upper bounded).
135
genTags :: Gen [String]
136
genTags = do
137
  -- the correct value would be C.maxTagsPerObj, but per the comment
138
  -- in genTag, we don't use tags enough in htools to warrant testing
139
  -- such big values
140
  n <- choose (0, 10::Int)
141
  tags <- mapM (const genTag) [1..n]
142
  return $ map (map tagGetChar) tags
b/htest/test.hs
32 32
import Ganeti.HTools.QC
33 33
import Test.Ganeti.Confd.Utils
34 34
import Test.Ganeti.Objects
35
import Test.Ganeti.Rpc
35 36

  
36 37
-- | Our default test options, overring the built-in test-framework
37 38
-- ones.
b/htools/Ganeti/HTools/QC.hs
48 48
  , testJSON
49 49
  , testLuxi
50 50
  , testSsconf
51
  , testRpc
52 51
  , testQlang
53
  , testConfd
54 52
  ) where
55 53

  
56 54
import qualified Test.HUnit as HUnit
......
87 85
import qualified Ganeti.Luxi as Luxi
88 86
import qualified Ganeti.Objects as Objects
89 87
import qualified Ganeti.OpCodes as OpCodes
90
import qualified Ganeti.Rpc as Rpc
91 88
import qualified Ganeti.Query.Language as Qlang
92 89
import qualified Ganeti.Runtime as Runtime
93 90
import qualified Ganeti.Ssconf as Ssconf
......
281 278
  n <- choose (1, 32)
282 279
  vectorOf n getName
283 280

  
284
-- | Defines a tag type.
285
newtype TagChar = TagChar { tagGetChar :: Char }
286

  
287
-- | All valid tag chars. This doesn't need to match _exactly_
288
-- Ganeti's own tag regex, just enough for it to be close.
289
tagChar :: [Char]
290
tagChar = ['a'..'z'] ++ ['A'..'Z'] ++ ['0'..'9'] ++ ".+*/:@-"
291

  
292
instance Arbitrary TagChar where
293
  arbitrary = do
294
    c <- elements tagChar
295
    return (TagChar c)
296

  
297
-- | Generates a tag
298
genTag :: Gen [TagChar]
299
genTag = do
300
  -- the correct value would be C.maxTagLen, but that's way too
301
  -- verbose in unittests, and at the moment I don't see any possible
302
  -- bugs with longer tags and the way we use tags in htools
303
  n <- choose (1, 10)
304
  vector n
305

  
306
-- | Generates a list of tags (correctly upper bounded).
307
genTags :: Gen [String]
308
genTags = do
309
  -- the correct value would be C.maxTagsPerObj, but per the comment
310
  -- in genTag, we don't use tags enough in htools to warrant testing
311
  -- such big values
312
  n <- choose (0, 10::Int)
313
  tags <- mapM (const genTag) [1..n]
314
  return $ map (map tagGetChar) tags
315

  
316 281
instance Arbitrary Types.InstanceStatus where
317 282
    arbitrary = elements [minBound..maxBound]
318 283

  
......
489 454
                         , Types.iPolicySpindleRatio = spindle_ratio
490 455
                         }
491 456

  
492
instance Arbitrary Objects.Hypervisor where
493
  arbitrary = elements [minBound..maxBound]
494

  
495
instance Arbitrary Objects.PartialNDParams where
496
  arbitrary = Objects.PartialNDParams <$> arbitrary <*> arbitrary
497

  
498
instance Arbitrary Objects.Node where
499
  arbitrary = Objects.Node <$> getFQDN <*> getFQDN <*> getFQDN
500
              <*> arbitrary <*> arbitrary <*> arbitrary <*> getFQDN
501
              <*> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
502
              <*> arbitrary <*> arbitrary <*> getFQDN <*> arbitrary
503
              <*> (Set.fromList <$> genTags)
504

  
505
instance Arbitrary Rpc.RpcCallAllInstancesInfo where
506
  arbitrary = Rpc.RpcCallAllInstancesInfo <$> arbitrary
507

  
508
instance Arbitrary Rpc.RpcCallInstanceList where
509
  arbitrary = Rpc.RpcCallInstanceList <$> arbitrary
510

  
511
instance Arbitrary Rpc.RpcCallNodeInfo where
512
  arbitrary = Rpc.RpcCallNodeInfo <$> arbitrary <*> arbitrary
513

  
514 457
-- | Custom 'Qlang.Filter' generator (top-level), which enforces a
515 458
-- (sane) limit on the depth of the generated filters.
516 459
genFilter :: Gen (Qlang.Filter Qlang.FilterField)
......
1976 1919
  [ 'prop_Ssconf_filename
1977 1920
  ]
1978 1921

  
1979
-- * Rpc tests
1980

  
1981
-- | Monadic check that, for an offline node and a call that does not
1982
-- offline nodes, we get a OfflineNodeError response.
1983
-- FIXME: We need a way of generalizing this, running it for
1984
-- every call manually will soon get problematic
1985
prop_Rpc_noffl_request_allinstinfo :: Rpc.RpcCallAllInstancesInfo -> Property
1986
prop_Rpc_noffl_request_allinstinfo call =
1987
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
1988
      res <- run $ Rpc.executeRpcCall [node] call
1989
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
1990

  
1991
prop_Rpc_noffl_request_instlist :: Rpc.RpcCallInstanceList -> Property
1992
prop_Rpc_noffl_request_instlist call =
1993
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
1994
      res <- run $ Rpc.executeRpcCall [node] call
1995
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
1996

  
1997
prop_Rpc_noffl_request_nodeinfo :: Rpc.RpcCallNodeInfo -> Property
1998
prop_Rpc_noffl_request_nodeinfo call =
1999
  forAll (arbitrary `suchThat` Objects.nodeOffline) $ \node -> monadicIO $ do
2000
      res <- run $ Rpc.executeRpcCall [node] call
2001
      stop $ res ==? [(node, Left (Rpc.OfflineNodeError node))]
2002

  
2003
testSuite "Rpc"
2004
  [ 'prop_Rpc_noffl_request_allinstinfo
2005
  , 'prop_Rpc_noffl_request_instlist
2006
  , 'prop_Rpc_noffl_request_nodeinfo
2007
  ]
2008

  
2009 1922
-- * Qlang tests
2010 1923

  
2011 1924
-- | Tests that serialisation/deserialisation of filters is

Also available in: Unified diff