summaryrefslogtreecommitdiff
path: root/cxmanage_api/tests
diff options
context:
space:
mode:
authorGeorge Kraft <george.kraft@calxeda.com>2013-12-07 12:14:23 -0600
committerGeorge Kraft <george.kraft@calxeda.com>2013-12-07 12:14:23 -0600
commit76084a9b7e3b7f09aecd404dbb803a3bb6a1d4c4 (patch)
tree79cfa374dd6d599980d3c2333de3150331f083de /cxmanage_api/tests
parent7af4294fbd7e214f669adc6ded77dadb627c41f9 (diff)
downloadcxmanage-76084a9b7e3b7f09aecd404dbb803a3bb6a1d4c4.tar.gz
CXMAN-263: Remove the cxmanage_api.dummy package
Put the dummies back in cxmanage_api.tests. They kinda go together.
Diffstat (limited to 'cxmanage_api/tests')
-rw-r--r--cxmanage_api/tests/__init__.py37
-rw-r--r--cxmanage_api/tests/dummy.py61
-rw-r--r--cxmanage_api/tests/dummy_bmc.py564
-rw-r--r--cxmanage_api/tests/dummy_image.py38
-rw-r--r--cxmanage_api/tests/dummy_ip_retriever.py52
-rw-r--r--cxmanage_api/tests/dummy_node.py232
-rw-r--r--cxmanage_api/tests/dummy_test.py2
-rw-r--r--cxmanage_api/tests/dummy_ubootenv.py43
-rw-r--r--cxmanage_api/tests/fabric_test.py2
-rw-r--r--cxmanage_api/tests/node_test.py2
-rw-r--r--cxmanage_api/tests/utilities.py59
11 files changed, 1059 insertions, 33 deletions
diff --git a/cxmanage_api/tests/__init__.py b/cxmanage_api/tests/__init__.py
index d8d5307..bf136c0 100644
--- a/cxmanage_api/tests/__init__.py
+++ b/cxmanage_api/tests/__init__.py
@@ -1,6 +1,3 @@
-"""Calxeda: __init__.py"""
-
-
# Copyright (c) 2012-2013, Calxeda Inc.
#
# All rights reserved.
@@ -31,30 +28,10 @@
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
# DAMAGE.
-
-import os
-import random
-import tempfile
-
-from cxmanage_api.image import Image
-
-def random_file(size):
- """ Create a random file """
- contents = "".join([chr(random.randint(0, 255)) for _ in range(size)])
- file_, filename = tempfile.mkstemp(prefix='cxmanage_test-')
- with os.fdopen(file_, "w") as file_handle:
- file_handle.write(contents)
-
- return filename
-
-class TestImage(Image):
- """TestImage Class."""
- def verify(self):
- return True
-
-# pylint: disable=R0903
-class TestSensor(object):
- """ Sensor result from bmc/target """
- def __init__(self, sensor_name, sensor_reading):
- self.sensor_name = sensor_name
- self.sensor_reading = sensor_reading
+from cxmanage_api.tests.utilities import random_file, TestImage, TestSensor
+from cxmanage_api.tests.dummy import Dummy
+from cxmanage_api.tests.dummy_bmc import DummyBMC
+from cxmanage_api.tests.dummy_node import DummyNode, DummyFailNode
+from cxmanage_api.tests.dummy_image import DummyImage
+from cxmanage_api.tests.dummy_ubootenv import DummyUbootEnv
+from cxmanage_api.tests.dummy_ip_retriever import DummyIPRetriever
diff --git a/cxmanage_api/tests/dummy.py b/cxmanage_api/tests/dummy.py
new file mode 100644
index 0000000..72f04ed
--- /dev/null
+++ b/cxmanage_api/tests/dummy.py
@@ -0,0 +1,61 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+from mock import Mock
+
+
+class Dummy(Mock):
+ """ Dummy class. Children of this class will automatically have their
+ methods be turned into Mock objects with side effects, allowing us to track
+ their usage and assert about how they are called.
+
+ They dummy_spec variable gives us a spec for building the Mock object, which
+ restricts the names of methods that can be called.
+
+ """
+
+ dummy_spec = None
+
+ def __init__(self):
+ super(Dummy, self).__init__(
+ spec=self.dummy_spec
+ )
+
+ for name in dir(self):
+ if not hasattr(Mock, name):
+ try:
+ attr = getattr(self, name)
+ if callable(attr) and not isinstance(attr, Mock):
+ setattr(self, name, Mock(side_effect=attr))
+ except AttributeError:
+ pass
+
+ def _get_child_mock(self, *args, **kwargs):
+ return Mock(*args, **kwargs)
diff --git a/cxmanage_api/tests/dummy_bmc.py b/cxmanage_api/tests/dummy_bmc.py
new file mode 100644
index 0000000..cc515db
--- /dev/null
+++ b/cxmanage_api/tests/dummy_bmc.py
@@ -0,0 +1,564 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+import random
+import shutil
+import tempfile
+from mock import Mock
+
+from pyipmi import IpmiError
+from pyipmi.bmc import LanBMC
+
+from cxmanage_api.tests import Dummy, TestSensor
+from cxmanage_api import temp_file
+from cxmanage_api.simg import create_simg, get_simg_header
+from cxmanage_api.tftp import InternalTftp, ExternalTftp
+
+
+# pylint: disable=R0902
+class DummyBMC(Dummy):
+ """ Dummy BMC for the node tests """
+ dummy_spec = LanBMC
+
+ ip_addresses = [
+ "192.168.100.%i" % n for n in range(1, 5)
+ ]
+ tftp = InternalTftp()
+
+
+ GUID_UNIQUE = 0
+
+
+ def __init__(self, **kwargs):
+ super(DummyBMC, self).__init__()
+ self.handle = Mock(name="handle")
+ self.partitions = [
+ Partition(0, 3, 0, 393216, in_use=True), # socman
+ Partition(1, 10, 393216, 196608, in_use=True), # factory cdb
+ Partition(2, 3, 589824, 393216, in_use=False), # socman
+ Partition(3, 10, 983040, 196608, in_use=False), # factory cdb
+ Partition(4, 10, 1179648, 196608, in_use=True), # running cdb
+ Partition(5, 11, 1376256, 12288), # ubootenv
+ Partition(6, 11, 1388544, 12288) # ubootenv
+ ]
+ self.ipaddr_base = '192.168.100.1'
+ self.unique_guid = 'FAKEGUID%s' % DummyBMC.GUID_UNIQUE
+ self.sel = DummyBMC.generate_sel(with_errors=False)
+
+ DummyBMC.GUID_UNIQUE += 1
+
+ def guid(self):
+ """Returns the GUID"""
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self, dummybmc):
+ self.system_guid = dummybmc.unique_guid
+ self.time_stamp = None
+ return Result(self)
+
+ def get_chassis_status(self):
+ """ Get chassis status """
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ self.power_on = False
+ self.power_restore_policy = "always-off"
+ return Result()
+
+ def sel_elist(self):
+ """ List SEL. with_errors=True simulates a SEL that contains errors """
+ return self.sel
+
+ @staticmethod
+ def generate_sel(with_errors=False):
+ """ Generates a SEL table for a Node """
+ if (with_errors):
+ return [
+ '1 | 11/20/2013 | 20:26:18 | Memory | Correctable ECC | Asserted',
+ '2 | 11/20/2013 | 20:26:43 | Processor | IERR | Asserted',
+ '83 | 11/14/2013 | 18:01:35 | OS Stop/Shutdown OS Stop Reason | ' +
+ 'Error during system startup | Asserted'
+ ]
+ else:
+ return [
+ '88 | 11/14/2013 | 18:02:29 | System Boot Initiated OS Boot ' +
+ 'Reason | Initiated by power up | Asserted',
+ '91 | 11/14/2013 | 19:24:25 | System Event BMC Status |',
+ ]
+
+ def get_firmware_info(self):
+ """ Get partition and simg info """
+ return [x.fwinfo for x in self.partitions]
+
+ def update_firmware(self, filename, partition, image_type, tftp_addr):
+ """ Download a file from a TFTP server to a given partition.
+
+ Make sure the image type matches. """
+ self.partitions[partition].updates += 1
+
+ localfile = temp_file()
+ self.tftp.get_file(filename, localfile)
+
+ contents = open(localfile).read()
+ simg = get_simg_header(contents)
+ self.partitions[partition].fwinfo.offset = "%8x" % simg.imgoff
+ self.partitions[partition].fwinfo.size = "%8x" % simg.imglen
+ self.partitions[partition].fwinfo.priority = "%8x" % simg.priority
+ self.partitions[partition].fwinfo.daddr = "%8x" % simg.daddr
+
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ """Default constructor for the Result class."""
+ self.tftp_handle_id = 0
+ return Result()
+
+ def retrieve_firmware(self, filename, partition, image_type, tftp_addr):
+ self.partitions[partition].retrieves += 1
+
+ # Upload blank image to tftp
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+ open("%s/%s" % (work_dir, filename), "w").write(create_simg(""))
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+ shutil.rmtree(work_dir)
+
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ self.tftp_handle_id = 0
+ return Result()
+
+ def register_firmware_read(self, filename, partition, image_type):
+ raise IpmiError()
+
+ def register_firmware_write(self, filename, partition, image_type):
+ raise IpmiError()
+
+ def get_firmware_status(self, handle):
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ self.status = "Complete"
+
+ del handle
+
+ return Result()
+
+ def check_firmware(self, partition):
+ self.partitions[partition].checks += 1
+
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ self.crc32 = 0
+ self.error = None
+ return Result()
+
+ def activate_firmware(self, partition):
+ self.partitions[partition].activates += 1
+
+ def sdr_list(self):
+ """ Get sensor info from the node. """
+ power_value = "%f (+/- 0) Watts" % random.uniform(0, 10)
+ temp_value = "%f (+/- 0) degrees C" % random.uniform(30, 50)
+ sensors = [
+ TestSensor("Node Power", power_value),
+ TestSensor("Board Temp", temp_value)
+ ]
+
+ return sensors
+
+ def get_info_basic(self):
+ """ Get basic SoC info from this node """
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ self.iana = int("0x0096CD", 16)
+ self.firmware_version = "ECX-0000-v0.0.0"
+ self.ecme_version = "v0.0.0"
+ self.ecme_timestamp = 0
+ return Result()
+
+ def get_info_card(self):
+ # pylint: disable=R0903
+ class Result(object):
+ """Results class."""
+ def __init__(self):
+ self.type = "TestBoard"
+ self.revision = "0"
+ return Result()
+
+ node_count = 0
+ def fabric_get_node_id(self):
+ result = DummyBMC.node_count
+ DummyBMC.node_count += 1
+ return result
+
+ def fabric_info_get_link_map(self, filename, tftp_addr=None):
+ """Upload a link_map file from the node to TFTP"""
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ link_map = []
+ link_map.append('Link 1: Node 2')
+ link_map.append('Link 3: Node 1')
+ link_map.append('Link 4: Node 3')
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+ with open('%s/%s' % (work_dir, filename), 'w') as lm_file:
+ for lmap in link_map:
+ lm_file.write(lmap + '\n')
+ lm_file.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ def fabric_info_get_routing_table(self, filename, tftp_addr=None):
+ """Upload a routing_table file from the node to TFTP"""
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ routing_table = []
+ routing_table.append('Node 1: rt - 0.2.0.3.2')
+ routing_table.append('Node 2: rt - 0.3.0.1.2')
+ routing_table.append('Node 3: rt - 0.2.0.1.3')
+ routing_table.append('Node 12: rt - 0.2.0.0.1')
+ routing_table.append('Node 13: rt - 0.2.0.0.1')
+ routing_table.append('Node 14: rt - 0.2.0.0.1')
+ routing_table.append('Node 15: rt - 0.2.0.0.1')
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+ with open('%s/%s' % (work_dir, filename), 'w') as rt_file:
+ for rtable in routing_table:
+ rt_file.write(rtable + '\n')
+ rt_file.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ def fabric_info_get_depth_chart(self, filename, tftp_addr=None):
+ """Upload a depth_chart file from the node to TFTP"""
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ depth_chart = []
+ depth_chart.append(
+ 'Node 1: Shortest Distance 0 hops via neighbor 0: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 2: Shortest Distance 0 hops via neighbor 0: ' +
+ 'other hops/neighbors - 1/3'
+ )
+ depth_chart.append(
+ 'Node 3: Shortest Distance 0 hops via neighbor 0: ' +
+ 'other hops/neighbors - 1/2'
+ )
+ depth_chart.append(
+ 'Node 4: Shortest Distance 2 hops via neighbor 6: ' +
+ 'other hops/neighbors - 3/7'
+ )
+ depth_chart.append(
+ 'Node 5: Shortest Distance 3 hops via neighbor 4: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 6: Shortest Distance 1 hops via neighbor 2: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 7: Shortest Distance 2 hops via neighbor 6: ' +
+ 'other hops/neighbors - 3/4'
+ )
+ depth_chart.append(
+ 'Node 8: Shortest Distance 3 hops via neighbor 10: ' +
+ 'other hops/neighbors - 4/11'
+ )
+ depth_chart.append(
+ 'Node 9: Shortest Distance 4 hops via neighbor 8: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 10: Shortest Distance 2 hops via neighbor 6: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 11: Shortest Distance 3 hops via neighbor 10: ' +
+ 'other hops/neighbors - 4/8'
+ )
+ depth_chart.append(
+ 'Node 12: Shortest Distance 4 hops via neighbor 14: ' +
+ 'other hops/neighbors - 5/15'
+ )
+ depth_chart.append(
+ 'Node 13: Shortest Distance 5 hops via neighbor 12: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 14: Shortest Distance 3 hops via neighbor 10: ' +
+ 'other hops/neighbors -'
+ )
+ depth_chart.append(
+ 'Node 15: Shortest Distance 4 hops via neighbor 14: ' +
+ 'other hops/neighbors - 5/12'
+ )
+
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+ with open('%s/%s' % (work_dir, filename), 'w') as dc_file:
+ for dchart in depth_chart:
+ dc_file.write(dchart + '\n')
+ dc_file.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ # pylint: disable=W0222
+ def fabric_get_linkstats(self, filename, tftp_addr=None,
+ link=None):
+ """Upload a link_stats file from the node to TFTP"""
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ link_stats = []
+ link_stats.append('Packet Counts for Link %s:' % link)
+ link_stats.append('Link0 StatspFS_LCn_CFG_0(link) = 0x1030d07f')
+ link_stats.append('pFS_LCn_CFG_1 = 0x105f')
+ link_stats.append('pFS_LCn_STATE = 0x1033')
+ link_stats.append('pFS_LCn_SC_STAT = 0x0')
+ link_stats.append('pFS_LCn_PKT_CNT_0 = 0x0')
+ link_stats.append('pFS_LCn_PKT_CNT_1 = 0x0')
+ link_stats.append('pFS_LCn_BYTE_CNT_0 = 0x0')
+ link_stats.append('pFS_LCn_BYTE_CNT_1 = 0x0')
+ link_stats.append('pFS_LCn_CM_TXDATA_0 = 0x82000000')
+ link_stats.append('pFS_LCn_CM_TXDATA_1 = 0x0')
+ link_stats.append('pFS_LCn_CM_RXDATA_0 = 0x0')
+ link_stats.append('pFS_LCn_CM_RXDATA_1 = 0x0')
+ link_stats.append('pFS_LCn_PKT_CNT_0 = 0x0')
+ link_stats.append('pFS_LCn_PKT_CNT_1 = 0x0')
+ link_stats.append('pFS_LCn_RMCSCNT = 0x1428')
+ link_stats.append('pFS_LCn_RUCSCNT = 0x116')
+ link_stats.append('pFS_LCn_RERRSCNT = 0x0')
+ link_stats.append('pFS_LCn_RDRPSCNT = 0xb4')
+ link_stats.append('pFS_LCn_RPKTSCNT = 0x0')
+ link_stats.append('pFS_LCn_TPKTSCNT = 0x1')
+ link_stats.append('pFS_LCn_TDRPSCNT = 0x0')
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+ with open('%s/%s' % (work_dir, filename), 'w') as ls_file:
+ for stat in link_stats:
+ ls_file.write(stat + '\n')
+ ls_file.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ def fabric_config_get_ip_info(self, filename, tftp_addr=None):
+ """ Upload an ipinfo file from the node to TFTP"""
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+
+ # Create IP info file
+ ipinfo = open("%s/%s" % (work_dir, filename), "w")
+ for i in range(len(self.ip_addresses)):
+ ipinfo.write("Node %i: %s\n" % (i, self.ip_addresses[i]))
+ ipinfo.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ def fabric_config_get_uplink_info(self, filename, tftp_addr=None):
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+ # Create uplink info file
+ ulinfo = open("%s/%s" % (work_dir, filename), "w")
+ for i in range(1, len(self.ip_addresses)):
+ ulinfo.write("Node %i: eth0 0, eth1 0, mgmt 0\n" % i)
+ ulinfo.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ def fabric_config_get_uplink(self, iface):
+ return 0
+
+ def fabric_config_get_mac_addresses(self, filename, tftp_addr=None):
+ """ Upload a macaddrs file from the node to TFTP"""
+ if not(tftp_addr):
+ raise IpmiError('No tftp address!')
+
+ work_dir = tempfile.mkdtemp(prefix="cxmanage_test-")
+
+ # Create macaddrs file
+ macaddrs = open("%s/%s" % (work_dir, filename), "w")
+ for i in range(len(self.ip_addresses)):
+ for port in range(3):
+ macaddr = "00:00:00:00:%x:%x" % (i, port)
+ macaddrs.write("Node %i, Port %i: %s\n" % (i, port, macaddr))
+ macaddrs.close()
+
+ # Upload to tftp
+ address, port = tftp_addr.split(":")
+ port = int(port)
+ tftp = ExternalTftp(address, port)
+ tftp.put_file("%s/%s" % (work_dir, filename), filename)
+
+ shutil.rmtree(work_dir)
+
+ def fabric_config_get_ip_src(self):
+ return 2
+
+ def fabric_config_set_ip_src(self, ipsrc_mode):
+ self.fabric_ipsrc = ipsrc_mode
+
+ def fabric_config_get_ip_addr_base(self):
+ """Provide a fake base IP addr"""
+ return self.ipaddr_base
+
+ def fabric_get_linkspeed(self, link="", actual=""):
+ return 1
+
+ def fabric_config_get_linkspeed(self):
+ return 1
+
+ def fabric_config_set_linkspeed(self, linkspeed):
+ self.fabric_linkspeed = linkspeed
+
+ def fabric_config_get_linkspeed_policy(self):
+ return 1
+
+ def fabric_config_set_linkspeed_policy(self, ls_policy):
+ self.fabric_ls_policy = ls_policy
+
+ def fabric_config_get_link_users_factor(self):
+ return 1
+
+ def fabric_config_set_link_users_factor(self, lu_factor):
+ self.fabric_lu_factor = lu_factor
+
+ def fabric_config_get_macaddr_base(self):
+ return "00:00:00:00:00:00"
+
+ def fabric_config_get_macaddr_mask(self):
+ return "00:00:00:00:00:00"
+
+ def fabric_get_uplink_info(self):
+ """Corresponds to Node.get_uplink_info()"""
+ return 'Node 0: eth0 0, eth1 0, mgmt 0'
+
+ def fabric_get_uplink_speed(self):
+ """Corresponds to Node.get_uplink_speed()"""
+ return 1
+
+ def fru_read(self, fru_number, filename):
+ with open(filename, "w") as fru_image:
+ # Writes a fake FRU image with version "0.0"
+ fru_image.write("x00" * 516 + "0.0" + "x00"*7673)
+
+ def pmic_get_version(self):
+ return "0"
+
+
+# pylint: disable=R0913, R0903
+class Partition(object):
+ """Partition class."""
+ def __init__(self, partition, type_, offset=0,
+ size=0, priority=0, daddr=0, in_use=None):
+ self.updates = 0
+ self.retrieves = 0
+ self.checks = 0
+ self.activates = 0
+ self.fwinfo = FWInfoEntry(partition, type_, offset, size, priority,
+ daddr, in_use)
+
+
+class FWInfoEntry(object):
+ """ Firmware info for a single partition """
+
+ def __init__(self, partition, type_, offset=0, size=0, priority=0, daddr=0,
+ in_use=None):
+ self.partition = "%2i" % partition
+ self.type = {
+ 2: "02 (S2_ELF)",
+ 3: "03 (SOC_ELF)",
+ 10: "0a (CDB)",
+ 11: "0b (UBOOTENV)"
+ }[type_]
+ self.offset = "%8x" % offset
+ self.size = "%8x" % size
+ self.priority = "%8x" % priority
+ self.daddr = "%8x" % daddr
+ self.in_use = {None: "Unknown", True: "1", False: "0"}[in_use]
+ self.flags = "fffffffd"
+ self.version = "v0.0.0"
diff --git a/cxmanage_api/tests/dummy_image.py b/cxmanage_api/tests/dummy_image.py
new file mode 100644
index 0000000..534befa
--- /dev/null
+++ b/cxmanage_api/tests/dummy_image.py
@@ -0,0 +1,38 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+# pylint: disable=R0903
+class DummyImage(object):
+ """Dummy Image class."""
+
+ def __init__(self, filename, image_type, *args):
+ self.filename = filename
+ self.type = image_type
+ self.args = args
diff --git a/cxmanage_api/tests/dummy_ip_retriever.py b/cxmanage_api/tests/dummy_ip_retriever.py
new file mode 100644
index 0000000..4767856
--- /dev/null
+++ b/cxmanage_api/tests/dummy_ip_retriever.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+from cxmanage_api.cx_exceptions import IPDiscoveryError
+
+
+# pylint: disable=R0903
+class DummyIPRetriever(object):
+ """ Dummy IP retriever """
+
+ def __init__(self, ecme_ip, aggressive=False, verbosity=0, **kwargs):
+ self.executed = False
+ self.ecme_ip = ecme_ip
+ self.aggressive = aggressive
+ self.verbosity = verbosity
+ for name, value in kwargs.iteritems():
+ setattr(self, name, value)
+
+ def run(self):
+ """ Set the server_ip variable. Raises an error if called more than
+ once. """
+ if self.executed:
+ raise IPDiscoveryError("DummyIPRetriever.run() was called twice!")
+ self.executed = True
+ self.server_ip = "192.168.200.1"
diff --git a/cxmanage_api/tests/dummy_node.py b/cxmanage_api/tests/dummy_node.py
new file mode 100644
index 0000000..02af2c2
--- /dev/null
+++ b/cxmanage_api/tests/dummy_node.py
@@ -0,0 +1,232 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+import random
+
+from cxmanage_api.ubootenv import UbootEnv
+from cxmanage_api.tests import Dummy, DummyBMC, TestSensor
+from cxmanage_api.node import Node
+
+
+class DummyNode(Dummy):
+ """ Dummy node """
+ dummy_spec = Node
+
+ ip_addresses = DummyBMC.ip_addresses
+
+ # pylint: disable=W0613
+ def __init__(self, ip_address, username="admin", password="admin",
+ tftp=None, *args, **kwargs):
+ super(DummyNode, self).__init__()
+ self.power_state = False
+ self.ip_address = ip_address
+ self.tftp = tftp
+ self.sel = []
+ self.bmc = DummyBMC()
+ #
+ # For now, we hard code this to 0 ...
+ #
+ self._chassis_id = 0
+
+ @property
+ def guid(self):
+ """Returns the node GUID"""
+ return self.bmc.guid().system_guid
+
+ @property
+ def chassis_id(self):
+ """Returns the chasis ID."""
+ return self._chassis_id
+
+ def get_sel(self):
+ """Simulate get_sel()"""
+ return self.sel
+
+ def get_power(self):
+ """Simulate get_power(). """
+ return self.power_state
+
+ def get_power_policy(self):
+ """Simulate get_power_policy(). """
+ return "always-off"
+
+ def get_sensors(self, name=""):
+ """Simulate get_sensors(). """
+ power_value = "%f (+/- 0) Watts" % random.uniform(0, 10)
+ temp_value = "%f (+/- 0) degrees C" % random.uniform(30, 50)
+ sensors = [
+ TestSensor("Node Power", power_value),
+ TestSensor("Board Temp", temp_value)
+ ]
+ return [s for s in sensors if name.lower() in s.sensor_name.lower()]
+
+ def get_boot_order(self):
+ """Simulate get_boot_order(). """
+ return ["disk", "pxe"]
+
+ def get_pxe_interface(self):
+ """Simulate get_pxe_interface(). """
+ return "eth0"
+
+ def get_versions(self):
+ """Simulate get_versions(). """
+ # pylint: disable=R0902, R0903
+ class Result(object):
+ """Result Class. """
+ def __init__(self):
+ self.header = "Calxeda SoC (0x0096CD)"
+ self.hardware_version = "TestBoard X00"
+ self.firmware_version = "v0.0.0"
+ self.ecme_version = "v0.0.0"
+ self.ecme_timestamp = "0"
+ self.a9boot_version = "v0.0.0"
+ self.uboot_version = "v0.0.0"
+ self.chip_name = "Unknown"
+ return Result()
+
+ def ipmitool_command(self, ipmitool_args):
+ """Simulate ipmitool_command(). """
+ return "Dummy output"
+
+ def get_ubootenv(self):
+ """Simulate get_ubootenv(). """
+ ubootenv = UbootEnv()
+ ubootenv.variables["bootcmd0"] = "run bootcmd_default"
+ ubootenv.variables["bootcmd_default"] = "run bootcmd_sata"
+ return ubootenv
+
+ @staticmethod
+ def get_fabric_ipinfo():
+ """Simulates get_fabric_ipinfo(). """
+ return {}
+
+ # pylint: disable=R0913
+ def get_server_ip(self, interface=None, ipv6=False, user="user1",
+ password="1Password", aggressive=False):
+ """Simulate get_server_ip(). """
+ return "192.168.200.1"
+
+ def get_fabric_macaddrs(self):
+ """Simulate get_fabric_macaddrs(). """
+ result = {}
+ for node in range(len(self.ip_addresses)):
+ result[node] = {}
+ for port in range(3):
+ address = "00:00:00:00:%02x:%02x" % (node, port)
+ result[node][port] = address
+ return result
+
+ def get_fabric_uplink_info(self):
+ """Simulate get_fabric_uplink_info(). """
+ results = {}
+ for nid in range(1, len(self.ip_addresses)):
+ results[nid] = {'eth0': 0, 'eth1': 0, 'mgmt': 0}
+ return results
+
+ def get_uplink_info(self):
+ """Simulate get_uplink_info(). """
+ return 'Node 0: eth0 0, eth1 0, mgmt 0'
+
+ def get_uplink_speed(self):
+ """Simulate get_uplink_speed(). """
+ return 1
+
+ def get_link_stats(self, link=0):
+ """Simulate get_link_stats(). """
+ return {
+ 'FS_LC%s_BYTE_CNT_0' % link: '0x0',
+ 'FS_LC%s_BYTE_CNT_1' % link: '0x0',
+ 'FS_LC%s_CFG_0' % link: '0x1030107f',
+ 'FS_LC%s_CFG_1' % link: '0x104f',
+ 'FS_LC%s_CM_RXDATA_0' % link: '0x0',
+ 'FS_LC%s_CM_RXDATA_1' % link: '0x0',
+ 'FS_LC%s_CM_TXDATA_0' % link: '0x0',
+ 'FS_LC%s_CM_TXDATA_1' % link: '0x0',
+ 'FS_LC%s_PKT_CNT_0' % link: '0x0',
+ 'FS_LC%s_PKT_CNT_1' % link: '0x0',
+ 'FS_LC%s_RDRPSCNT' % link: '0x0',
+ 'FS_LC%s_RERRSCNT' % link: '0x0',
+ 'FS_LC%sRMCSCNT' % link: '0x0',
+ 'FS_LC%s_RPKTSCNT' % link: '0x0',
+ 'FS_LC%s_RUCSCNT' % link: '0x0',
+ 'FS_LC%s_SC_STAT' % link: '0x0',
+ 'FS_LC%s_STATE' % link: '0x1033',
+ 'FS_LC%s_TDRPSCNT' % link: '0x0',
+ 'FS_LC%s_TPKTSCNT' % link: '0x1'
+ }
+
+ def get_linkmap(self):
+ """Simulate get_linkmap(). """
+ results = {}
+ for nid in range(0, len(self.ip_addresses)):
+ results[nid] = {nid: {1: 2, 3: 1, 4: 3}}
+ return results
+
+ def get_routing_table(self):
+ """Simulate get_routing_table(). """
+ results = {}
+ for nid in range(0, len(self.ip_addresses)):
+ results[nid] = {nid: {1: [0, 0, 0, 3, 0],
+ 2: [0, 3, 0, 0, 2],
+ 3: [0, 2, 0, 0, 3]}}
+ return results
+
+ def get_depth_chart(self):
+ """Simulate get_depth_chart(). """
+ results = {}
+ for nid in range(0, len(self.ip_addresses)):
+ results[nid] = {nid: {1: {'shortest': (0, 0)},
+ 2: {'hops': [(3, 1)], 'shortest': (0, 0)},
+ 3: {'hops': [(2, 1)], 'shortest': (0, 0)}}}
+ return results
+
+ def get_uplink(self, iface):
+ """Simulate get_uplink(). """
+ return 0
+
+ def get_node_fru_version(self):
+ """Simulate get_node_fru_version(). """
+ return "0.0"
+
+ def get_slot_fru_version(self):
+ """Simulate get_slot_fru_version(). """
+ return "0.0"
+
+
+class DummyFailNode(DummyNode):
+ """ Dummy node that should fail on some commands """
+
+ class DummyFailError(Exception):
+ """Dummy Fail Error class."""
+ pass
+
+ def get_power(self):
+ """Simulate get_power(). """
+ raise DummyFailNode.DummyFailError
diff --git a/cxmanage_api/tests/dummy_test.py b/cxmanage_api/tests/dummy_test.py
index c445272..8012ed2 100644
--- a/cxmanage_api/tests/dummy_test.py
+++ b/cxmanage_api/tests/dummy_test.py
@@ -1,6 +1,6 @@
import unittest
from mock import Mock, call
-from cxmanage_api.dummy import Dummy
+from cxmanage_api.tests import Dummy
class DummyTest(unittest.TestCase):
diff --git a/cxmanage_api/tests/dummy_ubootenv.py b/cxmanage_api/tests/dummy_ubootenv.py
new file mode 100644
index 0000000..a937419
--- /dev/null
+++ b/cxmanage_api/tests/dummy_ubootenv.py
@@ -0,0 +1,43 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+from cxmanage_api.ubootenv import UbootEnv
+
+
+class DummyUbootEnv(UbootEnv):
+ """UbootEnv info."""
+
+ def get_boot_order(self):
+ """Hard coded boot order for testing."""
+ return ["disk", "pxe"]
+
+ def set_boot_order(self, boot_args):
+ """ Do nothing """
+ pass
diff --git a/cxmanage_api/tests/fabric_test.py b/cxmanage_api/tests/fabric_test.py
index 6008388..3863186 100644
--- a/cxmanage_api/tests/fabric_test.py
+++ b/cxmanage_api/tests/fabric_test.py
@@ -38,7 +38,7 @@ from cxmanage_api.fabric import Fabric
from cxmanage_api.tftp import InternalTftp, ExternalTftp
from cxmanage_api.firmware_package import FirmwarePackage
from cxmanage_api.cx_exceptions import CommandFailedError
-from cxmanage_api.dummy import DummyNode, DummyFailNode
+from cxmanage_api.tests import DummyNode, DummyFailNode
# pylint: disable=R0904
diff --git a/cxmanage_api/tests/node_test.py b/cxmanage_api/tests/node_test.py
index e692e3e..1bbd6bc 100644
--- a/cxmanage_api/tests/node_test.py
+++ b/cxmanage_api/tests/node_test.py
@@ -37,8 +37,8 @@ import tempfile
import unittest
from mock import call
+from cxmanage_api.tests import DummyBMC, DummyUbootEnv, DummyIPRetriever
from cxmanage_api.tests import TestImage, random_file
-from cxmanage_api.dummy import DummyBMC, DummyUbootEnv, DummyIPRetriever
from cxmanage_api.node import Node
from cxmanage_api.firmware_package import FirmwarePackage
diff --git a/cxmanage_api/tests/utilities.py b/cxmanage_api/tests/utilities.py
new file mode 100644
index 0000000..6a405d7
--- /dev/null
+++ b/cxmanage_api/tests/utilities.py
@@ -0,0 +1,59 @@
+# Copyright (c) 2012-2013, Calxeda 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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * 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.
+# * Neither the name of Calxeda Inc. nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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 HOLDERS 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.
+
+import os
+import random
+import tempfile
+
+from cxmanage_api.image import Image
+
+
+def random_file(size):
+ """ Create a random file """
+ contents = "".join([chr(random.randint(0, 255)) for _ in range(size)])
+ file_, filename = tempfile.mkstemp(prefix='cxmanage_test-')
+ with os.fdopen(file_, "w") as file_handle:
+ file_handle.write(contents)
+
+ return filename
+
+
+class TestImage(Image):
+ """TestImage Class."""
+ def verify(self):
+ return True
+
+
+# pylint: disable=R0903
+class TestSensor(object):
+ """ Sensor result from bmc/target """
+ def __init__(self, sensor_name, sensor_reading):
+ self.sensor_name = sensor_name
+ self.sensor_reading = sensor_reading