Revision c5a957c3

b/Makefile.am
1070 1070
	test/data/xen-xm-list-4.0.1-dom0-only.txt \
1071 1071
	test/data/xen-xm-list-4.0.1-four-instances.txt \
1072 1072
	test/data/xen-xm-list-long-4.0.1.txt \
1073
	test/data/xen-xm-uptime-4.0.1.txt \
1073 1074
	test/py/ganeti-cli.test \
1074 1075
	test/py/gnt-cli.test \
1075 1076
	test/py/import-export_unittest-helper
b/src/Ganeti/Hypervisor/Xen/Types.hs
26 26
  ( LispConfig(..)
27 27
  , Domain(..)
28 28
  , FromLispConfig(..)
29
  , UptimeInfo(..)
29 30
  , ActualState(..)
30 31
  ) where
31 32

  
......
84 85
    Bad $ "Unable to extract a List from this configuration: "
85 86
      ++ show c
86 87

  
88
-- Data type representing the information that can be obtained from @xm uptime@
89
data UptimeInfo = UptimeInfo
90
  { uInfoName   :: String
91
  , uInfoID     :: Int
92
  , uInfoUptime :: String
93
  } deriving (Eq, Show)
94

  
87 95
data ActualState = ActualRunning  -- ^ The instance is running
88 96
                 | ActualBlocked  -- ^ The instance is not running or runnable
89 97
                 | ActualPaused   -- ^ The instance has been paused
b/src/Ganeti/Hypervisor/Xen/XmParser.hs
25 25
module Ganeti.Hypervisor.Xen.XmParser
26 26
  ( xmListParser
27 27
  , lispConfigParser
28
  , xmUptimeParser
29
  , uptimeLineParser
28 30
  ) where
29 31

  
30 32
import Control.Applicative
......
137 139
  case foldM foldResult Map.empty domains of
138 140
    Ok d -> return d
139 141
    Bad msg -> fail msg
142

  
143
-- | A parser for parsing the output of the @xm uptime@ command.
144
xmUptimeParser :: Parser (Map.Map Int UptimeInfo)
145
xmUptimeParser = do
146
  _ <- headerParser
147
  uptimes <- uptimeLineParser `AC.manyTill` A.endOfInput
148
  return $ Map.fromList [(uInfoID u, u) | u <- uptimes]
149
    where headerParser = A.string "Name" <* A.skipSpace <* A.string "ID"
150
            <* A.skipSpace <* A.string "Uptime" <* A.skipSpace
151

  
152
-- | A helper for parsing a single line of the @xm uptime@ output.
153
uptimeLineParser :: Parser UptimeInfo
154
uptimeLineParser = do
155
  name <- A.takeTill isSpace <* A.skipSpace
156
  idNum <- A.decimal <* A.skipSpace
157
  uptime <- A.takeTill (`elem` "\n\r") <* A.skipSpace
158
  return . UptimeInfo (unpack name) idNum $ unpack uptime
b/test/data/xen-xm-uptime-4.0.1.txt
1
Name                                ID Uptime
2
Domain-0                             0 98 days,  2:27:44
3
instance1.example.com               119 15 days, 20:57:07
b/test/hs/Test/Ganeti/Hypervisor/Xen/XmParser.hs
39 39
import Data.Text (pack)
40 40
import Data.Char
41 41
import qualified Data.Map as Map
42
import Text.Printf
42 43

  
43 44
import Ganeti.Hypervisor.Xen.Types
44 45
import Ganeti.Hypervisor.Xen.XmParser
......
70 71
canBeNumberChar :: Char -> Bool
71 72
canBeNumberChar c = isDigit c || (c `elem` "eE-")
72 73

  
74
-- | Generates an arbitrary @xm uptime@ output line.
75
instance Arbitrary UptimeInfo where
76
  arbitrary = do
77
    name <- genFQDN
78
    NonNegative idNum <- arbitrary :: Gen (NonNegative Int)
79
    NonNegative days <- arbitrary :: Gen (NonNegative Int)
80
    hours <- choose (0, 23) :: Gen Int
