Skip to content

Commit bb0e268

Browse files
committed
fix: add AAA test sections and update docformatter config
1 parent c685f3e commit bb0e268

File tree

3 files changed

+82
-13
lines changed

3 files changed

+82
-13
lines changed

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ mkdocs-material = ">=9"
5353
mkdocstrings = {version=">=0", extras=["python"]}
5454
mkdocs-print-site-plugin = "^2.3.6"
5555

56+
[tool.docformatter]
57+
wrap-summaries = 0
58+
wrap-descriptions = 0
59+
5660
[build-system]
5761
requires = ["poetry>=1.0.0"]
5862
build-backend = "poetry.masonry.api"

solnlib/bulletin_rest_client.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ def __init__(
4040
app: str,
4141
**context: dict,
4242
):
43-
"""Initializes BulletinRestClient. When creating a new bulletin
44-
message, you must provide a name, which is a kind of ID. If you try to
45-
create another message with the same name (ID), the API will not add
46-
another message to the bulletin, but it will overwrite the existing
47-
one. Similar behaviour applies to deletion. To delete a message, you
48-
must indicate the name (ID) of the message. To provide better and
49-
easier control over bulletin messages, this client works in such a way
50-
that there is one instance responsible for handling one specific
51-
message. If you need to add another message to bulletin create another
52-
instance with a different 'message_name' e.g. msg_1 =
53-
BulletinRestClient("message_1", "<some session key>") msg_2 =
54-
BulletinRestClient("message_2", "<some session key>")
43+
"""Initializes BulletinRestClient.
44+
When creating a new bulletin message, you must provide a name, which is a kind of ID.
45+
If you try to create another message with the same name (ID), the API will not add another message
46+
to the bulletin, but it will overwrite the existing one. Similar behaviour applies to deletion.
47+
To delete a message, you must indicate the name (ID) of the message.
48+
To provide better and easier control over bulletin messages, this client works in such a way
49+
that there is one instance responsible for handling one specific message.
50+
If you need to add another message to bulletin create another instance
51+
with a different 'message_name'
52+
e.g.
53+
msg_1 = BulletinRestClient("message_1", "<some session key>")
54+
msg_2 = BulletinRestClient("message_2", "<some session key>")
5555
5656
Arguments:
5757
message_name: Name of the message in the Splunk's bulletin.

tests/unit/test_observability.py

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,58 +86,81 @@ def _make_histogram_data_point(name, unit="s"):
8686

8787
class TestLoggerMetricExporter:
8888
def test_export_counter_returns_success(self, logger):
89+
# Arrange
8990
exporter = LoggerMetricExporter(logger)
91+
# Act
9092
result = exporter.export(_make_counter_data_point("my.metric", 42))
93+
# Assert
9194
assert result == MetricExportResult.SUCCESS
9295

9396
def test_export_counter_logs_value(self, logger):
97+
# Arrange
9498
exporter = LoggerMetricExporter(logger)
99+
# Act
95100
exporter.export(_make_counter_data_point("my.metric", 7, attributes={"a": "b"}))
101+
# Assert
96102
logger.info.assert_called()
97103
call_args = logger.info.call_args[0]
98104
assert "my.metric" in call_args[1]
99105

100106
def test_export_counter_no_attributes(self, logger):
107+
# Arrange
101108
exporter = LoggerMetricExporter(logger)
109+
# Act
102110
result = exporter.export(
103111
_make_counter_data_point("my.metric", 1, attributes=None)
104112
)
113+
# Assert
105114
assert result == MetricExportResult.SUCCESS
106115

107116
def test_export_histogram_returns_success(self, logger):
117+
# Arrange
108118
exporter = LoggerMetricExporter(logger)
119+
# Act
109120
result = exporter.export(_make_histogram_data_point("my.histogram"))
121+
# Assert
110122
assert result == MetricExportResult.SUCCESS
111123

112124
def test_export_histogram_logs_bucket_info(self, logger):
125+
# Arrange
113126
exporter = LoggerMetricExporter(logger)
127+
# Act
114128
exporter.export(_make_histogram_data_point("my.histogram"))
129+
# Assert
115130
logger.info.assert_called()
116131
call_args = logger.info.call_args[0]
117132
assert "my.histogram" in call_args[1]
118133

119134
def test_export_empty_metrics_data(self, logger):
135+
# Arrange
120136
metrics_data = MagicMock()
121137
metrics_data.resource_metrics = []
122138
exporter = LoggerMetricExporter(logger)
139+
# Act
123140
result = exporter.export(metrics_data)
141+
# Assert
124142
assert result == MetricExportResult.SUCCESS
125143
logger.debug.assert_not_called()
126144

127145
def test_export_returns_failure_on_exception(self, logger):
146+
# Arrange
128147
metrics_data = MagicMock()
129148
metrics_data.resource_metrics.__iter__ = MagicMock(
130149
side_effect=RuntimeError("boom")
131150
)
132151
exporter = LoggerMetricExporter(logger)
152+
# Act
133153
result = exporter.export(metrics_data)
154+
# Assert
134155
assert result == MetricExportResult.FAILURE
135156
logger.error.assert_called()
136157

