[Local Agent] Sync LA feature from source:

1. Update host for EAP partners
2. Fix unit test flakiness

Change-Id: I579a1ad95bc6b8de7bd65faab0ccc13d9e353655
diff --git a/local_agent/ams_client.py b/local_agent/ams_client.py
index 3382a43..4d1fee6 100644
--- a/local_agent/ams_client.py
+++ b/local_agent/ams_client.py
@@ -26,12 +26,6 @@
 
 logger = logger_module.get_logger()
 
-# TODO(b/194648316): Use production host when ready to launch.
-# The default AMS server configuration.
-_AMS_SCHEME = 'https'
-_AMS_HOST = 'chip-testsuite-experimental.appspot.com'
-_AMS_PORT = None
-
 # _ENDPOINTS stores the endpoint definitions.
 # _TIMEOUTS stores the timeout config for the endpoints.
 _ENDPOINTS = immutabledict.immutabledict({
@@ -47,6 +41,7 @@
 _DEFAULT_TIMEOUT = 5.0
 _DEFAULT_RETRY = 3
 _DEFAULT_RETRY_INTERVAL = 1.0
+_DEFAULT_SCHEME = 'https'
 _UNLINKED_ERR_MSG = 'Invalid agent id'
 
 
@@ -92,13 +87,14 @@
     APIs to AMS and receive responses.
     """
 
-    def __init__(self,
-                 host: Optional[str] = None,
-                 port: Optional[int] = None,
-                 scheme: Optional[str] = None):
+    def __init__(
+        self,
+        host: str,
+        port: Optional[int] = None,
+        scheme: str = _DEFAULT_SCHEME):
         """Initializes the AMS client.
 
-        The host, port, and scheme parameters are all optional. If not
+        The port and scheme parameters are optional. If not
         provided, we will use the defaults.
 
         Args:
@@ -106,9 +102,6 @@
             port: The port of AMS server.
             scheme: Either 'http' or 'https'.
         """
-        host = host or _AMS_HOST
-        port = port or _AMS_PORT
-        scheme = scheme or _AMS_SCHEME
         if port is not None:
             self._base_url = f'{scheme}://{host}:{port}'
         else:
diff --git a/local_agent/local_agent.py b/local_agent/local_agent.py
index b029faf..94b1541 100644
--- a/local_agent/local_agent.py
+++ b/local_agent/local_agent.py
@@ -55,6 +55,9 @@
 _USER_CONFIG_AMS_SCHEME = 'AMS_SCHEME'
 _USER_CONFIG_ARTIFACTS_DIR = 'ARTIFACTS_DIR'
 _USER_CONFIG_MATTER_DEVICE_CONTROLLERS = 'MatterDeviceControllerPackages'
+_EAP_AMS_HOST = 'rainier-test-suite-eap.appspot.com'
+_EAP_AMS_PORT = None
+_EAP_AMS_SCHEME = 'https'
 # ======================================================================= #
 
 
@@ -550,7 +553,7 @@
     sys.argv[1:] = leftover
 
     if not os.path.exists(args.user_config):
-        return {}
+        return {}, {}
 
     config = configparser.ConfigParser(allow_no_value=True)
     config.read(args.user_config)
@@ -584,9 +587,9 @@
     """Main entry of Local Agent."""
     user_config, matter_controllers_config = read_config()
 
-    ams_host = user_config.get(_USER_CONFIG_AMS_HOST)
-    ams_port = user_config.get(_USER_CONFIG_AMS_PORT)
-    ams_scheme = user_config.get(_USER_CONFIG_AMS_SCHEME)
+    ams_host = user_config.get(_USER_CONFIG_AMS_HOST, _EAP_AMS_HOST)
+    ams_port = user_config.get(_USER_CONFIG_AMS_PORT, _EAP_AMS_PORT)
+    ams_scheme = user_config.get(_USER_CONFIG_AMS_SCHEME, _EAP_AMS_SCHEME)
     artifacts_dir = (
         user_config.get(_USER_CONFIG_ARTIFACTS_DIR, DEFAULT_ARTIFACTS_DIR))
 
diff --git a/local_agent/tests/unit_tests/test_ams_client.py b/local_agent/tests/unit_tests/test_ams_client.py
index f99fc1c..ae71ac0 100644
--- a/local_agent/tests/unit_tests/test_ams_client.py
+++ b/local_agent/tests/unit_tests/test_ams_client.py
@@ -23,11 +23,15 @@
 from local_agent import ams_client
 from local_agent import errors
 
+_FAKE_HOST = 'fake-host'
+_FAKE_PORT = 8000
+
 
 class AmsClientTest(unittest.TestCase):
 
     def setUp(self):
         super().setUp()
+        self.sut = ams_client.AmsClient(host=_FAKE_HOST, port=_FAKE_PORT)
         sleep_patcher = mock.patch.object(time, 'sleep')
         sleep_patcher.start()
         self.addCleanup(sleep_patcher.stop)
@@ -36,7 +40,6 @@
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_register_success(self, mock_request, mock_set_credentials):
         """Verifies register successful."""
-        sut = ams_client.AmsClient()
         mock_response = mock_request.return_value
         mock_response.status_code = 200
         mock_response.json.return_value = {
@@ -44,7 +47,7 @@
                 'agentId': 'the-id',
                 'agentSecret': 'the-secret'}}
 
-        sut.register(linking_code='the-linking-code')
+        self.sut.register(linking_code='the-linking-code')
 
         mock_set_credentials.assert_called_once_with(
             local_agent_id='the-id',
@@ -53,18 +56,16 @@
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_register_api_timeout(self, mock_request):
         """Verifies register raises ApiTimeoutError when request timed out."""
-        sut = ams_client.AmsClient()
         mock_request.side_effect = requests.exceptions.Timeout
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.register(linking_code='the-linking-code')
+            self.sut.register(linking_code='the-linking-code')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_register_api_return_status_bad_request(self, mock_request):
         """Verifies register raises CredentialError when API response 400."""
-        sut = ams_client.AmsClient()
         mock_request.return_value.status_code = http.HTTPStatus.BAD_REQUEST
         with self.assertRaises(errors.CredentialsError):
-            sut.register(linking_code='the-linking-code')
+            self.sut.register(linking_code='the-linking-code')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_register_api_error_message_included(self, mock_request):
@@ -72,18 +73,16 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.BAD_REQUEST
         mock_response.json.return_value = {'errorMessage': 'the-message'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.CredentialsError, 'the-message'):
-            sut.register(linking_code='the-linking-code')
+            self.sut.register(linking_code='the-linking-code')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_register_api_return_status_not_ok(self, mock_request):
         """Verifies register raises ApiError when API fails."""
-        sut = ams_client.AmsClient()
         mock_request.return_value.status_code = http.HTTPStatus.NOT_FOUND
         with self.assertRaises(errors.ApiError):
-            sut.register(linking_code='the-linking-code')
+            self.sut.register(linking_code='the-linking-code')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_set_local_agent_credentials_get_auth_token_success(self, mock_request):
@@ -95,8 +94,7 @@
                 'authToken': 'the-auth-token',
             }
         }
-        sut = ams_client.AmsClient()
-        sut.set_local_agent_credentials('agent-id', 'agent-secret')
+        self.sut.set_local_agent_credentials('agent-id', 'agent-secret')
 
     @mock.patch.object(ams_client.AmsClient, '_request_wrapper')
     def test_get_auth_token_not_refreshing_auth(self, mock_request_wrapper):
@@ -104,9 +102,8 @@
         mock_response = mock_request_wrapper.return_value
         mock_response.status_code = http.HTTPStatus.CREATED
         mock_response.json.return_value = {'result': {'authToken': 'abc'}}
-        sut = ams_client.AmsClient()
 
-        sut._get_auth_token()
+        self.sut._get_auth_token()
 
         self.assertFalse(
             mock_request_wrapper.call_args.kwargs['refresh_auth'],
@@ -121,29 +118,26 @@
         mock_response = mock_request_wrapper.return_value
         mock_response.status_code = http.HTTPStatus.BAD_REQUEST
         mock_extract_err_msg.return_value = 'Invalid agent id'
-        sut = ams_client.AmsClient()
 
         error_regex = 'Local agent is unlinked'
         with self.assertRaisesRegex(errors.UnlinkedError, error_regex):
-            sut._get_auth_token()
+            self.sut._get_auth_token()
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_set_local_agent_credentials_raises_when_api_timeout(self,
                                                                  mock_request):
         """Verifies set_local_agent_credentials raises when API timed out."""
         mock_request.side_effect = requests.exceptions.Timeout
-        sut = ams_client.AmsClient()
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.set_local_agent_credentials('agent-id', 'agent-secret')
+            self.sut.set_local_agent_credentials('agent-id', 'agent-secret')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_set_local_agent_credentials_raises_when_api_error(self,
                                                                mock_request):
         """Verifies set_local_agent_credentials raises when API has error."""
         mock_request.return_value.status_code = http.HTTPStatus.NOT_FOUND
-        sut = ams_client.AmsClient()
         with self.assertRaises(errors.CredentialsError):
-            sut.set_local_agent_credentials('agent-id', 'agent-secret')
+            self.sut.set_local_agent_credentials('agent-id', 'agent-secret')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_set_local_agent_credentials_include_ams_error_message(
@@ -153,28 +147,25 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.NOT_FOUND
         mock_response.json.return_value = {'errorMessage': 'the-message'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.CredentialsError, 'the-message'):
-            sut.set_local_agent_credentials('agent-id', 'agent-secret')
+            self.sut.set_local_agent_credentials('agent-id', 'agent-secret')
 
     @mock.patch.object(requests.sessions.Session,
                        'request',
                        side_effect=requests.exceptions.Timeout)
     def test_report_info_api_timeout(self, mock_request):
         """Verifies report_info API timed out."""
-        sut = ams_client.AmsClient()
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.report_info({})
+            self.sut.report_info({})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_report_info_api_response_error(self, mock_request):
         """Verifies report_info raise exception when API response has error."""
         mock_request.return_value.status_code = http.HTTPStatus.BAD_REQUEST
-        sut = ams_client.AmsClient()
         with self.assertRaisesRegex(errors.ApiError,
                                     'Report info API failed: status 400'):
-            sut.report_info({})
+            self.sut.report_info({})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_report_info_api_response_error_include_ams_error_message(
@@ -184,19 +175,17 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.BAD_REQUEST
         mock_response.json.return_value = {'errorMessage': 'the-message'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.ApiError, 'the-message'):
-            sut.report_info({})
+            self.sut.report_info({})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_report_info_successful(self, mock_request):
         """Verifies report_info succeeds and sends info dict to AMS."""
         mock_request.return_value.status_code = http.HTTPStatus.OK
         local_agent_info = {'hi': 'hello'}
-        sut = ams_client.AmsClient()
 
-        sut.report_info(local_agent_info)
+        self.sut.report_info(local_agent_info)
 
         self.assertIn(
             'json',
@@ -211,9 +200,8 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.OK
         mock_response.json.return_value = {'result': {'hi': 'hello'}}
-        sut = ams_client.AmsClient()
 
-        self.assertEqual(sut.get_rpc_request_from_ams(),
+        self.assertEqual(self.sut.get_rpc_request_from_ams(),
                          {'hi': 'hello'})
 
     @mock.patch.object(requests.sessions.Session, 'request')
@@ -222,19 +210,17 @@
         """Verifies get_rpc_request_from_ams gets no request from AMS."""
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.NO_CONTENT
-        sut = ams_client.AmsClient()
 
-        self.assertIsNone(sut.get_rpc_request_from_ams())
+        self.assertIsNone(self.sut.get_rpc_request_from_ams())
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_get_rpc_request_from_ams_raises_when_api_timeout(self,
                                                               mock_request):
         """Verifies get_rpc_request_from_ams raises when API timed out."""
         mock_request.side_effect = requests.exceptions.Timeout
-        sut = ams_client.AmsClient()
 
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.get_rpc_request_from_ams()
+            self.sut.get_rpc_request_from_ams()
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_get_rpc_request_from_ams_raise_when_api_response_error(
@@ -242,10 +228,9 @@
         """Verifies get_rpc_request_from_ams raises when response has error."""
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.INTERNAL_SERVER_ERROR
-        sut = ams_client.AmsClient()
 
         with self.assertRaises(errors.ApiError):
-            sut.get_rpc_request_from_ams()
+            self.sut.get_rpc_request_from_ams()
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_get_rpc_request_from_ams_when_api_error_has_exception_message(
@@ -254,27 +239,26 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.INTERNAL_SERVER_ERROR
         mock_response.json.return_value = {'errorMessage': 'message-from-ams'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.ApiError, r'500.*message-from-ams'):
-            sut.get_rpc_request_from_ams()
+            self.sut.get_rpc_request_from_ams()
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_remove_rpc_request_from_ams_successful(self, mock_request):
         """Verifies remove_rpc_request_from_ams succeeds."""
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.OK
-        sut = ams_client.AmsClient()
-        sut.remove_rpc_request_from_ams({'the': 'request'})
+
+        self.sut.remove_rpc_request_from_ams({'the': 'request'})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_remove_rpc_request_from_ams_raises_when_api_timeout(
         self, mock_request):
         """Verifies remove_rpc_request_from_ams raises if API timed out."""
         mock_request.side_effect = requests.exceptions.Timeout
-        sut = ams_client.AmsClient()
+
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.remove_rpc_request_from_ams({'the': 'request'})
+            self.sut.remove_rpc_request_from_ams({'the': 'request'})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_remove_rpc_request_from_ams_raises_when_api_fails(
@@ -283,18 +267,17 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.INTERNAL_SERVER_ERROR
         mock_response.json.return_value = {'errorMessage': 'msg-from-ams'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.ApiError, r'500.*msg-from-ams'):
-            sut.remove_rpc_request_from_ams({'the': 'request'})
+            self.sut.remove_rpc_request_from_ams({'the': 'request'})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_send_rpc_response_successful(self, mock_request):
         """Verifies send_rpc_response sends RPC response to AMS successfully.
         """
         mock_request.return_value.status_code = http.HTTPStatus.OK
-        sut = ams_client.AmsClient()
-        sut.send_rpc_response({'the': 'response'})
+
+        self.sut.send_rpc_response({'the': 'response'})
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_send_rpc_response_raise_api_error(self, mock_request):
@@ -304,10 +287,9 @@
         mock_response.status_code = (
             http.HTTPStatus.INTERNAL_SERVER_ERROR)
         mock_response.json.return_value = {'errorMessage': 'the-ams-msg'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.ApiError, '500.*the-ams-msg'):
-            sut.send_rpc_response({'the': 'response'})
+            self.sut.send_rpc_response({'the': 'response'})
         # Verify we have retried.
         self.assertEqual(4, mock_request.call_count)
 
@@ -316,10 +298,9 @@
         """Verifies send_rpc_response raises ApiTimeoutError if API timed out.
         """
         mock_request.side_effect = requests.exceptions.Timeout
-        sut = ams_client.AmsClient()
 
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.send_rpc_response({'the': 'response'})
+            self.sut.send_rpc_response({'the': 'response'})
         # Verify we have retried.
         self.assertEqual(4, mock_request.call_count)
 
@@ -341,10 +322,9 @@
             requests.exceptions.Timeout,
             mock_500_response,
         )
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.ApiError, '500'):
-            sut.send_rpc_response({'the': 'response'})
+            self.sut.send_rpc_response({'the': 'response'})
         # Verify we have refreshed the auth token, and that does not count as
         # a retry.
         self.assertEqual(1, mock_get_auth_token.call_count)
@@ -355,8 +335,8 @@
     def test_upload_artifact_successful(self, mock_open, mock_request):
         """Verifies upload_artifact succeeds."""
         mock_request.return_value.status_code = http.HTTPStatus.OK
-        sut = ams_client.AmsClient()
-        sut.upload_artifact('the/file/path', 'the-test-result-id')
+
+        self.sut.upload_artifact('the/file/path', 'the-test-result-id')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     @mock.patch.object(ams_client, 'open', new_callable=mock.mock_open)
@@ -364,9 +344,9 @@
         """Verifies upload_artifact raises ApiTimeoutError if API timed out."""
         mock_request.return_value.status_code = http.HTTPStatus.OK
         mock_request.side_effect = requests.exceptions.Timeout
-        sut = ams_client.AmsClient()
+
         with self.assertRaises(errors.ApiTimeoutError):
-            sut.upload_artifact('the/file/path', 'the-test-result-id')
+            self.sut.upload_artifact('the/file/path', 'the-test-result-id')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     @mock.patch.object(ams_client, 'open', new_callable=mock.mock_open)
@@ -375,10 +355,9 @@
         mock_response = mock_request.return_value
         mock_response.status_code = http.HTTPStatus.INTERNAL_SERVER_ERROR
         mock_response.json.return_value = {'errorMessage': 'the-ams-err-msg'}
-        sut = ams_client.AmsClient()
 
         with self.assertRaisesRegex(errors.ApiError, '500.*the-ams-err-msg'):
-            sut.upload_artifact('the/file/path', 'the-test-result-id')
+            self.sut.upload_artifact('the/file/path', 'the-test-result-id')
 
     @mock.patch.object(requests.sessions.Session, 'request')
     def test_request_wrapper_no_timeout_and_invalid_num_retries(
@@ -386,9 +365,8 @@
         """Verifies request_wrapper no timeout field and invalid num_retries."""
         mock_response = mock.Mock(status_code=http.HTTPStatus.OK)
         mock_request.return_value = mock_response
-        sut = ams_client.AmsClient()
 
-        response = sut._request_wrapper(num_retries=-1)
+        response = self.sut._request_wrapper(num_retries=-1)
 
         self.assertEqual(mock_response, response)
 
diff --git a/local_agent/tests/unit_tests/test_local_agent.py b/local_agent/tests/unit_tests/test_local_agent.py
index 3b796a3..3f52f66 100644
--- a/local_agent/tests/unit_tests/test_local_agent.py
+++ b/local_agent/tests/unit_tests/test_local_agent.py
@@ -32,7 +32,6 @@
 
 ####################### Fake data for unit test #############################
 _FAKE_AMS_HOST = 'localhost'
-_FAKE_AMS_PORT = 8000
 _FAKE_AGENT_ID = 'fake-agent-id'
 _FAKE_AGENT_SECRET = 'fake-agent-secret'
 _FAKE_AUTH_TOKEN = 'fake-auth-token'
@@ -53,7 +52,8 @@
     def setUp(self):
         super().setUp()
         self.proc = local_agent.LocalAgentProcess(
-            client=ams_client.AmsClient(), artifacts_dir=_FAKE_ARTIFACTS_DIR)
+            client=ams_client.AmsClient(host=_FAKE_AMS_HOST), 
+            artifacts_dir=_FAKE_ARTIFACTS_DIR)
 
         _, local_agent.AUTH_FILE = self._create_temp_file_with_clean_up()
         _, local_agent.DEFAULT_USER_CONFIG = (
@@ -154,7 +154,7 @@
     def test_05_read_config_with_inexistent_file(self):
         """Verifies read_config returns {} when config file doesn't exist."""
         local_agent.DEFAULT_USER_CONFIG = ''
-        self.assertEqual({}, local_agent.read_config())
+        self.assertEqual(({}, {}), local_agent.read_config())
 
     @mock.patch.object(configparser, 'ConfigParser')
     def test_05_read_config_missing_root_key(self, mock_parser):
@@ -437,20 +437,20 @@
         mock_logger.error.assert_called_once()
 
     @mock.patch.object(ams_client.AmsClient, 'upload_artifact')
-    @mock.patch.object(os, 'stat')
+    @mock.patch.object(local_agent, 'os')
     @mock.patch.object(shutil, 'rmtree')
     @mock.patch.object(shutil, 'make_archive')
     def test_11_compress_artifacts_and_upload_on_success(
-        self, mock_make, mock_rm, mock_stat, mock_ams_upload):
+        self, mock_make, mock_rm, mock_os, mock_ams_upload):
         """Verifies _compress_artifacts_and_upload on success."""
-        mock_stat.return_value.st_size = 1
+        mock_os.stat.return_value.st_size = 1
         with mock.patch('builtins.open',
                         new_callable=mock.mock_open):
             self.proc._compress_artifacts_and_upload('', '')
-        self.assertEqual(1, mock_make.call_count)
-        self.assertEqual(1, mock_rm.call_count)
-        self.assertEqual(1, mock_stat.call_count)
-        self.assertEqual(1, mock_ams_upload.call_count)
+        mock_make.assert_called_once()
+        mock_rm.assert_called_once()
+        mock_os.stat.assert_called_once()
+        mock_ams_upload.assert_called_once()
 
     @mock.patch.object(os, 'stat')
     @mock.patch.object(shutil, 'rmtree')
diff --git a/local_agent/tests/unit_tests/test_suite_session_manager.py b/local_agent/tests/unit_tests/test_suite_session_manager.py
index 901e816..c9830cb 100644
--- a/local_agent/tests/unit_tests/test_suite_session_manager.py
+++ b/local_agent/tests/unit_tests/test_suite_session_manager.py
@@ -33,6 +33,8 @@
 _START_TEST_SUITE = 'startTestSuite'
 _END_TEST_SUITE = 'endTestSuite'
 _THREADING_MODULE_PATH = 'threading.Thread'
+_FAKE_OUTDATED_ARTIFACTS = 'outdated_artifacts.zip'
+_FAKE_NOT_OUTDATED_ARTIFACTS = 'not_outdated_artifacts.zip'
 ##############################################################################
 
 
@@ -169,56 +171,46 @@
         mock_add.assert_called_once()
 
     @mock.patch.object(logger_module, 'logger')
-    @mock.patch.object(os, 'listdir')
-    @mock.patch.object(os.path, 'isfile', return_value=True)
-    @mock.patch.object(os, 'stat')
-    @mock.patch.object(os, 'remove')
-    @mock.patch.object(os.path, 'exists', return_value=True)
+    @mock.patch.object(suite_session_manager, 'os')
     def test_06_remove_outdated_artifacts_on_success(
-        self,
-        mock_exists,
-        mock_rm,
-        mock_stat,
-        mock_isfile,
-        mock_listdir,
-        mock_logger):
+        self, mock_os, mock_logger):
         """Verifies _remove_outdated_artifacts removes outdated files only."""
