11import json
2+ import logging
23import sys
34
45import pytest
@@ -14,14 +15,17 @@ def __init__(
1415 * ,
1516 reason = "" ,
1617 url = "https://example.test/cwms-data/resource" ,
17- incident = None
18+ incident = None ,
19+ stack_trace_lines = None ,
1820 ):
1921 self .status_code = status_code
2022 self .reason = reason
2123 self .url = url
2224 payload = {"message" : message }
2325 if incident is not None :
2426 payload ["incidentIdentifier" ] = incident
27+ if stack_trace_lines is not None :
28+ payload ["details" ] = {"stackTraceLines" : stack_trace_lines }
2529 self .text = json .dumps (payload )
2630 self .content = self .text .encode ("utf-8" )
2731
@@ -139,3 +143,99 @@ def fake_cli(*args, **kwargs):
139143
140144 with pytest .raises (RuntimeError , match = "boom" ):
141145 cli_main .main ()
146+
147+
148+ def test_main_formats_cda_stack_trace_when_debug_env_enabled (monkeypatch , capsys ):
149+ from cwms .api import ApiError
150+
151+ def fake_cli (* args , ** kwargs ):
152+ raise ApiError (
153+ _FakeResponse (
154+ 400 ,
155+ "Text 'not-a-date' could not be parsed at index 0" ,
156+ reason = "Bad Request" ,
157+ incident = "trace-123" ,
158+ stack_trace_lines = [
159+ "java.time.format.DateTimeParseException: invalid date" ,
160+ "\t at cwms.cda.helpers.DateUtils.parseUserDate(DateUtils.java:91)" ,
161+ ],
162+ )
163+ )
164+
165+ monkeypatch .setattr (cli_main , "cli" , fake_cli )
166+ monkeypatch .setattr (sys , "argv" , ["cwms-cli" , "dummy" ])
167+ monkeypatch .setenv ("CWMS_CLI_DEBUG" , "1" )
168+
169+ with pytest .raises (SystemExit ) as exc :
170+ cli_main .main ()
171+
172+ captured = capsys .readouterr ()
173+ assert exc .value .code == 1
174+ assert "CDA server stack trace" in captured .err
175+ assert "incidentIdentifier: trace-123" in captured .err
176+ assert "java.time.format.DateTimeParseException" in captured .err
177+ assert "DateUtils.parseUserDate" in captured .err
178+ assert "Traceback (most recent call last)" not in captured .err
179+
180+
181+ def test_main_log_level_debug_formats_cda_stack_trace (monkeypatch , capsys ):
182+ from cwms .api import ApiError
183+
184+ previous_level = logging .getLogger ().level
185+
186+ def fake_cli (* args , ** kwargs ):
187+ logging .getLogger ().setLevel (logging .DEBUG )
188+ raise ApiError (
189+ _FakeResponse (
190+ 500 ,
191+ "System Error" ,
192+ incident = "trace-456" ,
193+ stack_trace_lines = ["java.lang.RuntimeException: boom" ],
194+ )
195+ )
196+
197+ monkeypatch .setattr (cli_main , "cli" , fake_cli )
198+ monkeypatch .setattr (sys , "argv" , ["cwms-cli" , "--log-level" , "DEBUG" , "dummy" ])
199+ monkeypatch .delenv ("CWMS_CLI_DEBUG" , raising = False )
200+
201+ try :
202+ with pytest .raises (SystemExit ) as exc :
203+ cli_main .main ()
204+ finally :
205+ logging .getLogger ().setLevel (previous_level )
206+
207+ captured = capsys .readouterr ()
208+ assert exc .value .code == 1
209+ assert "CDA server stack trace" in captured .err
210+ assert "java.lang.RuntimeException: boom" in captured .err
211+
212+
213+ def test_main_debug_finds_cda_stack_behind_click_exception (monkeypatch , capsys ):
214+ from cwms .api import ApiError
215+
216+ def fake_cli (* args , ** kwargs ):
217+ try :
218+ raise ApiError (
219+ _FakeResponse (
220+ 500 ,
221+ "System Error" ,
222+ incident = "trace-789" ,
223+ stack_trace_lines = ["java.lang.NullPointerException: missing" ],
224+ )
225+ )
226+ except ApiError :
227+ raise click .ClickException ("Friendly command error" ) from None
228+
229+ monkeypatch .setattr (cli_main , "cli" , fake_cli )
230+ monkeypatch .setattr (sys , "argv" , ["cwms-cli" , "dummy" ])
231+ monkeypatch .setenv ("CWMS_CLI_DEBUG" , "1" )
232+
233+ with pytest .raises (SystemExit ) as exc :
234+ cli_main .main ()
235+
236+ captured = capsys .readouterr ()
237+ assert exc .value .code == 1
238+ assert "CDA server stack trace" in captured .err
239+ assert "incidentIdentifier: trace-789" in captured .err
240+ assert "java.lang.NullPointerException: missing" in captured .err
241+ assert "Friendly command error" not in captured .err
0 commit comments