Statistics
| Branch: | Tag: | Revision:

root / htest / Test / Ganeti / HTools / CLI.hs @ 20bc5360

History | View | Annotate | Download (4.5 kB)

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.HTools.CLI (testCLI) where
30

    
31
import Test.QuickCheck
32

    
33
import Control.Monad
34
import Data.List
35
import Text.Printf (printf)
36
import qualified System.Console.GetOpt as GetOpt
37

    
38
import Test.Ganeti.TestHelper
39
import Test.Ganeti.TestCommon
40

    
41
import qualified Ganeti.HTools.CLI as CLI
42
import qualified Ganeti.HTools.Program as Program
43
import qualified Ganeti.HTools.Types as Types
44

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

    
51
-- | Test parsing failure due to wrong section count.
52
prop_parseISpecFail :: String -> Property
53
prop_parseISpecFail descr =
54
  forAll (choose (0,100) `suchThat` ((/=) 3)) $ \nelems ->
55
  forAll (replicateM nelems arbitrary) $ \values ->
56
  let str = intercalate "," $ map show (values::[Int])
57
  in case CLI.parseISpecString descr str of
58
       Types.Ok v -> failTest $ "Expected failure, got " ++ show v
59
       _ -> property True
60

    
61
-- | Test parseYesNo.
62
prop_parseYesNo :: Bool -> Bool -> [Char] -> Property
63
prop_parseYesNo def testval val =
64
  forAll (elements [val, "yes", "no"]) $ \actual_val ->
65
  if testval
66
    then CLI.parseYesNo def Nothing ==? Types.Ok def
67
    else let result = CLI.parseYesNo def (Just actual_val)
68
         in if actual_val `elem` ["yes", "no"]
69
              then result ==? Types.Ok (actual_val == "yes")
70
              else property $ Types.isBad result
71

    
72
-- | Helper to check for correct parsing of string arg.
73
checkStringArg :: [Char]
74
               -> (GetOpt.OptDescr (CLI.Options -> Types.Result CLI.Options),
75
                   CLI.Options -> Maybe [Char])
76
               -> Property
77
checkStringArg val (opt, fn) =
78
  let GetOpt.Option _ longs _ _ = opt
79
  in case longs of
80
       [] -> failTest "no long options?"
81
       cmdarg:_ ->
82
         case CLI.parseOptsInner ["--" ++ cmdarg ++ "=" ++ val] "prog" [opt] of
83
           Left e -> failTest $ "Failed to parse option: " ++ show e
84
           Right (options, _) -> fn options ==? Just val
85

    
86
-- | Test a few string arguments.
87
prop_StringArg :: [Char] -> Property
88
prop_StringArg argument =
89
  let args = [ (CLI.oDataFile,      CLI.optDataFile)
90
             , (CLI.oDynuFile,      CLI.optDynuFile)
91
             , (CLI.oSaveCluster,   CLI.optSaveCluster)
92
             , (CLI.oReplay,        CLI.optReplay)
93
             , (CLI.oPrintCommands, CLI.optShowCmds)
94
             , (CLI.oLuxiSocket,    CLI.optLuxi)
95
             ]
96
  in conjoin $ map (checkStringArg argument) args
97

    
98
-- | Helper to test that a given option is accepted OK with quick exit.
99
checkEarlyExit :: String -> [CLI.OptType] -> String -> Property
100
checkEarlyExit name options param =
101
  case CLI.parseOptsInner [param] name options of
102
    Left (code, _) -> if code == 0
103
                          then property True
104
                          else failTest $ "Program " ++ name ++
105
                                 " returns invalid code " ++ show code ++
106
                                 " for option " ++ param
107
    _ -> failTest $ "Program " ++ name ++ " doesn't consider option " ++
108
         param ++ " as early exit one"
109

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

    
119
testSuite "CLI"
120
          [ 'prop_parseISpec
121
          , 'prop_parseISpecFail
122
          , 'prop_parseYesNo
123
          , 'prop_StringArg
124
          , 'prop_stdopts
125
          ]