-        mock_listdir.return_value = [
-            'outdated_artifacts.zip',
-            'not_outdated_artifacts.zip',
+        mock_os.listdir.return_value = [
+            _FAKE_OUTDATED_ARTIFACTS,
+            _FAKE_NOT_OUTDATED_ARTIFACTS
         ]
-        mock_stat.side_effect = [
+        mock_os.stat.side_effect = [
             mock.Mock(st_ctime=0),
             mock.Mock(st_ctime=time.time()),
         ]
+        mock_os.path.isfile.return_value = True
+        mock_os.path.exists.return_value = True
+        mock_os.path.join.return_value = _FAKE_OUTDATED_ARTIFACTS
 
         self.suite_mgr._remove_outdated_artifacts()
 
-        mock_exists.assert_called_once()
-        mock_rm.assert_called_once()
-        self.assertEqual(2, mock_isfile.call_count)
-        self.assertEqual('outdated_artifacts.zip',
-                         os.path.basename(mock_rm.call_args.args[0]))
+        mock_os.path.exists.assert_called_once()
+        mock_os.remove.assert_called_once()
+        self.assertEqual(2, mock_os.path.isfile.call_count)
+        self.assertEqual(_FAKE_OUTDATED_ARTIFACTS,
+                         mock_os.remove.call_args.args[0])
 
-    @mock.patch.object(os, 'listdir')
-    @mock.patch.object(os.path, 'isfile', return_value=True)
-    @mock.patch.object(os, 'stat')
-    @mock.patch.object(os, 'remove')
-    @mock.patch.object(os.path, 'exists', return_value=True)
+    @mock.patch.object(suite_session_manager, 'os')
     def test_06_remove_outdated_artifacts_will_suppress_oserror(
-        self, mock_exists, mock_rm, mock_stat, mock_isfile, mock_listdir):
+        self, mock_os):
         """
         Verifies _remove_outdated_artifacts suppresses OSError
         when cannot remove.
         """
-        mock_listdir.return_value = ['artifacts.zip']
-        mock_stat.return_value.st_ctime = 0
-        mock_rm.side_effect = OSError
+        mock_os.listdir.return_value = [_FAKE_OUTDATED_ARTIFACTS]
+        mock_os.path.isfile.return_value = True
+        mock_os.stat.return_value.st_ctime = 0
+        mock_os.remove.side_effect = OSError
 
         self.suite_mgr._remove_outdated_artifacts()
 
-        mock_exists.assert_called_once()
-        mock_rm.assert_called_once()
+        mock_os.path.exists.assert_called_once()
+        mock_os.remove.assert_called_once()
 
     @mock.patch.object(os, 'remove')
     @mock.patch.object(os.path, 'exists', return_value=False)