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