Add a controller class to manage RF Switch.

This controller class gets all AP boxes and Client Boxes attached to the
RF Switch. Adding unit tests.

BUG=b:34983942
TEST=None

Change-Id: If541ef5815cf4fafd4466e28edea26218251f76a
Reviewed-on: https://chromium-review.googlesource.com/451577
Commit-Ready: Ashakiran Byrappa <abyrappa@google.com>
Tested-by: Ashakiran Byrappa <abyrappa@google.com>
Reviewed-by: Harpreet Grewal <harpreet@chromium.org>
Reviewed-by: Kris Rambish <krisr@chromium.org>
Reviewed-by: Godofredo Contreras <godofredoc@chromium.org>
diff --git a/server/cros/network/rf_switch_controller.py b/server/cros/network/rf_switch_controller.py
new file mode 100644
index 0000000..d8dca5c
--- /dev/null
+++ b/server/cros/network/rf_switch_controller.py
@@ -0,0 +1,76 @@
+# Copyright (c) 2017 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.
+
+"""RF Switch is a device used to route WiFi signals through RF cables
+between 4 isolation boxes with APs and 4 isolation boxes with DUTs.
+
+RFSwitchController Class provides methods to control RF Switch.
+
+This class can be used to:
+1) retrieve all APBoxes and ClientBoxes connected to the RF Switch.
+2) connect Client and AP Boxes for testing.
+3) retrieve information about current connections.
+4) reset all connections.
+"""
+
+import logging
+
+from autotest_lib.server import frontend
+from autotest_lib.server import site_utils
+from autotest_lib.server.cros.network import rf_switch_ap_box
+from autotest_lib.server.cros.network import rf_switch_client_box
+
+
+RF_SWITCH_STR = 'rf_switch_'
+RF_SWITCH_CLIENT = 'rf_switch_client'
+RF_SWITCH_APS = 'rf_switch_aps'
+
+
+class RFSwitchController(object):
+    """Controller class to manage the RFSwitch."""
+
+
+    def __init__(self, rf_switch_host):
+        """Constructor for RF Switch Controller.
+
+        @param rf_switch_host: An AFE Host object of RF Switch.
+        """
+        self.rf_switch_host = rf_switch_host
+        self.rf_switch_labels = rf_switch_host.labels
+        # RF Switches are named as rf_switch_1, rf_switch_2 using labels.
+        # To find the rf_switch, find label starting with 'rf_switch_'
+        labels = [
+                s for s in self.rf_switch_labels if s.startswith(RF_SWITCH_STR)]
+        afe = frontend.AFE(
+                debug=True, server=site_utils.get_global_afe_hostname())
+        self.hosts = afe.get_hosts(label=labels)
+        self.ap_boxes = []
+        self.client_boxes = []
+        for host in self.hosts:
+            if RF_SWITCH_APS in host.labels:
+                self.ap_boxes.append(rf_switch_ap_box.APBox(host))
+            elif RF_SWITCH_CLIENT in host.labels:
+                self.client_boxes.append(rf_switch_client_box.ClientBox(host))
+        if not self.ap_boxes:
+            logging.error('No AP boxes available for the RF Switch.')
+        if not self.client_boxes:
+            logging.error('No Client boxes available for the RF Switch.')
+
+
+    def get_ap_boxes(self):
+        """Returns all AP Boxes connected to the RF Switch.
+
+        @returns a list of
+        autotest_lib.server.cros.network.rf_switch_ap_box.APBox objects.
+        """
+        return self.ap_boxes
+
+
+    def get_client_boxes(self):
+        """Returns all Client Boxes connected to the RF Switch.
+
+        @returns a list of
+        autotest_lib.server.cros.network.rf_switch_client_box.ClientBox objects.
+        """
+        return self.client_boxes
diff --git a/server/cros/network/rf_switch_controller_test.py b/server/cros/network/rf_switch_controller_test.py
new file mode 100644
index 0000000..9b24463
--- /dev/null
+++ b/server/cros/network/rf_switch_controller_test.py
@@ -0,0 +1,100 @@
+"""Tests for rf_switch_controller class."""
+
+import unittest
+
+import mock
+
+from autotest_lib.server import frontend
+from autotest_lib.server import site_utils
+from autotest_lib.server.cros.network import rf_switch_controller
+
+
+class RfSwitchControllerTest(unittest.TestCase):
+    """Tests for RF Switch Controller class."""
+
+
+    RF_SWITCH_CLIENT = 'rf_switch_client'
+    RF_SWITCH_APS = 'rf_switch_aps'
+
+
+    def setUp(self):
+        """Initial setup required to test the methods.
+
+        Create three hosts: RF Switch, AP Box and Client Box. Assign the
+        hostnames and labels. Create an instance of RfSwitchController and
+        add mock hosts.
+        """
+        self.rf_switch_host = frontend.Host('', '')
+        self.ap_box_host = frontend.Host('', '')
+        self.client_box_host = frontend.Host('', '')
+
+        self.rf_switch_host.hostname = 'chromeos9-rfswitch'
+        self.ap_box_host.hostname = 'chromeos9-apbox1'
+        self.client_box_host.hostname = 'chromeos9-clientbox1'
+
+        self.rf_switch_host.labels = ['rf_switch', 'rf_switch_1']
+        self.ap_box_host.labels = ['rf_switch_1', 'ap_box_1', 'rf_switch_aps']
+        self.client_box_host.labels = [
+                'rf_switch_1', 'client_box_1', 'rf_switch_client']
+
+
+    @mock.patch('autotest_lib.server.frontend.AFE')
+    def testGetAPBoxes(self, mock_afe):
+        """Test to get all AP Boxes connected to the RF Switch."""
+        afe_instance = mock_afe()
+        afe_instance.get_hosts.return_value = [
+                self.ap_box_host, self.client_box_host]
+        rf_switch_manager = rf_switch_controller.RFSwitchController(
+                self.rf_switch_host)
+        ap_boxes = rf_switch_manager.get_ap_boxes()
+        self.assertEquals(len(ap_boxes), 1)
+        ap_box = ap_boxes[0]
+        self.assertEquals(ap_box.ap_box_host.hostname, 'chromeos9-apbox1')
+
+
+    @mock.patch('autotest_lib.server.frontend.AFE')
+    def testGetClientBoxes(self, mock_afe):
+        """Test to get all Client Boxes connected to the RF Switch."""
+        afe_instance = mock_afe()
+        afe_instance.get_hosts.return_value = [
+                self.ap_box_host, self.client_box_host]
+        rf_switch_manager = rf_switch_controller.RFSwitchController(
+                self.rf_switch_host)
+        client_boxes = rf_switch_manager.get_client_boxes()
+        self.assertEquals(len(client_boxes), 1)
+        client_box = client_boxes[0]
+        self.assertEquals(
+                client_box.client_box_host.hostname, 'chromeos9-clientbox1')
+
+
+    @mock.patch('autotest_lib.server.frontend.AFE')
+    def testRfSwitchNotConnectedToAPBoxes(self, mock_afe):
+        """Testing scenario when RF Switch is not connnected to AP Boxes."""
+        afe_instance = mock_afe()
+        afe_instance.get_hosts.return_value = [self.client_box_host]
+        with mock.patch('logging.Logger.error') as mock_logger:
+            rf_switch_manager = rf_switch_controller.RFSwitchController(
+                    self.rf_switch_host)
+            mock_logger.assert_called_with(
+                    'No AP boxes available for the RF Switch.')
+        ap_boxes = rf_switch_manager.get_ap_boxes()
+        self.assertEquals(len(ap_boxes), 0)
+
+
+    @mock.patch('autotest_lib.server.frontend.AFE')
+    def testClientBoxWithInvalidLabels(self, mock_afe):
+        """Test when RF Switch connected to Client Box with invalid labels."""
+        afe_instance = mock_afe()
+        self.client_box_host.labels = ['rf_switch_1', 'client_1', 'rf_client']
+        afe_instance.get_hosts.return_value = [self.client_box_host]
+        with mock.patch('logging.Logger.error') as mock_logger:
+            rf_switch_manager = rf_switch_controller.RFSwitchController(
+                    self.rf_switch_host)
+            mock_logger.assert_called_with(
+                'No Client boxes available for the RF Switch.')
+        client_boxes = rf_switch_manager.get_client_boxes()
+        self.assertEquals(len(client_boxes), 0)
+
+
+if __name__ == '__main__':
+  unittest.main()