16
16
from datetime import datetime
17
17
from datetime import timedelta
18
18
from datetime import timezone
19
+ import sys
19
20
20
21
import unittest
22
+ import pytest
21
23
22
24
import mock
23
25
@@ -1739,6 +1741,87 @@ def test_context_mgr_failure(self):
1739
1741
self .assertEqual (list (batch .entries ), UNSENT )
1740
1742
self .assertIsNone (api ._write_entries_called_with )
1741
1743
1744
+ @pytest .mark .skipif (
1745
+ sys .version_info < (3 , 8 ),
1746
+ reason = "InvalidArgument init with details requires python3.8+" ,
1747
+ )
1748
+ def test_append_context_to_error (self ):
1749
+ """
1750
+ If an InvalidArgument exception contains info on the log that threw it,
1751
+ we should be able to add it to the exceptiom message. If not, the
1752
+ exception should be unchanged
1753
+ """
1754
+ from google .api_core .exceptions import InvalidArgument
1755
+ from google .rpc .error_details_pb2 import DebugInfo
1756
+ from google .cloud .logging import TextEntry
1757
+
1758
+ logger = _Logger ()
1759
+ client = _Client (project = self .PROJECT )
1760
+ batch = self ._make_one (logger , client = client )
1761
+ test_entries = [TextEntry (payload = str (i )) for i in range (11 )]
1762
+ batch .entries = test_entries
1763
+ starting_message = "test"
1764
+ # test that properly formatted exceptions add log details
1765
+ for idx , entry in enumerate (test_entries ):
1766
+ api_entry = entry .to_api_repr ()
1767
+ err = InvalidArgument (
1768
+ starting_message , details = ["padding" , DebugInfo (detail = f"key: { idx } " )]
1769
+ )
1770
+ batch ._append_context_to_error (err )
1771
+ self .assertEqual (err .message , f"{ starting_message } : { str (api_entry )} ..." )
1772
+ self .assertIn (str (idx ), str (entry ))
1773
+ # test with missing debug info
1774
+ err = InvalidArgument (starting_message , details = [])
1775
+ batch ._append_context_to_error (err )
1776
+ self .assertEqual (
1777
+ err .message , starting_message , "message should have been unchanged"
1778
+ )
1779
+ # test with missing key
1780
+ err = InvalidArgument (
1781
+ starting_message , details = ["padding" , DebugInfo (detail = "no k e y here" )]
1782
+ )
1783
+ batch ._append_context_to_error (err )
1784
+ self .assertEqual (
1785
+ err .message , starting_message , "message should have been unchanged"
1786
+ )
1787
+ # test with key out of range
1788
+ err = InvalidArgument (
1789
+ starting_message , details = ["padding" , DebugInfo (detail = "key: 100" )]
1790
+ )
1791
+ batch ._append_context_to_error (err )
1792
+ self .assertEqual (
1793
+ err .message , starting_message , "message should have been unchanged"
1794
+ )
1795
+
1796
+ @pytest .mark .skipif (
1797
+ sys .version_info < (3 , 8 ),
1798
+ reason = "InvalidArgument init with details requires python3.8+" ,
1799
+ )
1800
+ def test_batch_error_gets_context (self ):
1801
+ """
1802
+ Simulate an InvalidArgument sent as part of a batch commit, to ensure
1803
+ _append_context_to_error is thrown
1804
+ """
1805
+ from google .api_core .exceptions import InvalidArgument
1806
+ from google .rpc .error_details_pb2 import DebugInfo
1807
+ from google .cloud .logging import TextEntry
1808
+
1809
+ logger = _Logger ()
1810
+ client = _Client (project = self .PROJECT )
1811
+ starting_message = "hello"
1812
+ exception = InvalidArgument (
1813
+ starting_message , details = [DebugInfo (detail = "key: 1" )]
1814
+ )
1815
+ client .logging_api = _DummyLoggingExceptionAPI (exception )
1816
+ batch = self ._make_one (logger , client = client )
1817
+ test_entries = [TextEntry (payload = str (i )) for i in range (11 )]
1818
+ batch .entries = test_entries
1819
+ with self .assertRaises (InvalidArgument ) as e :
1820
+ batch .commit ()
1821
+ expected_log = test_entries [1 ]
1822
+ api_entry = expected_log .to_api_repr ()
1823
+ self .assertEqual (e .message , f"{ starting_message } : { str (api_entry )} ..." )
1824
+
1742
1825
1743
1826
class _Logger (object ):
1744
1827
@@ -1773,6 +1856,25 @@ def logger_delete(self, logger_name):
1773
1856
self ._logger_delete_called_with = logger_name
1774
1857
1775
1858
1859
+ class _DummyLoggingExceptionAPI (object ):
1860
+ def __init__ (self , exception ):
1861
+ self .exception = exception
1862
+
1863
+ def write_entries (
1864
+ self ,
1865
+ entries ,
1866
+ * ,
1867
+ logger_name = None ,
1868
+ resource = None ,
1869
+ labels = None ,
1870
+ partial_success = False ,
1871
+ ):
1872
+ raise self .exception
1873
+
1874
+ def logger_delete (self , logger_name ):
1875
+ raise self .exception
1876
+
1877
+
1776
1878
class _Client (object ):
1777
1879
def __init__ (self , project , connection = None ):
1778
1880
self .project = project
0 commit comments