This commit introduces further test classes and methods for the Create
family of methods of the BlockDev subclasses and a few additional minor
cosmetic changes.

Signed-off-by: Federico Morg Pareschi <[email protected]>
---
 lib/storage/base.py                            |  13 ++
 lib/storage/gluster.py                         |   4 +-
 test/py/ganeti.storage.bdev_unittest.py        | 247 ++++++++++++++++++++++---
 test/py/ganeti.storage.drbd_unittest.py        |  88 ++++++++-
 test/py/ganeti.storage.extstorage_unittest.py  |  73 ++++++++
 test/py/ganeti.storage.filestorage_unittest.py |  56 ++++--
 test/py/ganeti.storage.gluster_unittest.py     |  41 +++-
 7 files changed, 475 insertions(+), 47 deletions(-)
 create mode 100755 test/py/ganeti.storage.extstorage_unittest.py

diff --git a/lib/storage/base.py b/lib/storage/base.py
index 588caf2..461fdad 100644
--- a/lib/storage/base.py
+++ b/lib/storage/base.py
@@ -93,6 +93,19 @@ class BlockDev(object):
     self.params = params
     self.dyn_params = dyn_params
 
+  def __eq__(self, other):
+    if not isinstance(self, type(other)):
+      return False
+    return (self._children == other._children and
+            self.dev_path == other.dev_path and
+            self.unique_id == other.unique_id and
+            self.major == other.major and
+            self.minor == other.minor and
+            self.attached == other.attached and
+            self.size == other.size and
+            self.params == other.params and
+            self.dyn_params == other.dyn_params)
+
   def Assemble(self):
     """Assemble the device from its components.
 
diff --git a/lib/storage/gluster.py b/lib/storage/gluster.py
index f8f5dea..b352d61 100644
--- a/lib/storage/gluster.py
+++ b/lib/storage/gluster.py
@@ -301,7 +301,7 @@ class GlusterStorage(base.BlockDev):
       base.ThrowError("Invalid setup for file device")
 
     try:
-      driver, path = unique_id
+      self.driver, self.path = unique_id
     except ValueError: # wrong number of arguments
       raise ValueError("Invalid configuration data %s" % repr(unique_id))
 
@@ -310,8 +310,6 @@ class GlusterStorage(base.BlockDev):
     volume = params[constants.GLUSTER_VOLUME]
 
     self.volume = GlusterVolume(server_addr, port, volume)
-    self.path = path
-    self.driver = driver
     self.full_path = io.PathJoin(self.volume.mount_point, self.path)
     self.file = None
 
diff --git a/test/py/ganeti.storage.bdev_unittest.py 
b/test/py/ganeti.storage.bdev_unittest.py
index 89f3b49..d107303 100755
--- a/test/py/ganeti.storage.bdev_unittest.py
+++ b/test/py/ganeti.storage.bdev_unittest.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2006, 2007, 2010, 2012, 2013 Google Inc.
+# Copyright (C) 2006, 2007, 2010, 2012, 2013, 2016 Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -44,11 +44,19 @@ from ganeti.storage import bdev
 
 import testutils
 
+def _FakeRunCmd(success, stdout, cmd):
+  if success:
+    exit_code = 0
+  else:
+    exit_code = 1
+  return utils.RunResult(exit_code, None, stdout, "", cmd,
+                         utils.process._TIMEOUT_NONE, 5)
 
 class TestRADOSBlockDevice(testutils.GanetiTestCase):
   """Tests for bdev.RADOSBlockDevice volumes
 
   """
+
   def setUp(self):
     """Set up input data"""
     testutils.GanetiTestCase.setUp(self)
@@ -84,7 +92,7 @@ class TestRADOSBlockDevice(testutils.GanetiTestCase):
       constants.LDP_POOL: "fake_pool"
       }
 
-  def test_ParseRbdShowmappedJson(self):
+  def testParseRbdShowmappedJson(self):
     parse_function = bdev.RADOSBlockDevice._ParseRbdShowmappedJson
 
     self.assertEqual(parse_function(self.json_output_ok, self.volume_name),
@@ -98,7 +106,7 @@ class TestRADOSBlockDevice(testutils.GanetiTestCase):
     self.assertRaises(errors.BlockDeviceError, parse_function,
                       self.output_invalid, self.volume_name)
 
-  def test_ParseRbdShowmappedPlain(self):
+  def testParseRbdShowmappedPlain(self):
     parse_function = bdev.RADOSBlockDevice._ParseRbdShowmappedPlain
 
     self.assertEqual(parse_function(self.plain_output_new_ok,
@@ -127,8 +135,7 @@ class TestRADOSBlockDevice(testutils.GanetiTestCase):
     """Test for bdev.RADOSBlockDevice.Import()"""
     # Set up the mock objects return values
     attach_mock.return_value = True
-    run_cmd_mock.return_value = \
-        utils.RunResult(0, None, "", "", "", utils.process._TIMEOUT_NONE, 0)
+    run_cmd_mock.return_value = _FakeRunCmd(True, "", "")
 
     # Create a fake rbd volume
     inst = bdev.RADOSBlockDevice(self.test_unique_id, [], 1024,
@@ -156,6 +163,34 @@ class TestRADOSBlockDevice(testutils.GanetiTestCase):
 
     self.assertEqual(inst.Export(), export_cmd)
 
+  @testutils.patch_object(utils, "RunCmd")
+  @testutils.patch_object(bdev.RADOSBlockDevice, "Attach")
+  def testRADOSBlockDeviceCreate(self, attach_mock, run_cmd_mock):
+    """Test for bdev.RADOSBlockDevice.Create() success"""
+    attach_mock.return_value = True
+    # This returns a successful RunCmd result
+    run_cmd_mock.return_value = _FakeRunCmd(True, "", "")
+
+    expect = bdev.RADOSBlockDevice(self.test_unique_id, [], 1024,
+                                   self.test_params, {})
+    got = bdev.RADOSBlockDevice.Create(self.test_unique_id, [], 1024, None,
+                                       self.test_params, False, {},
+                                       test_kwarg="test")
+
+    self.assertEqual(expect, got)
+
+  @testutils.patch_object(bdev.RADOSBlockDevice, "Attach")
+  def testRADOSBlockDeviceCreateFailure(self, attach_mock):
+    """Test for bdev.RADOSBlockDevice.Create() failure with exclusive_storage
+    enabled
+
+    """
+    attach_mock.return_value = True
+
+    self.assertRaises(errors.ProgrammerError, bdev.RADOSBlockDevice.Create,
+                      self.test_unique_id, [], 1024, None, self.test_params,
+                      True, {})
+
 
 class TestExclusiveStoragePvs(unittest.TestCase):
   """Test cases for functions dealing with LVM PV and exclusive storage"""
@@ -234,8 +269,30 @@ class TestExclusiveStoragePvs(unittest.TestCase):
             self.assertTrue(len(epvs) == num_req or pvi.free != pvi.size)
 
 
-class TestLogicalVolume(unittest.TestCase):
+class TestLogicalVolume(testutils.GanetiTestCase):
   """Tests for bdev.LogicalVolume."""
+
+  def setUp(self):
+    """Set up test data"""
+    testutils.GanetiTestCase.setUp(self)
+
+    self.volume_name = "31225655-5775-4356-c212-e8b1e137550a.disk0"
+    self.test_unique_id = ("ganeti", self.volume_name)
+    self.test_params = {
+      constants.LDP_STRIPES: 1
+      }
+    self.pv_info_return = [objects.LvmPvInfo(name="/dev/sda5", vg_name="xenvg",
+                                             size=3500000.00, free=5000000.00,
+                                             attributes="wz--n-", lv_list=[])]
+    self.pv_info_invalid = [objects.LvmPvInfo(name="/dev/s:da5",
+                                              vg_name="xenvg",
+                                             size=3500000.00, free=5000000.00,
+                                              attributes="wz--n-", lv_list=[])]
+    self.pv_info_no_space = [objects.LvmPvInfo(name="/dev/sda5", 
vg_name="xenvg",
+                                               size=3500000.00, free=0.00,
+                                               attributes="wz--n-", 
lv_list=[])]
+
+
   def testParseLvInfoLine(self):
     """Tests for LogicalVolume._ParseLvInfoLine."""
     broken_lines = [
@@ -279,14 +336,6 @@ class TestLogicalVolume(unittest.TestCase):
         parsed = bdev.LogicalVolume._ParseLvInfoLine(lvs_line, sep)
         self.assertEqual(parsed, exp)
 
-  @staticmethod
-  def _FakeRunCmd(success, stdout):
-    if success:
-      exit_code = 0
-    else:
-      exit_code = 1
-    return lambda cmd: utils.RunResult(exit_code, None, stdout, "", cmd,
-                                       utils.process._TIMEOUT_NONE, 5)
 
   def testGetLvGlobalInfo(self):
     """Tests for LogicalVolume._GetLvGlobalInfo."""
@@ -298,15 +347,19 @@ class TestLogicalVolume(unittest.TestCase):
 
     self.assertEqual({},
                      bdev.LogicalVolume._GetLvGlobalInfo(
-                         _run_cmd=self._FakeRunCmd(False, "Fake error msg")))
+                         _run_cmd=lambda cmd: _FakeRunCmd(False,
+                                                          "Fake error msg",
+                                                          cmd)))
     self.assertEqual({},
                      bdev.LogicalVolume._GetLvGlobalInfo(
-                         _run_cmd=self._FakeRunCmd(True, "")))
+                         _run_cmd=lambda cmd: _FakeRunCmd(True,
+                                                          "",
+                                                          cmd)))
     self.assertRaises(errors.BlockDeviceError,
                       bdev.LogicalVolume._GetLvGlobalInfo,
-                      _run_cmd=self._FakeRunCmd(True, "BadStdOut"))
+                      _run_cmd=lambda cmd: _FakeRunCmd(True, "BadStdOut", cmd))
 
-    fake_cmd = self._FakeRunCmd(True, good_lines)
+    fake_cmd = lambda cmd: _FakeRunCmd(True, good_lines, cmd)
     good_res = bdev.LogicalVolume._GetLvGlobalInfo(_run_cmd=fake_cmd)
     self.assertEqual(expected_output, good_res)
 
@@ -317,8 +370,7 @@ class TestLogicalVolume(unittest.TestCase):
     attach_mock.return_value = True
 
     # Create a fake logical volume
-    test_unique_id = ("ganeti",  "31225655-5775-4356-c212-e8b1e137550a.disk0")
-    inst = bdev.LogicalVolume(test_unique_id, [], 1024, {}, {})
+    inst = bdev.LogicalVolume(self.test_unique_id, [], 1024, {}, {})
 
     # Desired output command
     import_cmd = [constants.DD_CMD,
@@ -335,8 +387,7 @@ class TestLogicalVolume(unittest.TestCase):
     attach_mock.return_value = True
 
     # Create a fake logical volume
-    test_unique_id = ("ganeti",  "31225655-5775-4356-c212-e8b1e137550a.disk0")
-    inst = bdev.LogicalVolume(test_unique_id, [], 1024, {}, {})
+    inst = bdev.LogicalVolume(self.test_unique_id, [], 1024, {}, {})
 
     # Desired output command
     export_cmd = [constants.DD_CMD,
@@ -347,20 +398,168 @@ class TestLogicalVolume(unittest.TestCase):
 
     self.assertEqual(inst.Export(), export_cmd)
 
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(utils, "RunCmd")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreate(self, attach_mock, run_cmd_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() success"""
+    attach_mock.return_value = True
+    # This returns a successful RunCmd result
+    run_cmd_mock.return_value = _FakeRunCmd(True, "", "")
+    pv_info_mock.return_value = self.pv_info_return
+
+    expect = bdev.LogicalVolume(self.test_unique_id, [], 1024,
+                                self.test_params, {})
+    got = bdev.LogicalVolume.Create(self.test_unique_id, [], 1024, None,
+                                    self.test_params, False, {},
+                                    test_kwarg="test")
+
+    self.assertEqual(expect, got)
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailurePvsInfoExclStor(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when pv_info is empty and
+    exclusive storage is enabled
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = []
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, None, {}, True, {})
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailurePvsInfoNoExclStor(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when pv_info is empty and
+    exclusive storage is disabled
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = []
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, None, {}, False, {})
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailurePvsInvalid(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when pvs_info output is
+    invalid
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = self.pv_info_invalid
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, None, {}, False, {})
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailureNoSpindles(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when there are no spindles
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = self.pv_info_return
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, None,
+                      self.test_params,True, {})
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailureNotEnoughSpindles(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when there are not enough
+    spindles
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = self.pv_info_return
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, 0,
+                      self.test_params, True, {})
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailureNotEnoughEmptyPvs(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when there are not enough
+    empty pvs
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = self.pv_info_return
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, 2,
+                      self.test_params, True, {})
+
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailureNoFreeSpace(self, attach_mock, pv_info_mock):
+    """Test for bdev.LogicalVolume.Create() failure when there is no free space
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = self.pv_info_no_space
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, None,
+                      self.test_params, False, {})
+
+  @testutils.patch_object(utils, "RunCmd")
+  @testutils.patch_object(bdev.LogicalVolume, "GetPVInfo")
+  @testutils.patch_object(bdev.LogicalVolume, "Attach")
+  def testCreateFailureCommand(self, attach_mock, pv_info_mock, run_cmd_mock):
+    """Test for bdev.LogicalVolume.Create() failure when the runcmd is 
incorrect
+
+    """
+    attach_mock.return_value = True
+    pv_info_mock.return_value = self.pv_info_return
+    run_cmd_mock = _FakeRunCmd(False, "", "")
+
+    self.assertRaises(errors.BlockDeviceError, bdev.LogicalVolume.Create,
+                      self.test_unique_id, [], 1024, None,
+                      self.test_params, False, {})
+
 
 class TestPersistentBlockDevice(testutils.GanetiTestCase):
   """Tests for bdev.PersistentBlockDevice volumes
 
   """
+
+  def setUp(self):
+    """Set up test data"""
+    testutils.GanetiTestCase.setUp(self)
+    self.test_unique_id = (constants.BLOCKDEV_DRIVER_MANUAL, "/dev/abc")
+
   def testPersistentBlockDeviceImport(self):
     """Test case for bdev.PersistentBlockDevice.Import()"""
     # Create a fake block device
-    test_unique_id = (constants.BLOCKDEV_DRIVER_MANUAL, "/dev/abc")
-    inst = bdev.PersistentBlockDevice(test_unique_id, [], 1024, {}, {})
+    inst = bdev.PersistentBlockDevice(self.test_unique_id, [], 1024, {}, {})
 
     self.assertRaises(errors.BlockDeviceError,
                       bdev.PersistentBlockDevice.Import, inst)
 
+  @testutils.patch_object(bdev.PersistentBlockDevice, "Attach")
+  def testCreate(self, attach_mock):
+    """Test for bdev.PersostentBlockDevice.Create()"""
+    attach_mock.return_value = True
+
+    expect = bdev.PersistentBlockDevice(self.test_unique_id, [], 0, {}, {})
+    got = bdev.PersistentBlockDevice.Create(self.test_unique_id, [], 1024, 
None,
+                                            {}, False, {}, test_kwarg="test")
+
+    self.assertEqual(expect, got)
+
+  def testCreateFailure(self):
+    """Test for bdev.PersostentBlockDevice.Create() failure"""
+
+    self.assertRaises(errors.ProgrammerError, 
bdev.PersistentBlockDevice.Create,
+                      self.test_unique_id, [], 1024, None, {}, True, {})
+
 
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
diff --git a/test/py/ganeti.storage.drbd_unittest.py 
b/test/py/ganeti.storage.drbd_unittest.py
index 9a1894f..6ac2876 100755
--- a/test/py/ganeti.storage.drbd_unittest.py
+++ b/test/py/ganeti.storage.drbd_unittest.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2006, 2007, 2010, 2012, 2013 Google Inc.
+# Copyright (C) 2006, 2007, 2010, 2012, 2013, 2016 Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -424,6 +424,7 @@ class TestDRBD8Status(testutils.GanetiTestCase):
 
 
 class TestDRBD8Construction(testutils.GanetiTestCase):
+
   def setUp(self):
     """Read in txt data"""
     testutils.GanetiTestCase.setUp(self)
@@ -471,5 +472,90 @@ class TestDRBD8Construction(testutils.GanetiTestCase):
     self.assertTrue(isinstance(inst._cmd_gen, drbd_cmdgen.DRBD84CmdGenerator))
 
 
+class TestDRBD8Create(testutils.GanetiTestCase):
+
+  class fake_disk(object):
+    def __init__(self, dev_path):
+      self.dev_path = dev_path
+
+    def Assemble(self):
+      pass
+
+    def Attach(self):
+      return True
+
+  def setUp(self):
+    """Set up test data"""
+    testutils.GanetiTestCase.setUp(self)
+    self.proc84_info = \
+      drbd_info.DRBD8Info.CreateFromFile(
+        filename=testutils.TestDataFilename("proc_drbd84.txt"))
+
+    self.test_unique_id = ("hosta.com", 123, "host2.com", 123, 0,
+                           serializer.Private("secret"))
+    self.test_dyn_params = {
+      constants.DDP_LOCAL_IP: "192.0.2.1",
+      constants.DDP_LOCAL_MINOR: 0,
+      constants.DDP_REMOTE_IP: "192.0.2.2",
+      constants.DDP_REMOTE_MINOR: 0,
+    }
+
+    fake_child_1 = self.fake_disk("/dev/sda5")
+    fake_child_2 = self.fake_disk("/dev/sda6")
+    self.children = [fake_child_1, fake_child_2]
+
+  @testutils.patch_object(drbd.DRBD8Dev, "_InitMeta")
+  @testutils.patch_object(drbd.DRBD8Dev, "_CheckMetaSize")
+  @testutils.patch_object(drbd.DRBD8, "GetProcInfo")
+  def testCreate(self, proc_info, check_meta_size, init_meta):
+    proc_info.return_value = self.proc84_info
+    check_meta_size.return_value = None
+    init_meta.return_value = None
+    self.test_dyn_params[constants.DDP_LOCAL_MINOR] = 2
+
+    expected = drbd.DRBD8Dev(self.test_unique_id, [], 123, {},
+                             self.test_dyn_params)
+    got = drbd.DRBD8Dev.Create(self.test_unique_id, self.children, 123,
+                               None, {}, False, self.test_dyn_params,
+                               test_kwarg="test")
+
+    self.assertEqual(got, expected)
+
+  def testCreateFailureChildrenLength(self):
+    self.assertRaises(errors.ProgrammerError, drbd.DRBD8Dev.Create,
+                      self.test_unique_id, [], 123, None, {},
+                      False, self.test_dyn_params)
+
+  def testCreateFailureExclStorage(self):
+    self.assertRaises(errors.ProgrammerError, drbd.DRBD8Dev.Create,
+                      self.test_unique_id, self.children, 123, None, {},
+                      True, self.test_dyn_params)
+
+  def testCreateFailureNoMinor(self):
+    self.assertRaises(errors.ProgrammerError, drbd.DRBD8Dev.Create,
+                      self.test_unique_id, self.children, 123, None, {},
+                      False, {})
+
+  @testutils.patch_object(drbd.DRBD8, "GetProcInfo")
+  def testCreateFailureInUse(self, proc_info):
+    # The proc84_info config has a local minor in use, which triggers our
+    # failure test.
+    proc_info.return_value = self.proc84_info
+
+    self.assertRaises(errors.BlockDeviceError, drbd.DRBD8Dev.Create,
+                      self.test_unique_id, self.children, 123, None, {},
+                      False, self.test_dyn_params)
+
+  @testutils.patch_object(drbd.DRBD8, "GetProcInfo")
+  def testCreateFailureMetaAttach(self, proc_info):
+    proc_info.return_value = self.proc84_info
+    self.test_dyn_params[constants.DDP_LOCAL_MINOR] = 2
+    self.children[1].Attach = lambda: False
+
+    self.assertRaises(errors.BlockDeviceError, drbd.DRBD8Dev.Create,
+                      self.test_unique_id, self.children, 123, None, {},
+                      False, self.test_dyn_params)
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
diff --git a/test/py/ganeti.storage.extstorage_unittest.py 
b/test/py/ganeti.storage.extstorage_unittest.py
new file mode 100755
index 0000000..b8d2fd4
--- /dev/null
+++ b/test/py/ganeti.storage.extstorage_unittest.py
@@ -0,0 +1,73 @@
+#!/usr/bin/python
+#
+
+# Copyright (C) 2016 Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+"""Script for unittesting the extstorage module"""
+
+
+from ganeti import errors
+from ganeti.storage import extstorage
+
+import testutils
+
+
+class TestExtStorageDevice(testutils.GanetiTestCase):
+  """Testing case for extstorage.ExtStorageDevice"""
+
+  def setUp(self):
+    """Set up test data"""
+    testutils.GanetiTestCase.setUp(self)
+    self.name = "testname"
+    self.uuid = "testuuid"
+    self.test_unique_id = ("testdriver", "testvolumename")
+
+  @testutils.patch_object(extstorage.ExtStorageDevice, "Attach")
+  @testutils.patch_object(extstorage, "_ExtStorageAction")
+  def testCreate(self, action_mock, attach_mock):
+    action_mock.return_value = None
+    attach_mock.return_value = True
+
+    expected = extstorage.ExtStorageDevice(self.test_unique_id, [], 123, {}, 
{},
+                                     name=self.name, uuid=self.uuid)
+    got = extstorage.ExtStorageDevice.Create(self.test_unique_id, [], 123,
+                                             None, {}, False, {},
+                                             name=self.name, uuid=self.uuid)
+
+    self.assertEqual(got, expected)
+
+  def testCreateFailure(self):
+    self.assertRaises(errors.ProgrammerError,
+                      extstorage.ExtStorageDevice.Create,
+                      self.test_unique_id, [], 123, None, {},
+                      True, {}, name=self.name, uuid=self.uuid)
+
+
+if __name__ == "__main__":
+  testutils.GanetiTestProgram()
+
diff --git a/test/py/ganeti.storage.filestorage_unittest.py 
b/test/py/ganeti.storage.filestorage_unittest.py
index 4ac5743..fd6940d 100755
--- a/test/py/ganeti.storage.filestorage_unittest.py
+++ b/test/py/ganeti.storage.filestorage_unittest.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2013 Google Inc.
+# Copyright (C) 2013, 2016 Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -273,19 +273,18 @@ class TestFileDeviceHelper(testutils.GanetiTestCase):
 
     # These should fail horribly.
     volume.Exists(assert_exists=False)
-    self.assertRaises(errors.BlockDeviceError, lambda: \
-      volume.Exists(assert_exists=True))
-    self.assertRaises(errors.BlockDeviceError, lambda: \
-      volume.Size())
-    self.assertRaises(errors.BlockDeviceError, lambda: \
-      volume.Grow(0.020, True, False, None))
+    self.assertRaises(errors.BlockDeviceError, volume.Exists,
+                      assert_exists=True)
+    self.assertRaises(errors.BlockDeviceError, volume.Size)
+    self.assertRaises(errors.BlockDeviceError, volume.Grow,
+                      0.020, True, False, None)
 
     # Removing however fails silently.
     volume.Remove()
 
     # Make sure we don't create all directories for you unless we ask for it
-    self.assertRaises(errors.BlockDeviceError, lambda: \
-      TestFileDeviceHelper._Make(path, create_with_size=1))
+    self.assertRaises(errors.BlockDeviceError, TestFileDeviceHelper._Make,
+                      path, create_with_size=1)
 
   def testFileCreation(self):
     with TestFileDeviceHelper.TempEnvironment() as env:
@@ -293,22 +292,22 @@ class TestFileDeviceHelper(testutils.GanetiTestCase):
 
       self.assertTrue(env.volume.Exists())
       env.volume.Exists(assert_exists=True)
-      self.assertRaises(errors.BlockDeviceError, lambda: \
-        env.volume.Exists(assert_exists=False))
+      self.assertRaises(errors.BlockDeviceError, env.volume.Exists,
+                        assert_exists=False)
 
-    self.assertRaises(errors.BlockDeviceError, lambda: \
-      TestFileDeviceHelper._Make("/enoent", create_with_size=0.042))
+    self.assertRaises(errors.BlockDeviceError, TestFileDeviceHelper._Make,
+                      "/enoent", create_with_size=0.042)
 
   def testFailSizeDirectory(self):
   # This should still fail.
    with TestFileDeviceHelper.TempEnvironment(delete_file=False) as env:
-    self.assertRaises(errors.BlockDeviceError, lambda: \
-      TestFileDeviceHelper._Make(env.subdirectory).Size())
+     test_helper = TestFileDeviceHelper._Make(env.subdirectory)
+     self.assertRaises(errors.BlockDeviceError, test_helper.Size)
 
   def testGrowFile(self):
     with TestFileDeviceHelper.TempEnvironment(create_file=True) as env:
-      self.assertRaises(errors.BlockDeviceError, lambda: \
-        env.volume.Grow(-1, False, True, None))
+      self.assertRaises(errors.BlockDeviceError, env.volume.Grow, -1,
+                        False, True, None)
 
       env.volume.Grow(2, False, True, None)
       self.assertEqual(2.0, env.volume.Size() / 1024.0**2)
@@ -329,5 +328,28 @@ class TestFileDeviceHelper(testutils.GanetiTestCase):
       env.path = new_path # update the path for the context manager
 
 
+class TestFileStorage(testutils.GanetiTestCase):
+
+  @testutils.patch_object(filestorage, "FileDeviceHelper")
+  @testutils.patch_object(filestorage.FileStorage, "Attach")
+  def testCreate(self, attach_mock, helper_mock):
+    attach_mock.return_value = True
+    helper_mock.return_value = None
+    test_unique_id = ("test_driver", "/test/file")
+
+
+    expect = filestorage.FileStorage(test_unique_id, [], 123, {}, {})
+    got = filestorage.FileStorage.Create(test_unique_id, [], 123, None, {},
+                                         False, {}, test_kwarg="test")
+
+    self.assertEqual(expect, got)
+
+  def testCreateFailure(self):
+    test_unique_id = ("test_driver", "/test/file")
+
+    self.assertRaises(errors.ProgrammerError, filestorage.FileStorage.Create,
+                      test_unique_id, [], 123, None, {}, True, {})
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
diff --git a/test/py/ganeti.storage.gluster_unittest.py 
b/test/py/ganeti.storage.gluster_unittest.py
index b75bf6d..8204885 100644
--- a/test/py/ganeti.storage.gluster_unittest.py
+++ b/test/py/ganeti.storage.gluster_unittest.py
@@ -1,7 +1,7 @@
 #!/usr/bin/python
 #
 
-# Copyright (C) 2013 Google Inc.
+# Copyright (C) 2013, 2016 Google Inc.
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
@@ -35,9 +35,10 @@ import tempfile
 import unittest
 import mock
 
+from ganeti import constants
 from ganeti import errors
-from ganeti.storage import filestorage
 from ganeti.storage import gluster
+from ganeti import ssconf
 from ganeti import utils
 
 import testutils
@@ -141,5 +142,41 @@ class TestGlusterVolume(testutils.GanetiTestCase):
                     msg="%s not testvol on localhost:9001" % 
(fuseMountString,))
 
 
+class TestGlusterStorage(testutils.GanetiTestCase):
+
+  def setUp(self):
+    """Set up test data"""
+    testutils.GanetiTestCase.setUp(self)
+
+    self.test_params = {
+        constants.GLUSTER_HOST: "127.0.0.1",
+        constants.GLUSTER_PORT: "24007",
+        constants.GLUSTER_VOLUME: "/testvol"
+    }
+    self.test_unique_id = ("testdriver", "testpath")
+
+
+  @testutils.patch_object(gluster.FileDeviceHelper, "CreateFile")
+  @testutils.patch_object(gluster.GlusterVolume, "Mount")
+  @testutils.patch_object(ssconf.SimpleStore, "GetGlusterStorageDir")
+  @testutils.patch_object(gluster.GlusterStorage, "Attach")
+  def testCreate(self, attach_mock, storage_dir_mock, mount_mock, 
create_file_mock):
+    attach_mock.return_value = True
+    storage_dir_mock.return_value = "/testmount"
+
+    expect = gluster.GlusterStorage(self.test_unique_id, [], 123,
+                                    self.test_params, {})
+    got = gluster.GlusterStorage.Create(self.test_unique_id, [], 123, None,
+                                        self.test_params, False, {},
+                                        test_kwarg="test")
+
+    self.assertEqual(expect, got)
+
+  def testCreateFailure(self):
+    self.assertRaises(errors.ProgrammerError, gluster.GlusterStorage.Create,
+                      self.test_unique_id, [], 123, None,
+                      self.test_params, True, {})
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()
-- 
2.8.0.rc3.226.g39d4020

Reply via email to