Improved the rack concept, added OysterBay, tests.

Added OysterBayPxtDevelopmentRack which inherits from
RackWithLteAndDataSourceBase. These classes hold the
constituents of the rack, as well as what steps are
needed to initialize them.

Added RackWithLteAndHspa3GAndDataSourceBase as a
prototype to illustrate a Rack with more than one
call box.

BUG=chromium:272493
TEST=run_all_tests.py

Change-Id: Icab1dafe5c6773b2394bd6585b3f660d38381fe8
Reviewed-on: https://chromium-review.googlesource.com/182865
Reviewed-by: Prathmesh Prabhu <pprabhu@chromium.org>
Commit-Queue: Byron Kubert <byronk@chromium.org>
Tested-by: Byron Kubert <byronk@chromium.org>
diff --git a/self_tests/unit_tests_software/test_oyster_bay_development_rack.py b/self_tests/unit_tests_software/test_oyster_bay_development_rack.py
new file mode 100644
index 0000000..a87c665
--- /dev/null
+++ b/self_tests/unit_tests_software/test_oyster_bay_development_rack.py
@@ -0,0 +1,66 @@
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import unittest
+import subprocess
+
+from wireless_automation.racks import rack_with_lte_and_data_source
+
+
+class LocalIperf(object):
+
+    def __init__(self, config):
+        self.iperf_process = None
+        self.config = config
+
+    def __enter__(self):
+        self.iperf_process = subprocess.Popen(['iperf', '-s'])
+        self.config['NetworkDataSource']['ip_address'] = '127.0.0.1'
+        return self
+
+    def __exit__(self, the_type, value, tracebaack):
+        self.iperf_process.terminate()
+        return True
+
+
+class TestOysterBayDevelopmentRack(unittest.TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
+
+    @staticmethod
+    def test_make_a_real_one():
+        config = rack_with_lte_and_data_source.\
+            OysterBayPxtDevelopmentRack.get_default_config()
+        # Make this run against the local machine
+        with LocalIperf(config) as liperf:
+            one = rack_with_lte_and_data_source.\
+                OysterBayPxtDevelopmentRack(liperf.config)
+
+    @staticmethod
+    def test_make_a_fake_one():
+        config = rack_with_lte_and_data_source.\
+            OysterBayPxtDevelopmentRack.get_default_config()
+        config['NetworkDataSource']['fake_hardware'] = True
+        config['LteCallBox']['fake_hardware'] = True
+        one = rack_with_lte_and_data_source.\
+            OysterBayPxtDevelopmentRack(config)
+        assert True
+
+    @staticmethod
+    def test_composed_interface():
+        config = rack_with_lte_and_data_source.\
+            OysterBayPxtDevelopmentRack.get_default_config()
+
+    @staticmethod
+    def test_start_a_real_pxt():
+        config = rack_with_lte_and_data_source.\
+            OysterBayPxtDevelopmentRack.get_default_config()
+        with LocalIperf(config) as cfg:
+            one = rack_with_lte_and_data_source.\
+                OysterBayPxtDevelopmentRack(cfg.config)
+            one.call_box.start()
diff --git a/self_tests/unittests/test_oyster_bay_development_rack.py b/self_tests/unittests/test_oyster_bay_development_rack.py
deleted file mode 100644
index 2f22415..0000000
--- a/self_tests/unittests/test_oyster_bay_development_rack.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import unittest
-import subprocess
-
-from wireless_automation.racks import oyster_bay_rack
-
-
-class LocalIperf(object):
-
-    def __init__(self, config):
-        self.iperf_process = None
-        self.config = config
-
-    def __enter__(self):
-        self.iperf_process = subprocess.Popen(['/usr/bin/iperf', '-s'])
-        self.config['NetworkDataSource']['ip_address'] = '127.0.0.1'
-        return self
-
-    def __exit__(self, the_type, value, tracebaack):
-        self.iperf_process.terminate()
-        return True
-
-
-class TestOysterBayDevelopmentRack(unittest.TestCase):
-
-    def setUp(self):
-        pass
-
-    def tearDown(self):
-        pass
-
-    @staticmethod
-    def test_make_a_real_one():
-        config = \
-            oyster_bay_rack.OysterBayPxtDevelopmentRack.get_default_config()
-        # Make this run against the local machine
-        with LocalIperf(config) as liperf:
-            one = oyster_bay_rack.OysterBayPxtDevelopmentRack(liperf.config)
-
-    @staticmethod
-    def test_make_a_fake_one():
-        config = \
-            oyster_bay_rack.OysterBayPxtDevelopmentRack.get_default_config()
-        config['CallBoxFactory']['call_box_type'] = 'fake'
-        print '\n'.join(config.write())
-        print config
-        config['CallBoxFactory']['call_box_model'] = 'fake'
-        config['NetworkDataSource']['fake'] = True
-        one = oyster_bay_rack.OysterBayPxtDevelopmentRack(config)
-
-    @staticmethod
-    def test_composed_interface():
-        config = \
-            oyster_bay_rack.OysterBayPxtDevelopmentRack.get_default_config()
-        print config
-
-    @staticmethod
-    def test_start_a_real_pxt():
-        config = \
-            oyster_bay_rack.OysterBayPxtDevelopmentRack.get_default_config()
-        print '\n'.join(config.write())
-        config['CallBoxFactory']['call_box_model'] = 'pxt'
-        with LocalIperf(config) as cfg:
-            one = oyster_bay_rack.OysterBayPxtDevelopmentRack(cfg.config)
-            one.call_box.start()
diff --git a/wireless_automation/racks/call_box_rack_interface.py b/wireless_automation/racks/call_box_rack_interface.py
deleted file mode 100644
index d41005c..0000000
--- a/wireless_automation/racks/call_box_rack_interface.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-Definition of base racks. These define all the high level types
-of racks which tests use. There is one Rack Base for each major type
-of equipment setup; e.g. the PowerConsumptionRackBase, the
-CellularCallBoxRackBase, the CellularFemtocellRackBase. The specifics
-are handled by the children. CellularCallBoxRackBase may have
-
-Building1CellularCallBoxRack
-Building2CellularCallBoxRack
-
-With each of these containing the knowledge of how that particular
-lab is wired up. The RF ports may go through a splitter,  a notch
-filter and a series of RF switches. All this goes in this child
-class and the all the tests that use this rack never have to care.
-
-"""
-
-from wireless_automation.aspects import configurable
-from wireless_automation.duts import dut_factory
-from wireless_automation.instruments.call_box import call_box_factory
-from wireless_automation.instruments.network_data_source \
-    import network_data_source
-from wireless_automation.instruments.rf_switch import RfSwitch
-
-
-class CallBoxRackInterface(configurable.Configurable):
-    """
-    Base class for call box racks. Tests should be able to
-    run with any CallBoxRack.
-
-    """
-    CONFIGSPEC = [
-        'reset_everything = boolean(default=True)'] +\
-        configurable.nest_configspecs([
-            ('CallBoxFactory', call_box_factory.CallBoxFactory),
-            ('RfSwitch', RfSwitch),
-            ('Dut', dut_factory.DutFactory),
-            ('NetworkDataSource', network_data_source.NetworkDataSource)
-        ])
-
-    def __init__(self, config):
-        super(CallBoxRackInterface, self).__init__(config)
diff --git a/wireless_automation/racks/oyster_bay_rack.py b/wireless_automation/racks/oyster_bay_rack.py
deleted file mode 100644
index 69c1e8c..0000000
--- a/wireless_automation/racks/oyster_bay_rack.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-The OysterBayRack details. Derived from CallBoxRackInterface.
-"""
-
-from wireless_automation.aspects import configurable
-from wireless_automation.aspects import wireless_automation_logging
-from wireless_automation.duts import dut_factory
-from wireless_automation.instruments import rf_switch
-from wireless_automation.instruments.call_box import call_box_factory
-from wireless_automation.instruments.network_data_source \
-    import network_data_source
-from wireless_automation.racks import call_box_rack_interface
-
-# This class looks abstract because it doesn't have any functions.
-# It's used here as a container class, to hold both the parts of
-# rack, as well as the knowledge of how to setup that rack.
-# pylint: disable=interface-not-implemented
-
-
-class OysterBayPxtDevelopmentRack(call_box_rack_interface.CallBoxRackInterface):
-    """
-    Representation of the development rack in OysterBay.
-    """
-    # CONFIGSPEC is inherited from CallBoxRackInterface, and the configspec
-    # is part of that. Default values can change, but
-    # changing entries suggests you don't want a derived class.
-    base_configspec = call_box_rack_interface.CallBoxRackInterface.CONFIGSPEC
-    CONFIGSPEC = configurable.list_to_configspec(base_configspec)
-    # Change the IP's to the right ones for this lab
-    CONFIGSPEC['CallBoxFactory']['CallBox']['scpi_ip_address'] = \
-        "ip_addr(default='172.22.50.244')"
-    CONFIGSPEC['RfSwitch']['ip_address'] = \
-        "ip_addr(default='172.22.50.243')"
-
-    def __init__(self, config):
-        super(OysterBayPxtDevelopmentRack, self).__init__(config)
-        self.log = wireless_automation_logging.setup_logging('Rack')
-
-        cbf_config = config['CallBoxFactory']
-        self.call_box = call_box_factory.CallBoxFactory.build_one(cbf_config)
-
-        rfs_config = config['RfSwitch']
-        self.rf_switch = rf_switch.RfSwitch(rfs_config)
-
-        dut_config = config['Dut']
-        self.dut = dut_factory.build_one(dut_config)
-
-        cd_config = config['NetworkDataSource']
-        self.network_data_source = (
-            network_data_source.NetworkDataSource(cd_config))
-
-    def reset(self):
-        """
-        Reset entire rack.
-        """
-        self.call_box.reset()
-
-
-class ChromebookInfo(object):  # pylint:disable=too-many-instance-attributes,too-few-public-methods,line-too-long
-    """
-    A class to store Chromebook info.
-    todo(byronk): This class should be in a separate file? But the data
-    is only useful for OysterBayRack.
-    Fix this when we have a better idea what the job of a rack is.
-    So all these pylint disables can go away.
-    """
-    def __init__(self, name, ip, mac, modem,  # pylint:disable=too-many-arguments,line-too-long
-                 air_interfaces, location, rfswitch, switch_port):
-        self.long_name = name  # Long and meaningful name.
-        self.gpib_ip = ip  # The IP address of the GPIB bus.
-        self.mac = mac  # Hardware MAC address of the Ethernet interface
-        self.modem = modem  # The name of the modem
-        #assert air_interfaces in all_air_interfaces
-        self.air_interfaces = air_interfaces
-        self.location = location
-        self.rf_switch = rfswitch
-        self.switch_port = switch_port
-
-LAB_CHROMEBOOK_DICT = {
-    'link-lte': ChromebookInfo(name='DVT Link with LTE',
-                               ip="172.22.50.86",
-                               mac="00:0e:c6:89:9d:18",
-                               modem='GOBI3K',
-                               air_interfaces=["LTE"],
-                               location="rack2-host6",
-                               rfswitch="switch_1",
-                               switch_port="port1")
-}
diff --git a/wireless_automation/racks/rack_with_lte_and_data_source.py b/wireless_automation/racks/rack_with_lte_and_data_source.py
new file mode 100644
index 0000000..2f86fa6
--- /dev/null
+++ b/wireless_automation/racks/rack_with_lte_and_data_source.py
@@ -0,0 +1,86 @@
+# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""
+The OysterBayRack details. Derived from CallBoxRackInterface.
+"""
+
+from wireless_automation.aspects import configurable
+from wireless_automation.aspects import wireless_automation_logging
+from wireless_automation.instruments.call_box import call_box_interface
+from wireless_automation.instruments.call_box.agilent_pxt import call_box_pxt
+from wireless_automation.instruments.network_data_source \
+    import network_data_source
+
+# This class looks abstract because it doesn't have any functions.
+# It's used here as a container class, to hold both the parts of
+# rack, as well as the knowledge of how to setup that rack.
+# pylint: disable=interface-not-implemented
+
+
+class RackWithLteAndDataSourceBase(configurable.Configurable):
+    """
+    Representation of the development rack in OysterBay.
+    This does not contain a DUT.  DUTs are connected to
+    the rack for tests.
+    """
+    CONFIGSPEC = [
+        'reset_everything = boolean(default=True)'] +\
+        configurable.nest_configspecs([
+            ('LteCallBox', call_box_interface.CallBoxLteInterface),
+            ('NetworkDataSource', network_data_source.NetworkDataSource)
+        ])
+
+    def __init__(self, config):
+        """
+        :type self: object
+        """
+        super(RackWithLteAndDataSourceBase, self).__init__(config)
+        self.log = wireless_automation_logging.setup_logging('Rack')
+        self.log.info('Constructing : %s' % self.__class__)
+
+        cd_config = config['NetworkDataSource']
+        self.network_data_source = (
+            network_data_source.NetworkDataSource(cd_config))
+
+    def reset(self):
+        """
+        Reset entire rack.
+        """
+        # todo: add rest of parts to reset here
+# pylint: enable=interface-not-implemented
+
+
+class OysterBayPxtDevelopmentRack(RackWithLteAndDataSourceBase):
+    """
+    Specific settings for the specific rack in Oyster Bay.
+    This is a good place to set IP addresses.
+    """
+    # Change the config settings for OysterBay
+    base_configspec = RackWithLteAndDataSourceBase.CONFIGSPEC
+    CONFIGSPEC = configurable.list_to_configspec(base_configspec)
+    # Change the IP's to the right ones for this lab
+    CONFIGSPEC['LteCallBox']['scpi_ip_address'] = \
+        "ip_addr(default='172.22.50.236')"
+    CONFIGSPEC['NetworkDataSource']['ssh_ip_address'] = \
+        "ip_addr(default='172.22.50.236')"
+    CONFIGSPEC['NetworkDataSource']['ssh_port'] = 'integer(default=222)'
+
+    def __init__(self, config):
+        RackWithLteAndDataSourceBase.__init__(self, config)
+        self.log.info('Constructing : %s' % self.__class__)
+        cbf_config = config['LteCallBox']
+        self.call_box = call_box_pxt.CallBoxPxt(cbf_config)
+        assert True
+
+
+class RackWithLteAndHspa3GAndDataSourceBase(RackWithLteAndDataSourceBase):
+    """
+    Abstract class that adds the HSPA and 3G ability to the LTE Rack.
+    """
+    base_configspec = RackWithLteAndDataSourceBase.CONFIGSPEC
+    CONFIGSPEC = configurable.list_to_configspec(base_configspec)
+
+    def __init__(self, config):
+        RackWithLteAndDataSourceBase.__init__(self, config)
+        self.log.info('Constructing : %s' % self.__class__)