1 {-# LANGUAGE TemplateHaskell #-}
2 {-# OPTIONS_GHC -fno-warn-orphans #-}
4 {-| Unittests for ganeti-htools.
10 Copyright (C) 2009, 2010, 2011, 2012 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.Query.Query (testQuery_Query) where
31 import Test.HUnit (Assertion, assertEqual)
32 import Test.QuickCheck hiding (Result)
33 import Test.QuickCheck.Monadic
35 import Data.Function (on)
37 import qualified Data.Map as Map
39 import Text.JSON (JSValue(..))
41 import Test.Ganeti.TestHelper
42 import Test.Ganeti.TestCommon
43 import Test.Ganeti.Objects (genEmptyCluster)
45 import Ganeti.BasicTypes
46 import Ganeti.Query.Group
47 import Ganeti.Query.Language
48 import Ganeti.Query.Node
49 import Ganeti.Query.Query
51 {-# ANN module "HLint: ignore Use camelCase" #-}
55 -- | Checks if a list of field definitions contains unknown fields.
56 hasUnknownFields :: [FieldDefinition] -> Bool
57 hasUnknownFields = (QFTUnknown `notElem`) . map fdefKind
61 -- | Tests that querying any existing fields, via either query or
62 -- queryFields, will not return unknown fields.
63 prop_queryNode_noUnknown :: Property
64 prop_queryNode_noUnknown =
65 forAll (choose (0, maxNodes) >>= genEmptyCluster) $ \cluster ->
66 forAll (elements (Map.keys nodeFieldsMap)) $ \field -> monadicIO $ do
67 QueryResult fdefs fdata <-
68 run (query cluster False (Query QRNode [field] EmptyFilter)) >>= resultProp
69 QueryFieldsResult fdefs' <-
70 resultProp $ queryFields (QueryFields QRNode [field])
71 stop $ printTestCase ("Got unknown fields via query (" ++ show fdefs ++ ")")
72 (hasUnknownFields fdefs) .&&.
73 printTestCase ("Got unknown result status via query (" ++
75 (all (all ((/= RSUnknown) . rentryStatus)) fdata) .&&.
76 printTestCase ("Got unknown fields via query fields (" ++ show fdefs'
77 ++ ")") (hasUnknownFields fdefs')
79 -- | Tests that an unknown field is returned as such.
80 prop_queryNode_Unknown :: Property
81 prop_queryNode_Unknown =
82 forAll (choose (0, maxNodes) >>= genEmptyCluster) $ \cluster ->
83 forAll (arbitrary `suchThat` (`notElem` Map.keys nodeFieldsMap))
84 $ \field -> monadicIO $ do
85 QueryResult fdefs fdata <-
86 run (query cluster False (Query QRNode [field] EmptyFilter)) >>= resultProp
87 QueryFieldsResult fdefs' <-
88 resultProp $ queryFields (QueryFields QRNode [field])
89 stop $ printTestCase ("Got known fields via query (" ++ show fdefs ++ ")")
90 (not $ hasUnknownFields fdefs) .&&.
91 printTestCase ("Got /= ResultUnknown result status via query (" ++
93 (all (all ((== RSUnknown) . rentryStatus)) fdata) .&&.
94 printTestCase ("Got a Just in a result value (" ++
96 (all (all (isNothing . rentryValue)) fdata) .&&.
97 printTestCase ("Got known fields via query fields (" ++ show fdefs'
98 ++ ")") (not $ hasUnknownFields fdefs')
100 -- | Checks that a result type is conforming to a field definition.
101 checkResultType :: FieldDefinition -> ResultEntry -> Property
102 checkResultType _ (ResultEntry RSNormal Nothing) =
103 failTest "Nothing result in RSNormal field"
104 checkResultType _ (ResultEntry _ Nothing) = passTest
105 checkResultType fdef (ResultEntry RSNormal (Just v)) =
106 case (fdefKind fdef, v) of
107 (QFTText , JSString {}) -> passTest
108 (QFTBool , JSBool {}) -> passTest
109 (QFTNumber , JSRational {}) -> passTest
110 (QFTTimestamp , JSRational {}) -> passTest
111 (QFTUnit , JSRational {}) -> passTest
112 (QFTOther , _) -> passTest -- meh, QFT not precise...
113 (kind, _) -> failTest $ "Type mismatch, field definition says " ++
114 show kind ++ " but returned value is " ++ show v ++
115 " for field '" ++ fdefName fdef ++ "'"
116 checkResultType _ (ResultEntry r (Just _)) =
117 failTest $ "Just result in " ++ show r ++ " field"
119 -- | Tests that querying any existing fields, the following three
120 -- properties hold: RSNormal corresponds to a Just value, any other
121 -- value corresponds to Nothing, and for a RSNormal and value field,
122 -- the type of the value corresponds to the type of the field as
123 -- declared in the FieldDefinition.
124 prop_queryNode_types :: Property
125 prop_queryNode_types =
126 forAll (choose (0, maxNodes)) $ \numnodes ->
127 forAll (genEmptyCluster numnodes) $ \cfg ->
128 forAll (elements (Map.keys nodeFieldsMap)) $ \field -> monadicIO $ do
129 QueryResult fdefs fdata <-
130 run (query cfg False (Query QRNode [field] EmptyFilter)) >>= resultProp
131 stop $ printTestCase ("Inconsistent result entries (" ++ show fdata ++ ")")
132 (conjoin $ map (conjoin . zipWith checkResultType fdefs) fdata) .&&.
133 printTestCase "Wrong field definitions length"
134 (length fdefs ==? 1) .&&.
135 printTestCase "Wrong field result rows length"
136 (all ((== 1) . length) fdata) .&&.
137 printTestCase "Wrong number of result rows"
138 (length fdata ==? numnodes)
140 -- | Test that queryFields with empty fields list returns all node fields.
141 case_queryNode_allfields :: Assertion
142 case_queryNode_allfields = do
143 fdefs <- case queryFields (QueryFields QRNode []) of
144 Bad msg -> fail $ "Error in query all fields: " ++ msg
145 Ok (QueryFieldsResult v) -> return v
146 let field_sort = compare `on` fdefName
147 assertEqual "Mismatch in all fields list"
148 (sortBy field_sort . map fst $ Map.elems nodeFieldsMap)
149 (sortBy field_sort fdefs)
151 -- * Same as above, but for group
153 prop_queryGroup_noUnknown :: Property
154 prop_queryGroup_noUnknown =
155 forAll (choose (0, maxNodes) >>= genEmptyCluster) $ \cluster ->
156 forAll (elements (Map.keys groupFieldsMap)) $ \field -> monadicIO $ do
157 QueryResult fdefs fdata <-
158 run (query cluster False (Query QRGroup [field] EmptyFilter)) >>= resultProp
159 QueryFieldsResult fdefs' <-
160 resultProp $ queryFields (QueryFields QRGroup [field])
161 stop $ printTestCase ("Got unknown fields via query (" ++ show fdefs ++ ")")
162 (hasUnknownFields fdefs) .&&.
163 printTestCase ("Got unknown result status via query (" ++
165 (all (all ((/= RSUnknown) . rentryStatus)) fdata) .&&.
166 printTestCase ("Got unknown fields via query fields (" ++ show fdefs'
167 ++ ")") (hasUnknownFields fdefs')
169 prop_queryGroup_Unknown :: Property
170 prop_queryGroup_Unknown =
171 forAll (choose (0, maxNodes) >>= genEmptyCluster) $ \cluster ->
172 forAll (arbitrary `suchThat` (`notElem` Map.keys groupFieldsMap))
173 $ \field -> monadicIO $ do
174 QueryResult fdefs fdata <-
175 run (query cluster False (Query QRGroup [field] EmptyFilter)) >>= resultProp
176 QueryFieldsResult fdefs' <-
177 resultProp $ queryFields (QueryFields QRGroup [field])
178 stop $ printTestCase ("Got known fields via query (" ++ show fdefs ++ ")")
179 (not $ hasUnknownFields fdefs) .&&.
180 printTestCase ("Got /= ResultUnknown result status via query (" ++
182 (all (all ((== RSUnknown) . rentryStatus)) fdata) .&&.
183 printTestCase ("Got a Just in a result value (" ++
185 (all (all (isNothing . rentryValue)) fdata) .&&.
186 printTestCase ("Got known fields via query fields (" ++ show fdefs'
187 ++ ")") (not $ hasUnknownFields fdefs')
189 prop_queryGroup_types :: Property
190 prop_queryGroup_types =
191 forAll (choose (0, maxNodes)) $ \numnodes ->
192 forAll (genEmptyCluster numnodes) $ \cfg ->
193 forAll (elements (Map.keys groupFieldsMap)) $ \field -> monadicIO $ do
194 QueryResult fdefs fdata <-
195 run (query cfg False (Query QRGroup [field] EmptyFilter)) >>= resultProp
196 stop $ printTestCase ("Inconsistent result entries (" ++ show fdata ++ ")")
197 (conjoin $ map (conjoin . zipWith checkResultType fdefs) fdata) .&&.
198 printTestCase "Wrong field definitions length"
199 (length fdefs ==? 1) .&&.
200 printTestCase "Wrong field result rows length"
201 (all ((== 1) . length) fdata)
203 case_queryGroup_allfields :: Assertion
204 case_queryGroup_allfields = do
205 fdefs <- case queryFields (QueryFields QRGroup []) of
206 Bad msg -> fail $ "Error in query all fields: " ++ msg
207 Ok (QueryFieldsResult v) -> return v
208 let field_sort = compare `on` fdefName
209 assertEqual "Mismatch in all fields list"
210 (sortBy field_sort . map fst $ Map.elems groupFieldsMap)
211 (sortBy field_sort fdefs)
213 testSuite "Query/Query"
214 [ 'prop_queryNode_noUnknown
215 , 'prop_queryNode_Unknown
216 , 'prop_queryNode_types
217 , 'case_queryNode_allfields
218 , 'prop_queryGroup_noUnknown
219 , 'prop_queryGroup_Unknown
220 , 'prop_queryGroup_types
221 , 'case_queryGroup_allfields