Implement TempDir

Cherry-pick cl/185568469

TEST=acloud create --build_target gce_x86_phone-userdebug_fastbuild3c_linux
--build_id 3744001 --config_file ~/acloud.config
--serial_log /tmp/mylog.tar.gz -vv
Observed temp dir is created and deleted

Change-Id: I6838c26d4b0cefa6d1e999412205728e4be912ce
diff --git a/internal/lib/utils_test.py b/internal/lib/utils_test.py
index bb1200e..a450933 100644
--- a/internal/lib/utils_test.py
+++ b/internal/lib/utils_test.py
@@ -16,9 +16,12 @@
 
 """Tests for acloud.internal.lib.utils."""
 
+import errno
 import getpass
 import os
+import shutil
 import subprocess
+import tempfile
 import time
 
 import mock
@@ -30,6 +33,87 @@
 
 class UtilsTest(driver_test_lib.BaseDriverTest):
 
+  def testTempDir_Success(self):
+    """Test create a temp dir."""
+    self.Patch(os, "chmod")
+    self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
+    self.Patch(shutil, "rmtree")
+    with utils.TempDir():
+      pass
+    # Verify.
+    tempfile.mkdtemp.assert_called_once()
+    shutil.rmtree.assert_called_with("/tmp/tempdir")
+
+  def testTempDir_ExceptionRaised(self):
+    """Test create a temp dir and exception is raised within with-clause."""
+    self.Patch(os, "chmod")
+    self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
+    self.Patch(shutil, "rmtree")
+
+    class ExpectedException(Exception):
+      pass
+
+    def _Call():
+      with utils.TempDir():
+        raise ExpectedException("Expected exception.")
+    # Verify. ExpectedException should be raised.
+    self.assertRaises(ExpectedException, _Call)
+    tempfile.mkdtemp.assert_called_once()
+    shutil.rmtree.assert_called_with("/tmp/tempdir")
+
+  def testTempDir_WhenDeleteTempDirNoLongerExist(self):
+    """Test create a temp dir and dir no longer exists during deletion."""
+    self.Patch(os, "chmod")
+    self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
+    expected_error = EnvironmentError()
+    expected_error.errno = errno.ENOENT
+    self.Patch(shutil, "rmtree", side_effect=expected_error)
+    def _Call():
+      with utils.TempDir():
+        pass
+    # Verify no exception should be raised when rmtree raises
+    # EnvironmentError with errno.ENOENT, i.e.
+    # directory no longer exists.
+    _Call()
+    tempfile.mkdtemp.assert_called_once()
+    shutil.rmtree.assert_called_with("/tmp/tempdir")
+
+  def testTempDir_WhenDeleteEncounterError(self):
+    """Test create a temp dir and encoutered error during deletion."""
+    self.Patch(os, "chmod")
+    self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
+    expected_error = OSError("Expected OS Error")
+    self.Patch(shutil, "rmtree", side_effect=expected_error)
+    def _Call():
+      with utils.TempDir():
+        pass
+
+    # Verify OSError should be raised.
+    self.assertRaises(OSError, _Call)
+    tempfile.mkdtemp.assert_called_once()
+    shutil.rmtree.assert_called_with("/tmp/tempdir")
+
+  def testTempDir_OrininalErrorRaised(self):
+    """Test original error is raised even if tmp dir deletion failed."""
+    self.Patch(os, "chmod")
+    self.Patch(tempfile, "mkdtemp", return_value="/tmp/tempdir")
+    expected_error = OSError("Expected OS Error")
+    self.Patch(shutil, "rmtree", side_effect=expected_error)
+
+    class ExpectedException(Exception):
+      pass
+
+    def _Call():
+      with utils.TempDir():
+        raise ExpectedException("Expected Exception")
+
+    # Verify.
+    # ExpectedException should be raised, and OSError
+    # should not be raised.
+    self.assertRaises(ExpectedException, _Call)
+    tempfile.mkdtemp.assert_called_once()
+    shutil.rmtree.assert_called_with("/tmp/tempdir")
+
   def testCreateSshKeyPair_KeyAlreadyExists(self):
     """Test when the key pair already exists."""
     public_key = "/fake/public_key"