From 834bea99eeebca50477217297a385a212a802ba1 Mon Sep 17 00:00:00 2001 From: Helga Velroyen <helgav@google.com> Date: Thu, 7 Feb 2013 18:30:04 +0100 Subject: [PATCH] Unit tests for Query/Network.hs This patch adds a couple of unit tests for Query/Network.hs. Note that they'll need to be adapted, once issue 362 is addressed. Signed-off-by: Helga Velroyen <helgav@google.com> Reviewed-by: Iustin Pop <iustin@google.com> --- Makefile.am | 1 + src/Ganeti/Query/Network.hs | 11 ++- test/hs/Test/Ganeti/Objects.hs | 37 +++++++++ test/hs/Test/Ganeti/Query/Network.hs | 110 +++++++++++++++++++++++++++ test/hs/htest.hs | 2 + 5 files changed, 158 insertions(+), 3 deletions(-) create mode 100644 test/hs/Test/Ganeti/Query/Network.hs diff --git a/Makefile.am b/Makefile.am index 60118fe31..7425e2221 100644 --- a/Makefile.am +++ b/Makefile.am @@ -584,6 +584,7 @@ HS_TEST_SRCS = \ test/hs/Test/Ganeti/OpCodes.hs \ test/hs/Test/Ganeti/Query/Filter.hs \ test/hs/Test/Ganeti/Query/Language.hs \ + test/hs/Test/Ganeti/Query/Network.hs \ test/hs/Test/Ganeti/Query/Query.hs \ test/hs/Test/Ganeti/Rpc.hs \ test/hs/Test/Ganeti/Runtime.hs \ diff --git a/src/Ganeti/Query/Network.hs b/src/Ganeti/Query/Network.hs index 2d262bfa0..a9c46c7d5 100644 --- a/src/Ganeti/Query/Network.hs +++ b/src/Ganeti/Query/Network.hs @@ -24,10 +24,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -} module Ganeti.Query.Network - ( NetworkRuntime(..) + ( getGroupConnection + , getNetworkUuid + , instIsConnected + , NetworkRuntime(..) , networkFieldsMap ) where +-- FIXME: everything except NetworkRuntime(..) and networkFieldsMap +-- is only exported for testing. + import qualified Data.Map as Map import Data.Maybe (fromMaybe, mapMaybe) import Data.List (find) @@ -88,8 +94,7 @@ networkFieldsMap :: FieldMap Network NetworkRuntime networkFieldsMap = Map.fromList $ map (\v@(f, _, _) -> (fdefName f, v)) networkFields --- TODO: the following fields are not implemented yet: external_reservations, --- inst_cnt, inst_list +-- TODO: the following fields are not implemented yet: external_reservations -- | Given a network's UUID, this function lists all connections from -- the network to nodegroups including the respective mode and links. diff --git a/test/hs/Test/Ganeti/Objects.hs b/test/hs/Test/Ganeti/Objects.hs index dc619eccf..e1752ee56 100644 --- a/test/hs/Test/Ganeti/Objects.hs +++ b/test/hs/Test/Ganeti/Objects.hs @@ -29,7 +29,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA module Test.Ganeti.Objects ( testObjects , Node(..) + , genConfigDataWithNetworks , genEmptyCluster + , genInstWithNets , genValidNetwork , genBitStringMaxLen ) where @@ -40,6 +42,7 @@ import qualified Test.HUnit as HUnit import Control.Applicative import Control.Monad import Data.Char +import qualified Data.List as List import qualified Data.Map as Map import qualified Data.Set as Set import qualified Text.JSON as J @@ -116,6 +119,22 @@ instance Arbitrary Instance where -- tags <*> (Set.fromList <$> genTags) +-- | Generates an instance that is connected to the given networks +-- and possibly some other networks +genInstWithNets :: [String] -> Gen Instance +genInstWithNets nets = do + plain_inst <- arbitrary + mac <- arbitrary + ip <- arbitrary + nicparams <- arbitrary + -- generate some more networks than the given ones + num_more_nets <- choose (0,3) + more_nets <- vectorOf num_more_nets genName + let partial_nics = map (PartialNic mac ip nicparams . Just) + (List.nub (nets ++ more_nets)) + new_inst = plain_inst { instNics = partial_nics } + return new_inst + -- | FIXME: This generates completely random data, without normal -- validation rules. $(genArbitrary ''PartialISpecParams) @@ -216,6 +235,24 @@ genEmptyCluster ncount = do serial return c +-- | FIXME: make an even simpler base version of creating a cluster. + +-- | Generates config data with a couple of networks. +genConfigDataWithNetworks :: ConfigData -> Gen ConfigData +genConfigDataWithNetworks old_cfg = do + num_nets <- choose (0, 3) + -- generate a list of network names (no duplicates) + net_names <- genUniquesList num_nets genName >>= mapM mkNonEmpty + -- generate a random list of networks (possibly with duplicate names) + nets <- vectorOf num_nets genValidNetwork + -- use unique names for the networks + let nets_unique = map ( \(name, net) -> net { networkName = name } ) + (zip net_names nets) + net_map = GenericContainer $ Map.fromList + (map (\n -> (networkUuid n, n)) nets_unique) + new_cfg = old_cfg { configNetworks = net_map } + return new_cfg + -- * Test properties -- | Tests that fillDict behaves correctly diff --git a/test/hs/Test/Ganeti/Query/Network.hs b/test/hs/Test/Ganeti/Query/Network.hs new file mode 100644 index 000000000..4a3ae50bb --- /dev/null +++ b/test/hs/Test/Ganeti/Query/Network.hs @@ -0,0 +1,110 @@ +{-# LANGUAGE TemplateHaskell #-} +{-# OPTIONS_GHC -fno-warn-orphans #-} + +{-| Unittests for Network Queries. + +-} + +{- + +Copyright (C) 2013 Google Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. + +-} + +module Test.Ganeti.Query.Network + ( testQuery_Network + ) where + +import Ganeti.JSON +import Ganeti.Objects +import Ganeti.Query.Network +import Ganeti.Types + +import Test.Ganeti.Objects +import Test.Ganeti.TestCommon +import Test.Ganeti.TestHelper + +import Test.QuickCheck + +import qualified Data.Map as Map +import Data.Maybe + +instance Arbitrary ConfigData where + arbitrary = genEmptyCluster 0 >>= genConfigDataWithNetworks + +-- | Check if looking up a valid network ID of a nodegroup yields +-- a non-Nothing result. +prop_getGroupConnection :: NodeGroup -> Property +prop_getGroupConnection group = + let net_keys = (Map.keys . fromContainer . groupNetworks) group + in True ==? all + (\nk -> isJust (getGroupConnection nk group)) net_keys + +-- | Checks if looking up an ID of a non-existing network in a node group +-- yields 'Nothing'. +prop_getGroupConnection_notFound :: NodeGroup -> String -> Property +prop_getGroupConnection_notFound group uuid = + let net_keys = (Map.keys . fromContainer . groupNetworks) group + in notElem uuid net_keys ==> isNothing (getGroupConnection uuid group) + +-- | Check if getting the network's UUID from the config actually gets the +-- correct UUIDs. +prop_getNetworkUuid :: ConfigData -> Property +prop_getNetworkUuid cfg = + let nets = (Map.elems . fromContainer . configNetworks) cfg + in True ==? all + (\n -> fromJust (getNetworkUuid cfg ((fromNonEmpty . networkName) n)) + == networkUuid n) nets + +-- | Check if trying to get a UUID of a non-existing networks results in +-- 'Nothing'. +prop_getNetworkUuid_notFound :: ConfigData -> String -> Property +prop_getNetworkUuid_notFound cfg uuid = + let net_keys = (Map.keys . fromContainer . configNetworks) cfg + in notElem uuid net_keys ==> isNothing (getNetworkUuid cfg uuid) + +-- | Checks whether actually connected instances are identified as such. +prop_instIsConnected :: ConfigData -> Property +prop_instIsConnected cfg = + let nets = (fromContainer . configNetworks) cfg + net_keys = Map.keys nets + net_names = map (fromNonEmpty . networkName) (Map.elems nets) + in forAll (genInstWithNets net_names) $ \inst -> + True ==? all (\nk -> instIsConnected cfg nk inst) net_keys + +-- | Tests whether instances that are not connected to a network are +-- correctly classified as such. +prop_instIsConnected_notFound :: ConfigData -> String -> Property +prop_instIsConnected_notFound cfg network_uuid = + let nets = (fromContainer . configNetworks) cfg + net_keys = Map.keys nets + net_names = map (fromNonEmpty . networkName) (Map.elems nets) + in notElem network_uuid net_keys ==> + forAll (genInstWithNets net_names) $ \inst -> + not (instIsConnected cfg network_uuid inst) + +testSuite "Query_Network" + [ 'prop_getNetworkUuid + , 'prop_getNetworkUuid_notFound + , 'prop_getGroupConnection + , 'prop_getGroupConnection_notFound + , 'prop_instIsConnected + , 'prop_instIsConnected_notFound + ] + + diff --git a/test/hs/htest.hs b/test/hs/htest.hs index 4358c8589..b93ba81e2 100644 --- a/test/hs/htest.hs +++ b/test/hs/htest.hs @@ -61,6 +61,7 @@ import Test.Ganeti.Objects import Test.Ganeti.OpCodes import Test.Ganeti.Query.Filter import Test.Ganeti.Query.Language +import Test.Ganeti.Query.Network import Test.Ganeti.Query.Query import Test.Ganeti.Rpc import Test.Ganeti.Runtime @@ -114,6 +115,7 @@ allTests = , testOpCodes , testQuery_Filter , testQuery_Language + , testQuery_Network , testQuery_Query , testRpc , testRuntime -- GitLab