137158
def test_shutdown_does_not_raise(self, logger):
159+
# Arrange / Act / Assert
138160
LoggerMetricExporter(logger).shutdown()
139161

140162
def test_force_flush_returns_true(self, logger):
163+
# Arrange / Act / Assert
141164
assert LoggerMetricExporter(logger).force_flush() is True
142165

143166

@@ -164,20 +187,27 @@ def _make_service(logger, monkeypatch, extra_exporters=None):
164187

165188
class TestObservabilityService:
166189
def test_counters_are_created(self, logger, monkeypatch):
190+
# Arrange / Act
167191
svc = _make_service(logger, monkeypatch)
192+
# Assert
168193
assert svc.event_count_counter is not None
169194
assert svc.event_bytes_counter is not None
170195

171196
def test_meter_is_available(self, logger, monkeypatch):
197+
# Arrange / Act
172198
svc = _make_service(logger, monkeypatch)
199+
# Assert
173200
assert svc._meter is not None
174201

175202
def test_extra_exporter_is_added(self, logger, monkeypatch):
203+
# Arrange
176204
extra = MagicMock()
205+
# Act / Assert
177206
_make_service(logger, monkeypatch, extra_exporters=[extra])
178207
# No assertion needed beyond not raising; the exporter is wrapped internally
179208

180209
def test_missing_ta_name_logs_warning(self, logger, monkeypatch):
210+
# Arrange
181211
monkeypatch.setattr(
182212
"solnlib.observability.ObservabilityService._create_otlp_exporter",
183213
lambda self: None,
@@ -186,13 +216,16 @@ def test_missing_ta_name_logs_warning(self, logger, monkeypatch):
186216
"solnlib.observability.ObservabilityService._read_ta_info",
187217
lambda self: (None, None),
188218
)
219+
# Act
189220
svc = ObservabilityService(modinput_type="test-input", logger=logger)
221+
# Assert
190222
assert svc._meter is None
191223
logger.warning.assert_called()
192224