81
    mins <- choose (0, 59) :: Gen Int
82
    secs <- choose (0, 59) :: Gen Int
83
    let uptime :: String
84
        uptime =
85
          if days /= 0
86
            then printf "%d days, %d:%d:%d" days hours mins secs
87
            else printf "%d:%d:%d" hours mins secs
88
    return $ UptimeInfo name idNum uptime
89

  
73 90
-- * Helper functions for tests
74 91

  
75 92
-- | Function for testing whether a domain configuration is parsed correctly.
76 93
testDomain :: String -> Map.Map String Domain -> Assertion
77 94
testDomain fileName expectedContent = do
78
    fileContent <- readTestData fileName
79
    case A.parseOnly xmListParser $ pack fileContent of
80
        Left msg -> assertFailure $ "Parsing failed: " ++ msg
81
        Right obtained -> assertEqual fileName expectedContent obtained
95
  fileContent <- readTestData fileName
96
  case A.parseOnly xmListParser $ pack fileContent of
97
    Left msg -> assertFailure $ "Parsing failed: " ++ msg
98
    Right obtained -> assertEqual fileName expectedContent obtained
99

  
100
-- | Function for testing whether a @xm uptime@ output (stored in a file)
101
-- is parsed correctly.
102
testUptimeInfo :: String -> Map.Map Int UptimeInfo -> Assertion
103
testUptimeInfo fileName expectedContent = do
104
  fileContent <- readTestData fileName
105
  case A.parseOnly xmUptimeParser $ pack fileContent of
106
    Left msg -> assertFailure $ "Parsing failed: " ++ msg
107
    Right obtained -> assertEqual fileName expectedContent obtained
82 108

  
83 109
-- | Determines whether two LispConfig are equal, with the exception of Double
84 110
-- values, that just need to be "almost equal".
......
102 128
serializeConf (LCString s) = s
103 129
serializeConf (LCDouble d) = show d
104 130

  
131
-- | Function to serialize UptimeInfos in such a way that they can be rebuilt
132
-- againg by the uptimeLineParser.
133
serializeUptime :: UptimeInfo -> String
134
serializeUptime (UptimeInfo name idNum uptime) =
135
  printf "%s\t%d\t%s" name idNum uptime
136

  
105 137
-- | Test whether a randomly generated config can be parsed.
106 138
-- Implicitly, this also tests that the Show instance of Config is correct.
107 139
prop_config :: LispConfig -> Property
......
110 142
        Left msg -> fail $ "Parsing failed: " ++ msg
111 143
        Right obtained -> property $ isAlmostEqual obtained conf
112 144

  
145
-- | Test whether a randomly generated UptimeInfo text line can be parsed.
146
prop_uptimeInfo :: UptimeInfo -> Property
147
prop_uptimeInfo uInfo =
148
  case A.parseOnly uptimeLineParser . pack . serializeUptime $ uInfo of
149
    Left msg -> fail $ "Parsing failed: " ++ msg
150
    Right obtained -> obtained ==? uInfo
151

  
113 152
-- | Test a Xen 4.0.1 @xm list --long@ output.
114 153
case_xen401list :: Assertion
115 154
case_xen401list = testDomain "xen-xm-list-long-4.0.1.txt" $
......
119 158
      ActualBlocked Nothing)
120 159
    ]
121 160

  
161
-- | Test a Xen 4.0.1 @xm uptime@ output.
162
case_xen401uptime :: Assertion
163
case_xen401uptime = testUptimeInfo "xen-xm-uptime-4.0.1.txt" $
164
  Map.fromList
165
    [ (0, UptimeInfo "Domain-0" 0 "98 days,  2:27:44")
166
    , (119, UptimeInfo "instance1.example.com" 119 "15 days, 20:57:07")
167
    ]
168

  
122 169
testSuite "Hypervisor/Xen/XmParser"
123 170
          [ 'prop_config
171
          , 'prop_uptimeInfo
124 172
          , 'case_xen401list
173
          , 'case_xen401uptime
125 174
          ]

Also available in: Unified diff