remote_access: cache some basic checks

These should never change across a run, so cache their results.

BUG=None
TEST=`cros deploy` with multiple packages still works & caches calls

Change-Id: Icd5a48d7f8db47df90704fb3f44770dc70976b59
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/chromite/+/2651159
Tested-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
diff --git a/lib/remote_access.py b/lib/remote_access.py
index 4699de1..2cecd97 100644
--- a/lib/remote_access.py
+++ b/lib/remote_access.py
@@ -824,6 +824,7 @@
         ['PATH=%s:$PATH which' % DEV_BIN_PATHS, binary], check=False)
     return result.returncode == 0
 
+  @memoize.MemoizedSingleCall
   def HasRsync(self):
     """Checks if rsync exists on the device."""
     return self.HasProgramInPath('rsync')
@@ -838,6 +839,7 @@
                                       capture_output=True)
     return re.search(r'Speed: \d+000Mb/s', result.output)
 
+  @memoize.MemoizedSingleCall
   def IsSELinuxAvailable(self):
     """Check whether the device has SELinux compiled in."""
     # Note that SELinux can be enabled for some devices that lack SELinux
diff --git a/lib/remote_access_unittest.py b/lib/remote_access_unittest.py
index 9e842d2..5cf039e 100644
--- a/lib/remote_access_unittest.py
+++ b/lib/remote_access_unittest.py
@@ -388,29 +388,32 @@
 
     self.assertEqual(self.rsh_mock.call_count, 2)
 
-  def testSELinux(self):
-    """Tests behavior of IsSELinuxAvailable() and IsSELinuxEnforced()."""
+  def testSELinuxAvailable(self):
+    """Test IsSELinuxAvailable() and IsSELinuxEnforced() when available."""
     self.rsh_mock.AddCmdResult(
         partial_mock.ListRegex('which restorecon'), returncode=0)
+    self.rsh_mock.AddCmdResult(
+        partial_mock.ListRegex('test -f'), returncode=0)
     with remote_access.RemoteDeviceHandler(remote_access.TEST_IP) as device:
       self.rsh_mock.AddCmdResult(
-          partial_mock.ListRegex('test -f'), returncode=0)
-      self.rsh_mock.AddCmdResult(
           partial_mock.ListRegex('cat /sys/fs/selinux/enforce'),
           returncode=0, output='1')
       self.assertEqual(device.IsSELinuxAvailable(), True)
       self.assertEqual(device.IsSELinuxEnforced(), True)
 
       self.rsh_mock.AddCmdResult(
-          partial_mock.ListRegex('test -f'), returncode=0)
-      self.rsh_mock.AddCmdResult(
           partial_mock.ListRegex('cat /sys/fs/selinux/enforce'),
           returncode=0, output='0')
       self.assertEqual(device.IsSELinuxAvailable(), True)
       self.assertEqual(device.IsSELinuxEnforced(), False)
 
-      self.rsh_mock.AddCmdResult(
-          partial_mock.ListRegex('test -f'), returncode=1)
+  def testSELinuxUnavailable(self):
+    """Test IsSELinuxAvailable() and IsSELinuxEnforced() when unavailable."""
+    self.rsh_mock.AddCmdResult(
+        partial_mock.ListRegex('which restorecon'), returncode=0)
+    self.rsh_mock.AddCmdResult(
+        partial_mock.ListRegex('test -f'), returncode=1)
+    with remote_access.RemoteDeviceHandler(remote_access.TEST_IP) as device:
       self.assertEqual(device.IsSELinuxAvailable(), False)
       self.assertEqual(device.IsSELinuxEnforced(), False)