193225
def test_register_instrument_returns_none_when_meter_missing(
194226
self, logger, monkeypatch
195227
):
228+
# Arrange
196229
monkeypatch.setattr(
197230
"solnlib.observability.ObservabilityService._create_otlp_exporter",
198231
lambda self: None,
@@ -202,17 +235,23 @@ def test_register_instrument_returns_none_when_meter_missing(
202235
lambda self: (None, None),
203236
)
204237
svc = ObservabilityService(modinput_type="test-input", logger=logger)
238+
# Act
205239
result = svc.register_instrument(lambda m: m.create_counter("x"))
240+
# Assert
206241
assert result is None
207242

208243
def test_register_instrument_calls_callback(self, logger, monkeypatch):
244+
# Arrange
209245
svc = _make_service(logger, monkeypatch)
210246
callback = MagicMock(return_value="instrument")
247+
# Act
211248
result = svc.register_instrument(callback)
249+
# Assert
212250
callback.assert_called_once_with(svc._meter)
213251
assert result == "instrument"
214252

215253
def test_read_ta_info_returns_values(self, logger, monkeypatch):
254+
# Arrange
216255
monkeypatch.setattr(
217256
"solnlib.observability.get_conf_stanzas",
218257
lambda conf, **kwargs: {
@@ -224,10 +263,13 @@ def test_read_ta_info_returns_values(self, logger, monkeypatch):
224263
"solnlib.observability.ObservabilityService._create_otlp_exporter",
225264
lambda self: None,
226265
)
266+
# Act
227267
svc = ObservabilityService(modinput_type="test-input", logger=logger)
268+
# Assert
228269
assert svc._meter is not None
229270

230271
def test_read_ta_info_handles_exception(self, logger, monkeypatch):
272+
# Arrange
231273
monkeypatch.setattr(
232274
"solnlib.observability.ObservabilityService._create_otlp_exporter",
233275
lambda self: None,
@@ -236,50 +278,63 @@ def test_read_ta_info_handles_exception(self, logger, monkeypatch):
236278
"solnlib.observability.get_conf_stanzas",
237279
MagicMock(side_effect=Exception("no btool")),
238280
)
281+
# Act
239282
svc = ObservabilityService(modinput_type="test-input", logger=logger)
283+
# Assert
240284
assert svc._meter is None
241285

242286
def test_resolve_otlp_port_from_env(self, logger, monkeypatch):
287+
# Arrange
243288
monkeypatch.setenv("SPOTLIGHT_OTEL_RECEIVER_PORT", "4317")
244289
svc = _make_service(logger, monkeypatch)
290+
# Act / Assert
245291
assert svc._resolve_otlp_port() == "4317"
246292

247293
def test_resolve_otlp_port_falls_back_to_ipc(self, logger, monkeypatch):
294+
# Arrange
248295
monkeypatch.delenv("SPOTLIGHT_OTEL_RECEIVER_PORT", raising=False)
249296
monkeypatch.setattr(
250297
"solnlib.observability.ObservabilityService._discover_otlp_port_via_ipc_broker",
251298
lambda self: "9999",
252299
)
253300
svc = _make_service(logger, monkeypatch)
301+
# Act / Assert
254302
assert svc._resolve_otlp_port() == "9999"
255303

256304
def test_get_ipc_broker_port_returns_none_on_error(self, logger, monkeypatch):
305+
# Arrange
257306
monkeypatch.setattr(
258307
"solnlib.observability.get_conf_stanzas",
259308
MagicMock(side_effect=Exception("fail")),
260309
)
261310
svc = _make_service(logger, monkeypatch)
311+
# Act / Assert
262312
assert svc._get_ipc_broker_port() is None
263313

264314
def test_get_ipc_broker_port_returns_port(self, logger, monkeypatch):
315+
# Arrange
265316
monkeypatch.setattr(
266317
"solnlib.observability.get_conf_stanzas",
267318
lambda conf, **kwargs: {"ipc_broker": {"port": "8088"}},
268319
)
269320
svc = _make_service(logger, monkeypatch)
321+
# Act / Assert
270322
assert svc._get_ipc_broker_port() == 8088
271323

272324
def test_discover_otlp_port_returns_none_when_ipc_port_missing(
273325
self, logger, monkeypatch
274326
):
327+
# Arrange
275328
monkeypatch.setattr(
276329
"solnlib.observability.ObservabilityService._get_ipc_broker_port",
277330
lambda self: None,
278331
)
279332
svc = _make_service(logger, monkeypatch)
333+
# Act / Assert
280334
assert svc._discover_otlp_port_via_ipc_broker() is None
281335

282336
def test_discover_otlp_port_returns_none_on_http_error(self, logger, monkeypatch):
337+
# Arrange
283338
monkeypatch.setattr(
284339
"solnlib.observability.ObservabilityService._get_ipc_broker_port",
285340
lambda self: 8088,
@@ -289,11 +344,13 @@ def test_discover_otlp_port_returns_none_on_http_error(self, logger, monkeypatch
289344
MagicMock(side_effect=Exception("connection refused")),
290345
)
291346
svc = _make_service(logger, monkeypatch)
347+
# Act / Assert
292348
assert svc._discover_otlp_port_via_ipc_broker() is None
293349

294350
def test_discover_otlp_port_returns_none_on_unsuccessful_response(
295351
self, logger, monkeypatch
296352
):
353+
# Arrange
297354
monkeypatch.setattr(
298355
"solnlib.observability.ObservabilityService._get_ipc_broker_port",
299356
lambda self: 8088,
@@ -304,9 +361,11 @@ def test_discover_otlp_port_returns_none_on_unsuccessful_response(
304361
mock_resp.read.return_value = b'{"success": false}'
305362
monkeypatch.setattr("urllib.request.urlopen", lambda *a, **kw: mock_resp)
306363
svc = _make_service(logger, monkeypatch)
364+
# Act / Assert
307365
assert svc._discover_otlp_port_via_ipc_broker() is None
308366

309367
def test_discover_otlp_port_returns_port_on_success(self, logger, monkeypatch):
368+
# Arrange
310369
monkeypatch.setattr(
311370
"solnlib.observability.ObservabilityService._get_ipc_broker_port",
312371
lambda self: 8088,
@@ -317,24 +376,30 @@ def test_discover_otlp_port_returns_port_on_success(self, logger, monkeypatch):
317376
mock_resp.read.return_value = b'{"success": true, "port": 4317}'
318377
monkeypatch.setattr("urllib.request.urlopen", lambda *a, **kw: mock_resp)
319378
svc = _make_service(logger, monkeypatch)
379+
# Act / Assert
320380
assert svc._discover_otlp_port_via_ipc_broker() == "4317"
321381

322382
def test_create_otlp_exporter_returns_none_when_no_port(self, logger, monkeypatch):
383+
# Arrange
323384
monkeypatch.delenv("SPOTLIGHT_OTEL_RECEIVER_PORT", raising=False)
324385
monkeypatch.setattr(
325386
"solnlib.observability.ObservabilityService._discover_otlp_port_via_ipc_broker",
326387
lambda self: None,
327388
)
328389
svc = _make_service(logger, monkeypatch)
329-
# Call the real _create_otlp_exporter now (not patched)
390+
# Act — call the real _create_otlp_exporter (not patched)
330391
result = ObservabilityService._create_otlp_exporter(svc)
392+
# Assert
331393
assert result is None
332394

333395
def test_create_otlp_exporter_returns_none_when_cert_missing(
334396
self, logger, monkeypatch, tmp_path
335397
):
398+
# Arrange
336399
monkeypatch.setenv("SPOTLIGHT_OTEL_RECEIVER_PORT", "4317")
337400
monkeypatch.setenv("SPLUNK_HOME", str(tmp_path))
338401
svc = _make_service(logger, monkeypatch)
402+
# Act
339403
result = ObservabilityService._create_otlp_exporter(svc)
404+
# Assert
340405
assert result is None

0 commit comments

Comments
 (0)