|
18 | 18 | import datetime
|
19 | 19 | import sys
|
20 | 20 | import os
|
| 21 | +from . import mock |
21 | 22 | from .mock import patch, MagicMock
|
| 23 | +import ssl |
22 | 24 | import time
|
23 | 25 | import types
|
24 | 26 | import uuid
|
@@ -1900,6 +1902,100 @@ def test_status_not_200(self, mock_request):
|
1900 | 1902 | mock_request.return_value = (response, {})
|
1901 | 1903 | self.assertRaises(shotgun_api3.ProtocolError, self.sg.find_one, 'Shot', [])
|
1902 | 1904 |
|
| 1905 | + @patch('shotgun_api3.shotgun.Http.request') |
| 1906 | + def test_make_call_retry(self, mock_request): |
| 1907 | + response = MagicMock(name="response mock", spec=dict) |
| 1908 | + response.status = 200 |
| 1909 | + response.reason = 'reason' |
| 1910 | + mock_request.return_value = (response, {}) |
| 1911 | + |
| 1912 | + bak_rpc_attempt_interval = self.sg.config.rpc_attempt_interval |
| 1913 | + self.sg.config.rpc_attempt_interval = 0 |
| 1914 | + try: |
| 1915 | + # First: make the request raise a consistent exception |
| 1916 | + mock_request.side_effect = Exception("not working") |
| 1917 | + with self.assertLogs( |
| 1918 | + 'shotgun_api3', level='DEBUG' |
| 1919 | + ) as cm1, self.assertRaises( |
| 1920 | + Exception |
| 1921 | + ) as cm2: |
| 1922 | + self.sg.info() |
| 1923 | + |
| 1924 | + self.assertEqual(cm2.exception.args[0], "not working") |
| 1925 | + log_content = "\n".join(cm1.output) |
| 1926 | + for i in [1,2]: |
| 1927 | + self.assertIn( |
| 1928 | + f"Request failed, attempt {i} of 3. Retrying", |
| 1929 | + log_content, |
| 1930 | + ) |
| 1931 | + self.assertIn( |
| 1932 | + "Request failed. Giving up after 3 attempts.", |
| 1933 | + log_content, |
| 1934 | + ) |
| 1935 | + |
| 1936 | + # Then, make the exception happening only once and prove the |
| 1937 | + # retry works |
| 1938 | + def my_side_effect(*args, **kwargs): |
| 1939 | + try: |
| 1940 | + if my_side_effect.counter<1: |
| 1941 | + raise Exception("not working") |
| 1942 | + |
| 1943 | + return mock.DEFAULT |
| 1944 | + finally: |
| 1945 | + my_side_effect.counter += 1 |
| 1946 | + |
| 1947 | + my_side_effect.counter = 0 |
| 1948 | + mock_request.side_effect = my_side_effect |
| 1949 | + with self.assertLogs('shotgun_api3', level='DEBUG') as cm: |
| 1950 | + self.assertIsInstance( |
| 1951 | + self.sg.info(), |
| 1952 | + dict, |
| 1953 | + ) |
| 1954 | + |
| 1955 | + log_content = "\n".join(cm.output) |
| 1956 | + self.assertIn( |
| 1957 | + "Request failed, attempt 1 of 3. Retrying", |
| 1958 | + log_content, |
| 1959 | + ) |
| 1960 | + self.assertNotIn( |
| 1961 | + "Request failed, attempt 2 of 3. Retrying", |
| 1962 | + log_content, |
| 1963 | + ) |
| 1964 | + |
| 1965 | + # Last: raise a SSLEOFError exception - SG-34910 |
| 1966 | + def my_side_effect2(*args, **kwargs): |
| 1967 | + try: |
| 1968 | + if my_side_effect2.counter<1: |
| 1969 | + raise ssl.SSLEOFError( |
| 1970 | + "EOF occurred in violation of protocol (_ssl.c:2426)" |
| 1971 | + ) |
| 1972 | + |
| 1973 | + return mock.DEFAULT |
| 1974 | + finally: |
| 1975 | + my_side_effect2.counter += 1 |
| 1976 | + |
| 1977 | + my_side_effect2.counter = 0 |
| 1978 | + mock_request.side_effect = my_side_effect2 |
| 1979 | + |
| 1980 | + with self.assertLogs('shotgun_api3', level='DEBUG') as cm: |
| 1981 | + self.assertIsInstance( |
| 1982 | + self.sg.info(), |
| 1983 | + dict, |
| 1984 | + ) |
| 1985 | + |
| 1986 | + log_content = "\n".join(cm.output) |
| 1987 | + self.assertIn("SSLEOFError", log_content) |
| 1988 | + self.assertIn( |
| 1989 | + "Request failed, attempt 1 of 3. Retrying", |
| 1990 | + log_content, |
| 1991 | + ) |
| 1992 | + self.assertNotIn( |
| 1993 | + "Request failed, attempt 2 of 3. Retrying", |
| 1994 | + log_content, |
| 1995 | + ) |
| 1996 | + finally: |
| 1997 | + self.sg.config.rpc_attempt_interval = bak_rpc_attempt_interval |
| 1998 | + |
1903 | 1999 | @patch('shotgun_api3.shotgun.Http.request')
|
1904 | 2000 | def test_sha2_error(self, mock_request):
|
1905 | 2001 | # Simulate the exception raised with SHA-2 errors
|
|
0 commit comments