Revision 51000365 htest/Test/Ganeti/HTools/CLI.hs

b/htest/Test/Ganeti/HTools/CLI.hs
28 28

  
29 29
module Test.Ganeti.HTools.CLI (testHTools_CLI) where
30 30

  
31
import Test.HUnit
31 32
import Test.QuickCheck
32 33

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

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

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

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

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

  
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 62
-- | 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)
63
prop_string_arg :: String -> Property
64
prop_string_arg argument =
65
  let args = [ (oDataFile,      optDataFile)
66
             , (oDynuFile,      optDynuFile)
67
             , (oSaveCluster,   optSaveCluster)
68
             , (oPrintCommands, optShowCmds)
69
             , (oLuxiSocket,    optLuxi)
70
             , (oIAllocSrc,     optIAllocSrc)
71
             ]
72
  in conjoin $ map (\(o, opt) ->
73
                      checkOpt Just defaultOptions
74
                      failTest (const (==?)) Just (argument, o, opt)) args
75

  
76
-- | Test a few positive arguments.
77
prop_numeric_arg :: Positive Double -> Property
78
prop_numeric_arg (Positive argument) =
79
  let args = [ (oMaxCpu,     optMcpu)
80
             , (oMinDisk,    Just . optMdsk)
81
             , (oMinGain,    Just . optMinGain)
82
             , (oMinGainLim, Just . optMinGainLim)
83
             , (oMinScore,   Just . optMinScore)
95 84
             ]
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, _) ->
103
      printTestCase ("Program " ++ name ++
104
                     " returns invalid code " ++ show code ++
105
                     " for option " ++ param) (code == 0)
106
    _ -> failTest $ "Program " ++ name ++ " doesn't consider option " ++
107
         param ++ " as early exit one"
108

  
109
-- | Test that all binaries support some common options. There is
110
-- nothing actually random about this test...
111
prop_stdopts :: Property
112
prop_stdopts =
113
  let params = ["-h", "--help", "-V", "--version"]
114
      opts = map (\(name, (_, o)) -> (name, o)) Program.personalities
115
      -- apply checkEarlyExit across the cartesian product of params and opts
116
  in conjoin [checkEarlyExit n o p | p <- params, (n, o) <- opts]
85
  in conjoin $
86
     map (\(x, y) -> checkOpt (Just . show) defaultOptions
87
                     failTest (const (==?)) Just (argument, x, y)) args
88

  
89
-- | Test a few boolean arguments.
90
case_bool_arg :: Assertion
91
case_bool_arg =
92
  mapM_ (checkOpt (const Nothing) defaultOptions assertFailure
93
                  assertEqual id)
94
        [ (False, oDiskMoves,    optDiskMoves)
95
        , (False, oInstMoves,    optInstMoves)
96
        , (True,  oEvacMode,     optEvacMode)
97
        , (True,  oExecJobs,     optExecJobs)
98
        , (True,  oNoHeaders,    optNoHeaders)
99
        , (True,  oNoSimulation, optNoSimulation)
100
        ]
101

  
102
-- | Tests a few invalid arguments.
103
case_wrong_arg :: Assertion
104
case_wrong_arg = do
105
  mapM_ (passFailOpt defaultOptions assertFailure (return ()))
106
        [ (oSpindleUse,   "-1", "1")
107
        , (oSpindleUse,   "a",  "1")
108
        , (oMaxCpu,       "-1", "1")
109
        , (oMinDisk,      "a",  "1")
110
        , (oMinGainLim,   "a",  "1")
111
        , (oMaxSolLength, "x",  "10")
112
        , (oStdSpec,      "no-such-spec", "1,1,1")
113
        , (oTieredSpec,   "no-such-spec", "1,1,1")
114
        ]
115

  
116
-- | Test that all binaries support some common options.
117
case_stdopts :: Assertion
118
case_stdopts =
119
  mapM_ (\(name, (_, o)) -> checkEarlyExit defaultOptions name o)
120
      Program.personalities
117 121

  
118 122
testSuite "HTools/CLI"
119 123
          [ 'prop_parseISpec
120 124
          , 'prop_parseISpecFail
121
          , 'prop_parseYesNo
122
          , 'prop_StringArg
123
          , 'prop_stdopts
125
          , 'prop_string_arg
126
          , 'prop_numeric_arg
127
          , 'case_bool_arg
128
          , 'case_wrong_arg
129
          , 'case_stdopts
124 130
          ]

Also available in: Unified diff