Merge "Unit tests: mock some time.sleep and time.time"
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index c7cc638..492bdca 100644
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -20,6 +20,7 @@
 from tempest import exceptions
 from tempest.services.volume.base import base_volumes_client
 from tempest.tests import base
+import tempest.tests.utils as utils
 
 
 class TestImageWaiters(base.TestCase):
@@ -37,17 +38,24 @@
         # Ensure waiter returns before build_timeout
         self.assertTrue((end_time - start_time) < 10)
 
-    def test_wait_for_image_status_timeout(self):
+    @mock.patch('time.sleep')
+    def test_wait_for_image_status_timeout(self, mock_sleep):
+        time_mock = self.patch('time.time')
+        time_mock.side_effect = utils.generate_timeout_series(1)
+
         self.client.show_image.return_value = ({'status': 'saving'})
         self.assertRaises(exceptions.TimeoutException,
                           waiters.wait_for_image_status,
                           self.client, 'fake_image_id', 'active')
+        mock_sleep.assert_called_once_with(1)
 
-    def test_wait_for_image_status_error_on_image_create(self):
+    @mock.patch('time.sleep')
+    def test_wait_for_image_status_error_on_image_create(self, mock_sleep):
         self.client.show_image.return_value = ({'status': 'ERROR'})
         self.assertRaises(exceptions.AddImageException,
                           waiters.wait_for_image_status,
                           self.client, 'fake_image_id', 'active')
+        mock_sleep.assert_called_once_with(1)
 
     @mock.patch.object(time, 'sleep')
     def test_wait_for_volume_status_error_restoring(self, mock_sleep):
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/test_rest_client.py
index 6aff305..87af455 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/test_rest_client.py
@@ -25,6 +25,7 @@
 from tempest.tests.lib import base
 from tempest.tests.lib import fake_auth_provider
 from tempest.tests.lib import fake_http
+import tempest.tests.utils as utils
 
 
 class BaseRestClientTestClass(base.TestCase):
@@ -511,11 +512,20 @@
     def test_wait_for_resource_deletion_not_deleted(self):
         self.patch('time.sleep')
         # Set timeout to be very quick to force exception faster
-        self.rest_client.build_timeout = 1
+        timeout = 1
+        self.rest_client.build_timeout = timeout
+
+        time_mock = self.patch('time.time')
+        time_mock.side_effect = utils.generate_timeout_series(timeout)
+
         self.assertRaises(exceptions.TimeoutException,
                           self.rest_client.wait_for_resource_deletion,
                           '1234')
 
+        # time.time() should be called twice, first to start the timer
+        # and then to compute the timedelta
+        self.assertEqual(2, time_mock.call_count)
+
     def test_wait_for_deletion_with_unimplemented_deleted_method(self):
         self.rest_client.is_resource_deleted = self.original_deleted_method
         self.assertRaises(NotImplementedError,
diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py
index 7a4fc09..f6efd47 100644
--- a/tempest/tests/lib/test_ssh.py
+++ b/tempest/tests/lib/test_ssh.py
@@ -14,7 +14,6 @@
 
 from io import StringIO
 import socket
-import time
 
 import mock
 import six
@@ -23,6 +22,7 @@
 from tempest.lib.common import ssh
 from tempest.lib import exceptions
 from tempest.tests.lib import base
+import tempest.tests.utils as utils
 
 
 class TestSshClient(base.TestCase):
@@ -79,7 +79,8 @@
         self.assertEqual(expected_connect, client_mock.connect.mock_calls)
         self.assertEqual(0, s_mock.call_count)
 
-    def test_get_ssh_connection_two_attemps(self):
+    @mock.patch('time.sleep')
+    def test_get_ssh_connection_two_attemps(self, sleep_mock):
         c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
 
         c_mock.return_value = client_mock
@@ -89,15 +90,18 @@
         ]
 
         client = ssh.Client('localhost', 'root', timeout=1)
-        start_time = int(time.time())
         client._get_ssh_connection(sleep=1)
-        end_time = int(time.time())
-        self.assertLess((end_time - start_time), 4)
-        self.assertGreater((end_time - start_time), 1)
+        # We slept 2 seconds: because sleep is "1" and backoff is "1" too
+        sleep_mock.assert_called_once_with(2)
+        self.assertEqual(2, client_mock.connect.call_count)
 
     def test_get_ssh_connection_timeout(self):
         c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
 
+        timeout = 2
+        time_mock = self.patch('time.time')
+        time_mock.side_effect = utils.generate_timeout_series(timeout + 1)
+
         c_mock.return_value = client_mock
         client_mock.connect.side_effect = [
             socket.error,
@@ -105,13 +109,16 @@
             socket.error,
         ]
 
-        client = ssh.Client('localhost', 'root', timeout=2)
-        start_time = int(time.time())
-        with testtools.ExpectedException(exceptions.SSHTimeout):
-            client._get_ssh_connection()
-        end_time = int(time.time())
-        self.assertLess((end_time - start_time), 5)
-        self.assertGreaterEqual((end_time - start_time), 2)
+        client = ssh.Client('localhost', 'root', timeout=timeout)
+        # We need to mock LOG here because LOG.info() calls time.time()
+        # in order to preprend a timestamp.
+        with mock.patch.object(ssh, 'LOG'):
+            self.assertRaises(exceptions.SSHTimeout,
+                              client._get_ssh_connection)
+
+        # time.time() should be called twice, first to start the timer
+        # and then to compute the timedelta
+        self.assertEqual(2, time_mock.call_count)
 
     @mock.patch('select.POLLIN', SELECT_POLLIN, create=True)
     def test_timeout_in_exec_command(self):
diff --git a/tempest/tests/utils.py b/tempest/tests/utils.py
new file mode 100644
index 0000000..9c3049d
--- /dev/null
+++ b/tempest/tests/utils.py
@@ -0,0 +1,29 @@
+#    Copyright 2016 OpenStack Foundation
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+#
+
+
+def generate_timeout_series(timeout):
+    """Generate a series of times that exceeds the given timeout.
+
+    Yields a series of fake time.time() floating point numbers
+    such that the difference between each pair in the series just
+    exceeds the timeout value that is passed in.  Useful for
+    mocking time.time() in methods that otherwise wait for timeout
+    seconds.
+    """
+    iteration = 0
+    while True:
+        iteration += 1
+        yield (iteration * timeout) + iteration